]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / EmmcDxe / EmmcBlockIo.c
1 /** @file
2 The helper functions for BlockIo and BlockIo2 protocol.
3
4 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "EmmcDxe.h"
10
11 /**
12 Nonblocking I/O callback function when the event is signaled.
13
14 @param[in] Event The Event this notify function registered to.
15 @param[in] Context Pointer to the context data registered to the
16 Event.
17
18 **/
19 VOID
20 EFIAPI
21 AsyncIoCallback (
22 IN EFI_EVENT Event,
23 IN VOID *Context
24 )
25 {
26 EMMC_REQUEST *Request;
27 EFI_STATUS Status;
28
29 Status = gBS->CloseEvent (Event);
30 if (EFI_ERROR (Status)) {
31 return;
32 }
33
34 Request = (EMMC_REQUEST *)Context;
35
36 DEBUG_CODE_BEGIN ();
37 DEBUG ((
38 DEBUG_INFO,
39 "Emmc Async Request: CmdIndex[%d] Arg[%08x] %r\n",
40 Request->SdMmcCmdBlk.CommandIndex,
41 Request->SdMmcCmdBlk.CommandArgument,
42 Request->Packet.TransactionStatus
43 ));
44 DEBUG_CODE_END ();
45
46 if (EFI_ERROR (Request->Packet.TransactionStatus)) {
47 Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
48 }
49
50 RemoveEntryList (&Request->Link);
51
52 if (Request->IsEnd) {
53 gBS->SignalEvent (Request->Token->Event);
54 }
55
56 FreePool (Request);
57 }
58
59 /**
60 Send command SELECT to the device to select/deselect the device.
61
62 @param[in] Device A pointer to the EMMC_DEVICE instance.
63 @param[in] Rca The relative device address to use.
64
65 @retval EFI_SUCCESS The request is executed successfully.
66 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
67 @retval Others The request could not be executed successfully.
68
69 **/
70 EFI_STATUS
71 EmmcSelect (
72 IN EMMC_DEVICE *Device,
73 IN UINT16 Rca
74 )
75 {
76 EFI_STATUS Status;
77 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
78 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
79 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
80 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
81
82 PassThru = Device->Private->PassThru;
83
84 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
85 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
86 ZeroMem (&Packet, sizeof (Packet));
87 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
88 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
89 Packet.Timeout = EMMC_GENERIC_TIMEOUT;
90
91 SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
92 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
93 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
94 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
95
96 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
97
98 return Status;
99 }
100
101 /**
102 Send command SEND_STATUS to the device to get device status.
103
104 @param[in] Device A pointer to the EMMC_DEVICE instance.
105 @param[in] Rca The relative device address to use.
106 @param[out] DevStatus The buffer to store the device status.
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 EmmcSendStatus (
115 IN EMMC_DEVICE *Device,
116 IN UINT16 Rca,
117 OUT UINT32 *DevStatus
118 )
119 {
120 EFI_STATUS Status;
121 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
122 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
123 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
124 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
125
126 PassThru = Device->Private->PassThru;
127
128 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
129 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
130 ZeroMem (&Packet, sizeof (Packet));
131 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
132 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
133 Packet.Timeout = EMMC_GENERIC_TIMEOUT;
134
135 SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
136 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
137 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
138 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
139
140 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
141 if (!EFI_ERROR (Status)) {
142 CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
143 }
144
145 return Status;
146 }
147
148 /**
149 Send command SEND_CSD to the device to get the CSD register data.
150
151 @param[in] Device A pointer to the EMMC_DEVICE instance.
152 @param[in] Rca The relative device address to use.
153 @param[out] Csd The buffer to store the EMMC_CSD register data.
154
155 @retval EFI_SUCCESS The request is executed successfully.
156 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
157 @retval Others The request could not be executed successfully.
158
159 **/
160 EFI_STATUS
161 EmmcGetCsd (
162 IN EMMC_DEVICE *Device,
163 IN UINT16 Rca,
164 OUT EMMC_CSD *Csd
165 )
166 {
167 EFI_STATUS Status;
168 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
169 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
170 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
171 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
172
173 PassThru = Device->Private->PassThru;
174
175 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
176 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
177 ZeroMem (&Packet, sizeof (Packet));
178 ZeroMem (Csd, sizeof (EMMC_CSD));
179
180 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
181 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
182 Packet.Timeout = EMMC_GENERIC_TIMEOUT;
183
184 SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
185 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
186 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
187 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
188
189 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
190 if (!EFI_ERROR (Status)) {
191 //
192 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
193 //
194 CopyMem (((UINT8 *)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
195 }
196
197 return Status;
198 }
199
200 /**
201 Send command SEND_CID to the device to get the CID register data.
202
203 @param[in] Device A pointer to the EMMC_DEVICE instance.
204 @param[in] Rca The relative device address to use.
205 @param[out] Cid The buffer to store the EMMC_CID register data.
206
207 @retval EFI_SUCCESS The request is executed successfully.
208 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
209 @retval Others The request could not be executed successfully.
210
211 **/
212 EFI_STATUS
213 EmmcGetCid (
214 IN EMMC_DEVICE *Device,
215 IN UINT16 Rca,
216 OUT EMMC_CID *Cid
217 )
218 {
219 EFI_STATUS Status;
220 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
221 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
222 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
223 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
224
225 PassThru = Device->Private->PassThru;
226
227 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
228 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
229 ZeroMem (&Packet, sizeof (Packet));
230 ZeroMem (Cid, sizeof (EMMC_CID));
231
232 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
233 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
234 Packet.Timeout = EMMC_GENERIC_TIMEOUT;
235
236 SdMmcCmdBlk.CommandIndex = EMMC_SEND_CID;
237 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
238 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
239 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
240
241 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
242 if (!EFI_ERROR (Status)) {
243 //
244 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
245 //
246 CopyMem (((UINT8 *)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CID) - 1);
247 }
248
249 return Status;
250 }
251
252 /**
253 Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
254
255 @param[in] Device A pointer to the EMMC_DEVICE instance.
256 @param[out] ExtCsd The buffer to store the EXT_CSD register data.
257
258 @retval EFI_SUCCESS The request is executed successfully.
259 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
260 @retval Others The request could not be executed successfully.
261
262 **/
263 EFI_STATUS
264 EmmcGetExtCsd (
265 IN EMMC_DEVICE *Device,
266 OUT EMMC_EXT_CSD *ExtCsd
267 )
268 {
269 EFI_STATUS Status;
270 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
271 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
272 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
273 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
274
275 PassThru = Device->Private->PassThru;
276
277 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
278 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
279 ZeroMem (&Packet, sizeof (Packet));
280 ZeroMem (ExtCsd, sizeof (EMMC_EXT_CSD));
281 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
282 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
283 Packet.Timeout = EMMC_GENERIC_TIMEOUT;
284
285 SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
286 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
287 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
288 SdMmcCmdBlk.CommandArgument = 0x00000000;
289 Packet.InDataBuffer = ExtCsd;
290 Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
291
292 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
293
294 return Status;
295 }
296
297 /**
298 Set the specified EXT_CSD register field through sync or async I/O request.
299
300 @param[in] Partition A pointer to the EMMC_PARTITION instance.
301 @param[in] Offset The offset of the specified field in EXT_CSD register.
302 @param[in] Value The byte value written to the field specified by Offset.
303 @param[in] Token A pointer to the token associated with the transaction.
304 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
305 This parameter is only meaningful in async I/O request.
306
307 @retval EFI_SUCCESS The request is executed successfully.
308 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
309 @retval Others The request could not be executed successfully.
310
311 **/
312 EFI_STATUS
313 EmmcSetExtCsd (
314 IN EMMC_PARTITION *Partition,
315 IN UINT8 Offset,
316 IN UINT8 Value,
317 IN EFI_BLOCK_IO2_TOKEN *Token,
318 IN BOOLEAN IsEnd
319 )
320 {
321 EFI_STATUS Status;
322 EMMC_DEVICE *Device;
323 EMMC_REQUEST *SetExtCsdReq;
324 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
325 UINT32 CommandArgument;
326 EFI_TPL OldTpl;
327
328 SetExtCsdReq = NULL;
329
330 Device = Partition->Device;
331 PassThru = Device->Private->PassThru;
332
333 SetExtCsdReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
334 if (SetExtCsdReq == NULL) {
335 Status = EFI_OUT_OF_RESOURCES;
336 goto Error;
337 }
338
339 SetExtCsdReq->Signature = EMMC_REQUEST_SIGNATURE;
340 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
341 InsertTailList (&Partition->Queue, &SetExtCsdReq->Link);
342 gBS->RestoreTPL (OldTpl);
343 SetExtCsdReq->Packet.SdMmcCmdBlk = &SetExtCsdReq->SdMmcCmdBlk;
344 SetExtCsdReq->Packet.SdMmcStatusBlk = &SetExtCsdReq->SdMmcStatusBlk;
345 SetExtCsdReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
346
347 SetExtCsdReq->SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
348 SetExtCsdReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
349 SetExtCsdReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
350 //
351 // Write the Value to the field specified by Offset.
352 //
353 CommandArgument = (Value << 8) | (Offset << 16) | BIT24 | BIT25;
354 SetExtCsdReq->SdMmcCmdBlk.CommandArgument = CommandArgument;
355
356 SetExtCsdReq->IsEnd = IsEnd;
357 SetExtCsdReq->Token = Token;
358
359 if ((Token != NULL) && (Token->Event != NULL)) {
360 Status = gBS->CreateEvent (
361 EVT_NOTIFY_SIGNAL,
362 TPL_NOTIFY,
363 AsyncIoCallback,
364 SetExtCsdReq,
365 &SetExtCsdReq->Event
366 );
367 if (EFI_ERROR (Status)) {
368 goto Error;
369 }
370 } else {
371 SetExtCsdReq->Event = NULL;
372 }
373
374 Status = PassThru->PassThru (PassThru, Device->Slot, &SetExtCsdReq->Packet, SetExtCsdReq->Event);
375
376 Error:
377 if ((Token != NULL) && (Token->Event != NULL)) {
378 //
379 // For asynchronous operation, only free request and event in error case.
380 // The request and event will be freed in asynchronous callback for success case.
381 //
382 if (EFI_ERROR (Status) && (SetExtCsdReq != NULL)) {
383 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
384 RemoveEntryList (&SetExtCsdReq->Link);
385 gBS->RestoreTPL (OldTpl);
386 if (SetExtCsdReq->Event != NULL) {
387 gBS->CloseEvent (SetExtCsdReq->Event);
388 }
389
390 FreePool (SetExtCsdReq);
391 }
392 } else {
393 //
394 // For synchronous operation, free request whatever the execution result is.
395 //
396 if (SetExtCsdReq != NULL) {
397 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
398 RemoveEntryList (&SetExtCsdReq->Link);
399 gBS->RestoreTPL (OldTpl);
400 FreePool (SetExtCsdReq);
401 }
402 }
403
404 return Status;
405 }
406
407 /**
408 Set the number of blocks for a block read/write cmd through sync or async I/O request.
409
410 @param[in] Partition A pointer to the EMMC_PARTITION instance.
411 @param[in] BlockNum The number of blocks for transfer.
412 @param[in] Token A pointer to the token associated with the transaction.
413 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
414 This parameter is only meaningful in async I/O request.
415
416 @retval EFI_SUCCESS The request is executed successfully.
417 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
418 @retval Others The request could not be executed successfully.
419
420 **/
421 EFI_STATUS
422 EmmcSetBlkCount (
423 IN EMMC_PARTITION *Partition,
424 IN UINT16 BlockNum,
425 IN EFI_BLOCK_IO2_TOKEN *Token,
426 IN BOOLEAN IsEnd
427 )
428 {
429 EFI_STATUS Status;
430 EMMC_DEVICE *Device;
431 EMMC_REQUEST *SetBlkCntReq;
432 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
433 EFI_TPL OldTpl;
434
435 SetBlkCntReq = NULL;
436
437 Device = Partition->Device;
438 PassThru = Device->Private->PassThru;
439
440 SetBlkCntReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
441 if (SetBlkCntReq == NULL) {
442 Status = EFI_OUT_OF_RESOURCES;
443 goto Error;
444 }
445
446 SetBlkCntReq->Signature = EMMC_REQUEST_SIGNATURE;
447 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
448 InsertTailList (&Partition->Queue, &SetBlkCntReq->Link);
449 gBS->RestoreTPL (OldTpl);
450 SetBlkCntReq->Packet.SdMmcCmdBlk = &SetBlkCntReq->SdMmcCmdBlk;
451 SetBlkCntReq->Packet.SdMmcStatusBlk = &SetBlkCntReq->SdMmcStatusBlk;
452 SetBlkCntReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
453
454 SetBlkCntReq->SdMmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;
455 SetBlkCntReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
456 SetBlkCntReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
457 SetBlkCntReq->SdMmcCmdBlk.CommandArgument = BlockNum;
458
459 SetBlkCntReq->IsEnd = IsEnd;
460 SetBlkCntReq->Token = Token;
461
462 if ((Token != NULL) && (Token->Event != NULL)) {
463 Status = gBS->CreateEvent (
464 EVT_NOTIFY_SIGNAL,
465 TPL_NOTIFY,
466 AsyncIoCallback,
467 SetBlkCntReq,
468 &SetBlkCntReq->Event
469 );
470 if (EFI_ERROR (Status)) {
471 goto Error;
472 }
473 } else {
474 SetBlkCntReq->Event = NULL;
475 }
476
477 Status = PassThru->PassThru (PassThru, Device->Slot, &SetBlkCntReq->Packet, SetBlkCntReq->Event);
478
479 Error:
480 if ((Token != NULL) && (Token->Event != NULL)) {
481 //
482 // For asynchronous operation, only free request and event in error case.
483 // The request and event will be freed in asynchronous callback for success case.
484 //
485 if (EFI_ERROR (Status) && (SetBlkCntReq != NULL)) {
486 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
487 RemoveEntryList (&SetBlkCntReq->Link);
488 gBS->RestoreTPL (OldTpl);
489 if (SetBlkCntReq->Event != NULL) {
490 gBS->CloseEvent (SetBlkCntReq->Event);
491 }
492
493 FreePool (SetBlkCntReq);
494 }
495 } else {
496 //
497 // For synchronous operation, free request whatever the execution result is.
498 //
499 if (SetBlkCntReq != NULL) {
500 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
501 RemoveEntryList (&SetBlkCntReq->Link);
502 gBS->RestoreTPL (OldTpl);
503 FreePool (SetBlkCntReq);
504 }
505 }
506
507 return Status;
508 }
509
510 /**
511 Read blocks through security protocol cmds with the way of sync or async I/O request.
512
513 @param[in] Partition A pointer to the EMMC_PARTITION instance.
514 @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
515 the security protocol command to be sent.
516 @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
517 of the security protocol command to be sent.
518 @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
519 @param[out] PayloadBuffer A pointer to a destination buffer to store the security
520 protocol command specific payload data for the security
521 protocol command. The caller is responsible for having
522 either implicit or explicit ownership of the buffer.
523 @param[in] IsRead Indicates it is a read or write operation.
524 @param[in] Timeout The timeout value, in 100ns units.
525 @param[in] Token A pointer to the token associated with the transaction.
526 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
527 This parameter is only meaningful in async I/O request.
528
529 @retval EFI_SUCCESS The request is executed successfully.
530 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
531 @retval Others The request could not be executed successfully.
532
533 **/
534 EFI_STATUS
535 EmmcProtocolInOut (
536 IN EMMC_PARTITION *Partition,
537 IN UINT8 SecurityProtocol,
538 IN UINT16 SecurityProtocolSpecificData,
539 IN UINTN PayloadBufferSize,
540 OUT VOID *PayloadBuffer,
541 IN BOOLEAN IsRead,
542 IN UINT64 Timeout,
543 IN EFI_BLOCK_IO2_TOKEN *Token,
544 IN BOOLEAN IsEnd
545 )
546 {
547 EFI_STATUS Status;
548 EMMC_DEVICE *Device;
549 EMMC_REQUEST *ProtocolReq;
550 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
551 EFI_TPL OldTpl;
552
553 ProtocolReq = NULL;
554
555 Device = Partition->Device;
556 PassThru = Device->Private->PassThru;
557
558 ProtocolReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
559 if (ProtocolReq == NULL) {
560 Status = EFI_OUT_OF_RESOURCES;
561 goto Error;
562 }
563
564 ProtocolReq->Signature = EMMC_REQUEST_SIGNATURE;
565 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
566 InsertTailList (&Partition->Queue, &ProtocolReq->Link);
567 gBS->RestoreTPL (OldTpl);
568 ProtocolReq->Packet.SdMmcCmdBlk = &ProtocolReq->SdMmcCmdBlk;
569 ProtocolReq->Packet.SdMmcStatusBlk = &ProtocolReq->SdMmcStatusBlk;
570
571 if (IsRead) {
572 ProtocolReq->Packet.InDataBuffer = PayloadBuffer;
573 ProtocolReq->Packet.InTransferLength = (UINT32)PayloadBufferSize;
574
575 ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_RD;
576 ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
577 ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
578 } else {
579 ProtocolReq->Packet.OutDataBuffer = PayloadBuffer;
580 ProtocolReq->Packet.OutTransferLength = (UINT32)PayloadBufferSize;
581
582 ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_WR;
583 ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
584 ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
585 }
586
587 ProtocolReq->SdMmcCmdBlk.CommandArgument = (SecurityProtocol << 8) | (SecurityProtocolSpecificData << 16);
588 //
589 // Convert to 1 microsecond unit.
590 //
591 ProtocolReq->Packet.Timeout = DivU64x32 (Timeout, 10) + 1;
592
593 ProtocolReq->IsEnd = IsEnd;
594 ProtocolReq->Token = Token;
595
596 if ((Token != NULL) && (Token->Event != NULL)) {
597 Status = gBS->CreateEvent (
598 EVT_NOTIFY_SIGNAL,
599 TPL_NOTIFY,
600 AsyncIoCallback,
601 ProtocolReq,
602 &ProtocolReq->Event
603 );
604 if (EFI_ERROR (Status)) {
605 goto Error;
606 }
607 } else {
608 ProtocolReq->Event = NULL;
609 }
610
611 Status = PassThru->PassThru (PassThru, Device->Slot, &ProtocolReq->Packet, ProtocolReq->Event);
612
613 Error:
614 if ((Token != NULL) && (Token->Event != NULL)) {
615 //
616 // For asynchronous operation, only free request and event in error case.
617 // The request and event will be freed in asynchronous callback for success case.
618 //
619 if (EFI_ERROR (Status) && (ProtocolReq != NULL)) {
620 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
621 RemoveEntryList (&ProtocolReq->Link);
622 gBS->RestoreTPL (OldTpl);
623 if (ProtocolReq->Event != NULL) {
624 gBS->CloseEvent (ProtocolReq->Event);
625 }
626
627 FreePool (ProtocolReq);
628 }
629 } else {
630 //
631 // For synchronous operation, free request whatever the execution result is.
632 //
633 if (ProtocolReq != NULL) {
634 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
635 RemoveEntryList (&ProtocolReq->Link);
636 gBS->RestoreTPL (OldTpl);
637 FreePool (ProtocolReq);
638 }
639 }
640
641 return Status;
642 }
643
644 /**
645 Read/write multiple blocks through sync or async I/O request.
646
647 @param[in] Partition A pointer to the EMMC_PARTITION instance.
648 @param[in] Lba The starting logical block address to be read/written.
649 The caller is responsible for reading/writing to only
650 legitimate locations.
651 @param[in] Buffer A pointer to the destination/source buffer for the data.
652 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
653 @param[in] IsRead Indicates it is a read or write operation.
654 @param[in] Token A pointer to the token associated with the transaction.
655 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
656 This parameter is only meaningful in async I/O request.
657
658 @retval EFI_SUCCESS The request is executed successfully.
659 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
660 @retval Others The request could not be executed successfully.
661
662 **/
663 EFI_STATUS
664 EmmcRwMultiBlocks (
665 IN EMMC_PARTITION *Partition,
666 IN EFI_LBA Lba,
667 IN VOID *Buffer,
668 IN UINTN BufferSize,
669 IN BOOLEAN IsRead,
670 IN EFI_BLOCK_IO2_TOKEN *Token,
671 IN BOOLEAN IsEnd
672 )
673 {
674 EFI_STATUS Status;
675 EMMC_DEVICE *Device;
676 EMMC_REQUEST *RwMultiBlkReq;
677 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
678 EFI_TPL OldTpl;
679
680 RwMultiBlkReq = NULL;
681
682 Device = Partition->Device;
683 PassThru = Device->Private->PassThru;
684
685 RwMultiBlkReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
686 if (RwMultiBlkReq == NULL) {
687 Status = EFI_OUT_OF_RESOURCES;
688 goto Error;
689 }
690
691 RwMultiBlkReq->Signature = EMMC_REQUEST_SIGNATURE;
692 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
693 InsertTailList (&Partition->Queue, &RwMultiBlkReq->Link);
694 gBS->RestoreTPL (OldTpl);
695 RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
696 RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
697 //
698 // Calculate timeout value through the below formula.
699 // Timeout = (transfer size) / (2MB/s).
700 // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest
701 // transfer speed (2.4MB/s).
702 // Refer to eMMC 5.0 spec section 6.9.1 for details.
703 //
704 RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
705
706 if (IsRead) {
707 RwMultiBlkReq->Packet.InDataBuffer = Buffer;
708 RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
709
710 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;
711 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
712 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
713 } else {
714 RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
715 RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
716
717 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;
718 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
719 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
720 }
721
722 if (Partition->Device->SectorAddressing) {
723 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
724 } else {
725 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Partition->BlockMedia.BlockSize);
726 }
727
728 RwMultiBlkReq->IsEnd = IsEnd;
729 RwMultiBlkReq->Token = Token;
730
731 if ((Token != NULL) && (Token->Event != NULL)) {
732 Status = gBS->CreateEvent (
733 EVT_NOTIFY_SIGNAL,
734 TPL_NOTIFY,
735 AsyncIoCallback,
736 RwMultiBlkReq,
737 &RwMultiBlkReq->Event
738 );
739 if (EFI_ERROR (Status)) {
740 goto Error;
741 }
742 } else {
743 RwMultiBlkReq->Event = NULL;
744 }
745
746 Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
747
748 Error:
749 if ((Token != NULL) && (Token->Event != NULL)) {
750 //
751 // For asynchronous operation, only free request and event in error case.
752 // The request and event will be freed in asynchronous callback for success case.
753 //
754 if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
755 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
756 RemoveEntryList (&RwMultiBlkReq->Link);
757 gBS->RestoreTPL (OldTpl);
758 if (RwMultiBlkReq->Event != NULL) {
759 gBS->CloseEvent (RwMultiBlkReq->Event);
760 }
761
762 FreePool (RwMultiBlkReq);
763 }
764 } else {
765 //
766 // For synchronous operation, free request whatever the execution result is.
767 //
768 if (RwMultiBlkReq != NULL) {
769 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
770 RemoveEntryList (&RwMultiBlkReq->Link);
771 gBS->RestoreTPL (OldTpl);
772 FreePool (RwMultiBlkReq);
773 }
774 }
775
776 return Status;
777 }
778
779 /**
780 This function transfers data from/to EMMC device.
781
782 @param[in] Partition A pointer to the EMMC_PARTITION instance.
783 @param[in] MediaId The media ID that the read/write request is for.
784 @param[in] Lba The starting logical block address to be read/written.
785 The caller is responsible for reading/writing to only
786 legitimate locations.
787 @param[in, out] Buffer A pointer to the destination/source buffer for the data.
788 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
789 @param[in] IsRead Indicates it is a read or write operation.
790 @param[in, out] Token A pointer to the token associated with the transaction.
791
792 @retval EFI_SUCCESS The data was read/written correctly to the device.
793 @retval EFI_WRITE_PROTECTED The device can not be read/written to.
794 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
795 @retval EFI_NO_MEDIA There is no media in the device.
796 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
797 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
798 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
799 or the buffer is not on proper alignment.
800
801 **/
802 EFI_STATUS
803 EmmcReadWrite (
804 IN EMMC_PARTITION *Partition,
805 IN UINT32 MediaId,
806 IN EFI_LBA Lba,
807 IN OUT VOID *Buffer,
808 IN UINTN BufferSize,
809 IN BOOLEAN IsRead,
810 IN OUT EFI_BLOCK_IO2_TOKEN *Token
811 )
812 {
813 EFI_STATUS Status;
814 EMMC_DEVICE *Device;
815 EFI_BLOCK_IO_MEDIA *Media;
816 UINTN BlockSize;
817 UINTN BlockNum;
818 UINTN IoAlign;
819 UINT8 PartitionConfig;
820 UINTN Remaining;
821 UINT32 MaxBlock;
822 BOOLEAN LastRw;
823
824 Status = EFI_SUCCESS;
825 Device = Partition->Device;
826 Media = &Partition->BlockMedia;
827 LastRw = FALSE;
828
829 if (MediaId != Media->MediaId) {
830 return EFI_MEDIA_CHANGED;
831 }
832
833 if (!IsRead && Media->ReadOnly) {
834 return EFI_WRITE_PROTECTED;
835 }
836
837 //
838 // Check parameters.
839 //
840 if (Buffer == NULL) {
841 return EFI_INVALID_PARAMETER;
842 }
843
844 if (BufferSize == 0) {
845 if ((Token != NULL) && (Token->Event != NULL)) {
846 Token->TransactionStatus = EFI_SUCCESS;
847 gBS->SignalEvent (Token->Event);
848 }
849
850 return EFI_SUCCESS;
851 }
852
853 BlockSize = Media->BlockSize;
854 if ((BufferSize % BlockSize) != 0) {
855 return EFI_BAD_BUFFER_SIZE;
856 }
857
858 BlockNum = BufferSize / BlockSize;
859 if ((Lba + BlockNum - 1) > Media->LastBlock) {
860 return EFI_INVALID_PARAMETER;
861 }
862
863 IoAlign = Media->IoAlign;
864 if ((IoAlign > 0) && (((UINTN)Buffer & (IoAlign - 1)) != 0)) {
865 return EFI_INVALID_PARAMETER;
866 }
867
868 if ((Token != NULL) && (Token->Event != NULL)) {
869 Token->TransactionStatus = EFI_SUCCESS;
870 }
871
872 //
873 // Check if needs to switch partition access.
874 //
875 PartitionConfig = Device->ExtCsd.PartitionConfig;
876 if ((PartitionConfig & 0x7) != Partition->PartitionType) {
877 PartitionConfig &= (UINT8) ~0x7;
878 PartitionConfig |= Partition->PartitionType;
879 Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, Token, FALSE);
880 if (EFI_ERROR (Status)) {
881 return Status;
882 }
883
884 Device->ExtCsd.PartitionConfig = PartitionConfig;
885 }
886
887 //
888 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
889 //
890 Remaining = BlockNum;
891 MaxBlock = 0xFFFF;
892
893 while (Remaining > 0) {
894 if (Remaining <= MaxBlock) {
895 BlockNum = Remaining;
896 LastRw = TRUE;
897 } else {
898 BlockNum = MaxBlock;
899 }
900
901 Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, Token, FALSE);
902 if (EFI_ERROR (Status)) {
903 return Status;
904 }
905
906 BufferSize = BlockNum * BlockSize;
907 Status = EmmcRwMultiBlocks (Partition, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
908 if (EFI_ERROR (Status)) {
909 return Status;
910 }
911
912 DEBUG ((
913 DEBUG_BLKIO,
914 "Emmc%a(): Part %d Lba 0x%x BlkNo 0x%x Event %p with %r\n",
915 IsRead ? "Read " : "Write",
916 Partition->PartitionType,
917 Lba,
918 BlockNum,
919 (Token != NULL) ? Token->Event : NULL,
920 Status
921 ));
922
923 Lba += BlockNum;
924 Buffer = (UINT8 *)Buffer + BufferSize;
925 Remaining -= BlockNum;
926 }
927
928 return Status;
929 }
930
931 /**
932 Reset the Block Device.
933
934 @param This Indicates a pointer to the calling context.
935 @param ExtendedVerification Driver may perform diagnostics on reset.
936
937 @retval EFI_SUCCESS The device was reset.
938 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
939 not be reset.
940
941 **/
942 EFI_STATUS
943 EFIAPI
944 EmmcReset (
945 IN EFI_BLOCK_IO_PROTOCOL *This,
946 IN BOOLEAN ExtendedVerification
947 )
948 {
949 EFI_STATUS Status;
950 EMMC_PARTITION *Partition;
951 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
952
953 Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
954
955 PassThru = Partition->Device->Private->PassThru;
956 Status = PassThru->ResetDevice (PassThru, Partition->Device->Slot);
957 if (EFI_ERROR (Status)) {
958 Status = EFI_DEVICE_ERROR;
959 }
960
961 return Status;
962 }
963
964 /**
965 Read BufferSize bytes from Lba into Buffer.
966
967 @param This Indicates a pointer to the calling context.
968 @param MediaId Id of the media, changes every time the media is replaced.
969 @param Lba The starting Logical Block Address to read from
970 @param BufferSize Size of Buffer, must be a multiple of device block size.
971 @param Buffer A pointer to the destination buffer for the data. The caller is
972 responsible for either having implicit or explicit ownership of the buffer.
973
974 @retval EFI_SUCCESS The data was read correctly from the device.
975 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
976 @retval EFI_NO_MEDIA There is no media in the device.
977 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
978 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
979 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
980 or the buffer is not on proper alignment.
981
982 **/
983 EFI_STATUS
984 EFIAPI
985 EmmcReadBlocks (
986 IN EFI_BLOCK_IO_PROTOCOL *This,
987 IN UINT32 MediaId,
988 IN EFI_LBA Lba,
989 IN UINTN BufferSize,
990 OUT VOID *Buffer
991 )
992 {
993 EFI_STATUS Status;
994 EMMC_PARTITION *Partition;
995
996 Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
997
998 Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
999 return Status;
1000 }
1001
1002 /**
1003 Write BufferSize bytes from Lba into Buffer.
1004
1005 @param This Indicates a pointer to the calling context.
1006 @param MediaId The media ID that the write request is for.
1007 @param Lba The starting logical block address to be written. The caller is
1008 responsible for writing to only legitimate locations.
1009 @param BufferSize Size of Buffer, must be a multiple of device block size.
1010 @param Buffer A pointer to the source buffer for the data.
1011
1012 @retval EFI_SUCCESS The data was written correctly to the device.
1013 @retval EFI_WRITE_PROTECTED The device can not be written to.
1014 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1015 @retval EFI_NO_MEDIA There is no media in the device.
1016 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1017 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1018 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1019 or the buffer is not on proper alignment.
1020
1021 **/
1022 EFI_STATUS
1023 EFIAPI
1024 EmmcWriteBlocks (
1025 IN EFI_BLOCK_IO_PROTOCOL *This,
1026 IN UINT32 MediaId,
1027 IN EFI_LBA Lba,
1028 IN UINTN BufferSize,
1029 IN VOID *Buffer
1030 )
1031 {
1032 EFI_STATUS Status;
1033 EMMC_PARTITION *Partition;
1034
1035 Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
1036
1037 Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
1038 return Status;
1039 }
1040
1041 /**
1042 Flush the Block Device.
1043
1044 @param This Indicates a pointer to the calling context.
1045
1046 @retval EFI_SUCCESS All outstanding data was written to the device
1047 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
1048 @retval EFI_NO_MEDIA There is no media in the device.
1049
1050 **/
1051 EFI_STATUS
1052 EFIAPI
1053 EmmcFlushBlocks (
1054 IN EFI_BLOCK_IO_PROTOCOL *This
1055 )
1056 {
1057 //
1058 // return directly
1059 //
1060 return EFI_SUCCESS;
1061 }
1062
1063 /**
1064 Reset the Block Device.
1065
1066 @param[in] This Indicates a pointer to the calling context.
1067 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
1068
1069 @retval EFI_SUCCESS The device was reset.
1070 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
1071 not be reset.
1072
1073 **/
1074 EFI_STATUS
1075 EFIAPI
1076 EmmcResetEx (
1077 IN EFI_BLOCK_IO2_PROTOCOL *This,
1078 IN BOOLEAN ExtendedVerification
1079 )
1080 {
1081 EMMC_PARTITION *Partition;
1082 LIST_ENTRY *Link;
1083 LIST_ENTRY *NextLink;
1084 EMMC_REQUEST *Request;
1085 EFI_TPL OldTpl;
1086
1087 Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
1088
1089 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1090 for (Link = GetFirstNode (&Partition->Queue);
1091 !IsNull (&Partition->Queue, Link);
1092 Link = NextLink)
1093 {
1094 NextLink = GetNextNode (&Partition->Queue, Link);
1095 RemoveEntryList (Link);
1096
1097 Request = EMMC_REQUEST_FROM_LINK (Link);
1098
1099 gBS->CloseEvent (Request->Event);
1100 Request->Token->TransactionStatus = EFI_ABORTED;
1101
1102 if (Request->IsEnd) {
1103 gBS->SignalEvent (Request->Token->Event);
1104 }
1105
1106 FreePool (Request);
1107 }
1108
1109 gBS->RestoreTPL (OldTpl);
1110
1111 return EFI_SUCCESS;
1112 }
1113
1114 /**
1115 Read BufferSize bytes from Lba into Buffer.
1116
1117 @param[in] This Indicates a pointer to the calling context.
1118 @param[in] MediaId Id of the media, changes every time the media is replaced.
1119 @param[in] Lba The starting Logical Block Address to read from.
1120 @param[in, out] Token A pointer to the token associated with the transaction.
1121 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
1122 @param[out] Buffer A pointer to the destination buffer for the data. The caller is
1123 responsible for either having implicit or explicit ownership of the buffer.
1124
1125 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
1126 The data was read correctly from the device if
1127 the Event is NULL.
1128 @retval EFI_DEVICE_ERROR The device reported an error while performing
1129 the read.
1130 @retval EFI_NO_MEDIA There is no media in the device.
1131 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1132 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
1133 intrinsic block size of the device.
1134 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
1135 or the buffer is not on proper alignment.
1136 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1137 of resources.
1138
1139 **/
1140 EFI_STATUS
1141 EFIAPI
1142 EmmcReadBlocksEx (
1143 IN EFI_BLOCK_IO2_PROTOCOL *This,
1144 IN UINT32 MediaId,
1145 IN EFI_LBA Lba,
1146 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
1147 IN UINTN BufferSize,
1148 OUT VOID *Buffer
1149 )
1150 {
1151 EFI_STATUS Status;
1152 EMMC_PARTITION *Partition;
1153
1154 Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
1155
1156 Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
1157 return Status;
1158 }
1159
1160 /**
1161 Write BufferSize bytes from Lba into Buffer.
1162
1163 @param[in] This Indicates a pointer to the calling context.
1164 @param[in] MediaId The media ID that the write request is for.
1165 @param[in] Lba The starting logical block address to be written. The
1166 caller is responsible for writing to only legitimate
1167 locations.
1168 @param[in, out] Token A pointer to the token associated with the transaction.
1169 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
1170 @param[in] Buffer A pointer to the source buffer for the data.
1171
1172 @retval EFI_SUCCESS The data was written correctly to the device.
1173 @retval EFI_WRITE_PROTECTED The device can not be written to.
1174 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1175 @retval EFI_NO_MEDIA There is no media in the device.
1176 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1177 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1178 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1179 or the buffer is not on proper alignment.
1180
1181 **/
1182 EFI_STATUS
1183 EFIAPI
1184 EmmcWriteBlocksEx (
1185 IN EFI_BLOCK_IO2_PROTOCOL *This,
1186 IN UINT32 MediaId,
1187 IN EFI_LBA Lba,
1188 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
1189 IN UINTN BufferSize,
1190 IN VOID *Buffer
1191 )
1192 {
1193 EFI_STATUS Status;
1194 EMMC_PARTITION *Partition;
1195
1196 Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
1197
1198 Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
1199 return Status;
1200 }
1201
1202 /**
1203 Flush the Block Device.
1204
1205 @param[in] This Indicates a pointer to the calling context.
1206 @param[in, out] Token A pointer to the token associated with the transaction.
1207
1208 @retval EFI_SUCCESS All outstanding data was written to the device
1209 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
1210 @retval EFI_NO_MEDIA There is no media in the device.
1211
1212 **/
1213 EFI_STATUS
1214 EFIAPI
1215 EmmcFlushBlocksEx (
1216 IN EFI_BLOCK_IO2_PROTOCOL *This,
1217 IN OUT EFI_BLOCK_IO2_TOKEN *Token
1218 )
1219 {
1220 //
1221 // Signal event and return directly.
1222 //
1223 if ((Token != NULL) && (Token->Event != NULL)) {
1224 Token->TransactionStatus = EFI_SUCCESS;
1225 gBS->SignalEvent (Token->Event);
1226 }
1227
1228 return EFI_SUCCESS;
1229 }
1230
1231 /**
1232 Send a security protocol command to a device that receives data and/or the result
1233 of one or more commands sent by SendData.
1234
1235 The ReceiveData function sends a security protocol command to the given MediaId.
1236 The security protocol command sent is defined by SecurityProtocolId and contains
1237 the security protocol specific data SecurityProtocolSpecificData. The function
1238 returns the data from the security protocol command in PayloadBuffer.
1239
1240 For devices supporting the SCSI command set, the security protocol command is sent
1241 using the SECURITY PROTOCOL IN command defined in SPC-4.
1242
1243 For devices supporting the ATA command set, the security protocol command is sent
1244 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
1245 is non-zero.
1246
1247 If the PayloadBufferSize is zero, the security protocol command is sent using the
1248 Trusted Non-Data command defined in ATA8-ACS.
1249
1250 If PayloadBufferSize is too small to store the available data from the security
1251 protocol command, the function shall copy PayloadBufferSize bytes into the
1252 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1253
1254 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1255 the function shall return EFI_INVALID_PARAMETER.
1256
1257 If the given MediaId does not support security protocol commands, the function shall
1258 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1259 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1260 the function returns EFI_MEDIA_CHANGED.
1261
1262 If the security protocol fails to complete within the Timeout period, the function
1263 shall return EFI_TIMEOUT.
1264
1265 If the security protocol command completes without an error, the function shall
1266 return EFI_SUCCESS. If the security protocol command completes with an error, the
1267 function shall return EFI_DEVICE_ERROR.
1268
1269 @param[in] This Indicates a pointer to the calling context.
1270 @param[in] MediaId ID of the medium to receive data from.
1271 @param[in] Timeout The timeout, in 100ns units, to use for the execution
1272 of the security protocol command. A Timeout value of 0
1273 means that this function will wait indefinitely for the
1274 security protocol command to execute. If Timeout is greater
1275 than zero, then this function will return EFI_TIMEOUT
1276 if the time required to execute the receive data command
1277 is greater than Timeout.
1278 @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
1279 the security protocol command to be sent.
1280 @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1281 of the security protocol command to be sent.
1282 @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
1283 @param[out] PayloadBuffer A pointer to a destination buffer to store the security
1284 protocol command specific payload data for the security
1285 protocol command. The caller is responsible for having
1286 either implicit or explicit ownership of the buffer.
1287 @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1288 data written to the payload data buffer.
1289 @param[in] IsRead Indicates it is a read or write operation.
1290
1291 @retval EFI_SUCCESS The security protocol command completed successfully.
1292 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1293 data from the device. The PayloadBuffer contains the truncated data.
1294 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1295 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1296 @retval EFI_NO_MEDIA There is no media in the device.
1297 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1298 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1299 PayloadBufferSize is non-zero.
1300 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1301 protocol command to execute.
1302
1303 **/
1304 EFI_STATUS
1305 EFIAPI
1306 EmmcSecurityProtocolInOut (
1307 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1308 IN UINT32 MediaId,
1309 IN UINT64 Timeout,
1310 IN UINT8 SecurityProtocolId,
1311 IN UINT16 SecurityProtocolSpecificData,
1312 IN UINTN PayloadBufferSize,
1313 OUT VOID *PayloadBuffer,
1314 OUT UINTN *PayloadTransferSize,
1315 IN BOOLEAN IsRead
1316 )
1317 {
1318 EFI_STATUS Status;
1319 EMMC_PARTITION *Partition;
1320 EMMC_DEVICE *Device;
1321 EFI_BLOCK_IO_MEDIA *Media;
1322 UINTN BlockSize;
1323 UINTN BlockNum;
1324 UINTN IoAlign;
1325 UINTN Remaining;
1326 UINT32 MaxBlock;
1327 UINT8 PartitionConfig;
1328
1329 Status = EFI_SUCCESS;
1330 Partition = EMMC_PARTITION_DATA_FROM_SSP (This);
1331 Device = Partition->Device;
1332 Media = &Partition->BlockMedia;
1333
1334 if (PayloadTransferSize != NULL) {
1335 *PayloadTransferSize = 0;
1336 }
1337
1338 if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
1339 return EFI_INVALID_PARAMETER;
1340 }
1341
1342 if (MediaId != Media->MediaId) {
1343 return EFI_MEDIA_CHANGED;
1344 }
1345
1346 if (PayloadBufferSize == 0) {
1347 return EFI_SUCCESS;
1348 }
1349
1350 BlockSize = Media->BlockSize;
1351 if ((PayloadBufferSize % BlockSize) != 0) {
1352 return EFI_BAD_BUFFER_SIZE;
1353 }
1354
1355 BlockNum = PayloadBufferSize / BlockSize;
1356
1357 IoAlign = Media->IoAlign;
1358 if ((IoAlign > 0) && (((UINTN)PayloadBuffer & (IoAlign - 1)) != 0)) {
1359 return EFI_INVALID_PARAMETER;
1360 }
1361
1362 //
1363 // Security protocol interface is synchronous transfer.
1364 // Waiting for async I/O list to be empty before any operation.
1365 //
1366 while (!IsListEmpty (&Partition->Queue)) {
1367 }
1368
1369 //
1370 // Check if needs to switch partition access.
1371 //
1372 PartitionConfig = Device->ExtCsd.PartitionConfig;
1373 if ((PartitionConfig & 0x7) != Partition->PartitionType) {
1374 PartitionConfig &= (UINT8) ~0x7;
1375 PartitionConfig |= Partition->PartitionType;
1376 Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, NULL, FALSE);
1377 if (EFI_ERROR (Status)) {
1378 return Status;
1379 }
1380
1381 Device->ExtCsd.PartitionConfig = PartitionConfig;
1382 }
1383
1384 //
1385 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
1386 //
1387 Remaining = BlockNum;
1388 MaxBlock = 0xFFFF;
1389
1390 while (Remaining > 0) {
1391 if (Remaining <= MaxBlock) {
1392 BlockNum = Remaining;
1393 } else {
1394 BlockNum = MaxBlock;
1395 }
1396
1397 Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, NULL, FALSE);
1398 if (EFI_ERROR (Status)) {
1399 return Status;
1400 }
1401
1402 PayloadBufferSize = BlockNum * BlockSize;
1403 Status = EmmcProtocolInOut (Partition, SecurityProtocolId, SecurityProtocolSpecificData, PayloadBufferSize, PayloadBuffer, IsRead, Timeout, NULL, FALSE);
1404 if (EFI_ERROR (Status)) {
1405 return Status;
1406 }
1407
1408 PayloadBuffer = (UINT8 *)PayloadBuffer + PayloadBufferSize;
1409 Remaining -= BlockNum;
1410 if (PayloadTransferSize != NULL) {
1411 *PayloadTransferSize += PayloadBufferSize;
1412 }
1413 }
1414
1415 return Status;
1416 }
1417
1418 /**
1419 Send a security protocol command to a device that receives data and/or the result
1420 of one or more commands sent by SendData.
1421
1422 The ReceiveData function sends a security protocol command to the given MediaId.
1423 The security protocol command sent is defined by SecurityProtocolId and contains
1424 the security protocol specific data SecurityProtocolSpecificData. The function
1425 returns the data from the security protocol command in PayloadBuffer.
1426
1427 For devices supporting the SCSI command set, the security protocol command is sent
1428 using the SECURITY PROTOCOL IN command defined in SPC-4.
1429
1430 For devices supporting the ATA command set, the security protocol command is sent
1431 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
1432 is non-zero.
1433
1434 If the PayloadBufferSize is zero, the security protocol command is sent using the
1435 Trusted Non-Data command defined in ATA8-ACS.
1436
1437 If PayloadBufferSize is too small to store the available data from the security
1438 protocol command, the function shall copy PayloadBufferSize bytes into the
1439 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1440
1441 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1442 the function shall return EFI_INVALID_PARAMETER.
1443
1444 If the given MediaId does not support security protocol commands, the function shall
1445 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1446 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1447 the function returns EFI_MEDIA_CHANGED.
1448
1449 If the security protocol fails to complete within the Timeout period, the function
1450 shall return EFI_TIMEOUT.
1451
1452 If the security protocol command completes without an error, the function shall
1453 return EFI_SUCCESS. If the security protocol command completes with an error, the
1454 function shall return EFI_DEVICE_ERROR.
1455
1456 @param This Indicates a pointer to the calling context.
1457 @param MediaId ID of the medium to receive data from.
1458 @param Timeout The timeout, in 100ns units, to use for the execution
1459 of the security protocol command. A Timeout value of 0
1460 means that this function will wait indefinitely for the
1461 security protocol command to execute. If Timeout is greater
1462 than zero, then this function will return EFI_TIMEOUT
1463 if the time required to execute the receive data command
1464 is greater than Timeout.
1465 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1466 the security protocol command to be sent.
1467 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1468 of the security protocol command to be sent.
1469 @param PayloadBufferSize Size in bytes of the payload data buffer.
1470 @param PayloadBuffer A pointer to a destination buffer to store the security
1471 protocol command specific payload data for the security
1472 protocol command. The caller is responsible for having
1473 either implicit or explicit ownership of the buffer.
1474 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1475 data written to the payload data buffer.
1476
1477 @retval EFI_SUCCESS The security protocol command completed successfully.
1478 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1479 data from the device. The PayloadBuffer contains the truncated data.
1480 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1481 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1482 @retval EFI_NO_MEDIA There is no media in the device.
1483 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1484 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1485 PayloadBufferSize is non-zero.
1486 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1487 protocol command to execute.
1488
1489 **/
1490 EFI_STATUS
1491 EFIAPI
1492 EmmcSecurityProtocolIn (
1493 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1494 IN UINT32 MediaId,
1495 IN UINT64 Timeout,
1496 IN UINT8 SecurityProtocolId,
1497 IN UINT16 SecurityProtocolSpecificData,
1498 IN UINTN PayloadBufferSize,
1499 OUT VOID *PayloadBuffer,
1500 OUT UINTN *PayloadTransferSize
1501 )
1502 {
1503 EFI_STATUS Status;
1504
1505 if ((PayloadTransferSize == NULL) && (PayloadBufferSize != 0)) {
1506 return EFI_INVALID_PARAMETER;
1507 }
1508
1509 Status = EmmcSecurityProtocolInOut (
1510 This,
1511 MediaId,
1512 Timeout,
1513 SecurityProtocolId,
1514 SecurityProtocolSpecificData,
1515 PayloadBufferSize,
1516 PayloadBuffer,
1517 PayloadTransferSize,
1518 TRUE
1519 );
1520
1521 return Status;
1522 }
1523
1524 /**
1525 Send a security protocol command to a device.
1526
1527 The SendData function sends a security protocol command containing the payload
1528 PayloadBuffer to the given MediaId. The security protocol command sent is
1529 defined by SecurityProtocolId and contains the security protocol specific data
1530 SecurityProtocolSpecificData. If the underlying protocol command requires a
1531 specific padding for the command payload, the SendData function shall add padding
1532 bytes to the command payload to satisfy the padding requirements.
1533
1534 For devices supporting the SCSI command set, the security protocol command is sent
1535 using the SECURITY PROTOCOL OUT command defined in SPC-4.
1536
1537 For devices supporting the ATA command set, the security protocol command is sent
1538 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
1539 is non-zero. If the PayloadBufferSize is zero, the security protocol command is
1540 sent using the Trusted Non-Data command defined in ATA8-ACS.
1541
1542 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1543 return EFI_INVALID_PARAMETER.
1544
1545 If the given MediaId does not support security protocol commands, the function
1546 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
1547 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
1548 device, the function returns EFI_MEDIA_CHANGED.
1549
1550 If the security protocol fails to complete within the Timeout period, the function
1551 shall return EFI_TIMEOUT.
1552
1553 If the security protocol command completes without an error, the function shall return
1554 EFI_SUCCESS. If the security protocol command completes with an error, the function
1555 shall return EFI_DEVICE_ERROR.
1556
1557 @param This Indicates a pointer to the calling context.
1558 @param MediaId ID of the medium to receive data from.
1559 @param Timeout The timeout, in 100ns units, to use for the execution
1560 of the security protocol command. A Timeout value of 0
1561 means that this function will wait indefinitely for the
1562 security protocol command to execute. If Timeout is greater
1563 than zero, then this function will return EFI_TIMEOUT
1564 if the time required to execute the receive data command
1565 is greater than Timeout.
1566 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1567 the security protocol command to be sent.
1568 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1569 of the security protocol command to be sent.
1570 @param PayloadBufferSize Size in bytes of the payload data buffer.
1571 @param PayloadBuffer A pointer to a destination buffer to store the security
1572 protocol command specific payload data for the security
1573 protocol command.
1574
1575 @retval EFI_SUCCESS The security protocol command completed successfully.
1576 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1577 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1578 @retval EFI_NO_MEDIA There is no media in the device.
1579 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1580 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
1581 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1582 protocol command to execute.
1583
1584 **/
1585 EFI_STATUS
1586 EFIAPI
1587 EmmcSecurityProtocolOut (
1588 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1589 IN UINT32 MediaId,
1590 IN UINT64 Timeout,
1591 IN UINT8 SecurityProtocolId,
1592 IN UINT16 SecurityProtocolSpecificData,
1593 IN UINTN PayloadBufferSize,
1594 IN VOID *PayloadBuffer
1595 )
1596 {
1597 EFI_STATUS Status;
1598
1599 Status = EmmcSecurityProtocolInOut (
1600 This,
1601 MediaId,
1602 Timeout,
1603 SecurityProtocolId,
1604 SecurityProtocolSpecificData,
1605 PayloadBufferSize,
1606 PayloadBuffer,
1607 NULL,
1608 FALSE
1609 );
1610
1611 return Status;
1612 }
1613
1614 /**
1615 Set the erase start address through sync or async I/O request.
1616
1617 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1618 @param[in] StartLba The starting logical block address to be erased.
1619 @param[in] Token A pointer to the token associated with the transaction.
1620 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1621 This parameter is only meaningful in async I/O request.
1622
1623 @retval EFI_SUCCESS The request is executed successfully.
1624 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1625 @retval Others The request could not be executed successfully.
1626
1627 **/
1628 EFI_STATUS
1629 EmmcEraseBlockStart (
1630 IN EMMC_PARTITION *Partition,
1631 IN EFI_LBA StartLba,
1632 IN EFI_BLOCK_IO2_TOKEN *Token,
1633 IN BOOLEAN IsEnd
1634 )
1635 {
1636 EFI_STATUS Status;
1637 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1638 EMMC_DEVICE *Device;
1639 EMMC_REQUEST *EraseBlockStart;
1640 EFI_TPL OldTpl;
1641
1642 EraseBlockStart = NULL;
1643
1644 Device = Partition->Device;
1645 PassThru = Device->Private->PassThru;
1646
1647 EraseBlockStart = AllocateZeroPool (sizeof (EMMC_REQUEST));
1648 if (EraseBlockStart == NULL) {
1649 Status = EFI_OUT_OF_RESOURCES;
1650 goto Error;
1651 }
1652
1653 EraseBlockStart->Signature = EMMC_REQUEST_SIGNATURE;
1654 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1655 InsertTailList (&Partition->Queue, &EraseBlockStart->Link);
1656 gBS->RestoreTPL (OldTpl);
1657 EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
1658 EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
1659 EraseBlockStart->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
1660
1661 EraseBlockStart->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_START;
1662 EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1663 EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1664
1665 if (Device->SectorAddressing) {
1666 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
1667 } else {
1668 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Partition->BlockMedia.BlockSize);
1669 }
1670
1671 EraseBlockStart->IsEnd = IsEnd;
1672 EraseBlockStart->Token = Token;
1673
1674 if ((Token != NULL) && (Token->Event != NULL)) {
1675 Status = gBS->CreateEvent (
1676 EVT_NOTIFY_SIGNAL,
1677 TPL_NOTIFY,
1678 AsyncIoCallback,
1679 EraseBlockStart,
1680 &EraseBlockStart->Event
1681 );
1682 if (EFI_ERROR (Status)) {
1683 goto Error;
1684 }
1685 } else {
1686 EraseBlockStart->Event = NULL;
1687 }
1688
1689 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
1690
1691 Error:
1692 if ((Token != NULL) && (Token->Event != NULL)) {
1693 //
1694 // For asynchronous operation, only free request and event in error case.
1695 // The request and event will be freed in asynchronous callback for success case.
1696 //
1697 if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
1698 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1699 RemoveEntryList (&EraseBlockStart->Link);
1700 gBS->RestoreTPL (OldTpl);
1701 if (EraseBlockStart->Event != NULL) {
1702 gBS->CloseEvent (EraseBlockStart->Event);
1703 }
1704
1705 FreePool (EraseBlockStart);
1706 }
1707 } else {
1708 //
1709 // For synchronous operation, free request whatever the execution result is.
1710 //
1711 if (EraseBlockStart != NULL) {
1712 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1713 RemoveEntryList (&EraseBlockStart->Link);
1714 gBS->RestoreTPL (OldTpl);
1715 FreePool (EraseBlockStart);
1716 }
1717 }
1718
1719 return Status;
1720 }
1721
1722 /**
1723 Set the erase end address through sync or async I/O request.
1724
1725 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1726 @param[in] EndLba The ending logical block address to be erased.
1727 @param[in] Token A pointer to the token associated with the transaction.
1728 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1729 This parameter is only meaningful in async I/O request.
1730
1731 @retval EFI_SUCCESS The request is executed successfully.
1732 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1733 @retval Others The request could not be executed successfully.
1734
1735 **/
1736 EFI_STATUS
1737 EmmcEraseBlockEnd (
1738 IN EMMC_PARTITION *Partition,
1739 IN EFI_LBA EndLba,
1740 IN EFI_BLOCK_IO2_TOKEN *Token,
1741 IN BOOLEAN IsEnd
1742 )
1743 {
1744 EFI_STATUS Status;
1745 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1746 EMMC_DEVICE *Device;
1747 EMMC_REQUEST *EraseBlockEnd;
1748 EFI_TPL OldTpl;
1749
1750 EraseBlockEnd = NULL;
1751
1752 Device = Partition->Device;
1753 PassThru = Device->Private->PassThru;
1754
1755 EraseBlockEnd = AllocateZeroPool (sizeof (EMMC_REQUEST));
1756 if (EraseBlockEnd == NULL) {
1757 Status = EFI_OUT_OF_RESOURCES;
1758 goto Error;
1759 }
1760
1761 EraseBlockEnd->Signature = EMMC_REQUEST_SIGNATURE;
1762 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1763 InsertTailList (&Partition->Queue, &EraseBlockEnd->Link);
1764 gBS->RestoreTPL (OldTpl);
1765 EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
1766 EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
1767 EraseBlockEnd->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
1768
1769 EraseBlockEnd->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_END;
1770 EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1771 EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1772
1773 if (Device->SectorAddressing) {
1774 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
1775 } else {
1776 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Partition->BlockMedia.BlockSize);
1777 }
1778
1779 EraseBlockEnd->IsEnd = IsEnd;
1780 EraseBlockEnd->Token = Token;
1781
1782 if ((Token != NULL) && (Token->Event != NULL)) {
1783 Status = gBS->CreateEvent (
1784 EVT_NOTIFY_SIGNAL,
1785 TPL_NOTIFY,
1786 AsyncIoCallback,
1787 EraseBlockEnd,
1788 &EraseBlockEnd->Event
1789 );
1790 if (EFI_ERROR (Status)) {
1791 goto Error;
1792 }
1793 } else {
1794 EraseBlockEnd->Event = NULL;
1795 }
1796
1797 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
1798
1799 Error:
1800 if ((Token != NULL) && (Token->Event != NULL)) {
1801 //
1802 // For asynchronous operation, only free request and event in error case.
1803 // The request and event will be freed in asynchronous callback for success case.
1804 //
1805 if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
1806 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1807 RemoveEntryList (&EraseBlockEnd->Link);
1808 gBS->RestoreTPL (OldTpl);
1809 if (EraseBlockEnd->Event != NULL) {
1810 gBS->CloseEvent (EraseBlockEnd->Event);
1811 }
1812
1813 FreePool (EraseBlockEnd);
1814 }
1815 } else {
1816 //
1817 // For synchronous operation, free request whatever the execution result is.
1818 //
1819 if (EraseBlockEnd != NULL) {
1820 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1821 RemoveEntryList (&EraseBlockEnd->Link);
1822 gBS->RestoreTPL (OldTpl);
1823 FreePool (EraseBlockEnd);
1824 }
1825 }
1826
1827 return Status;
1828 }
1829
1830 /**
1831 Erase specified blocks through sync or async I/O request.
1832
1833 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1834 @param[in] Token A pointer to the token associated with the transaction.
1835 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1836 This parameter is only meaningful in async I/O request.
1837
1838 @retval EFI_SUCCESS The request is executed successfully.
1839 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1840 @retval Others The request could not be executed successfully.
1841
1842 **/
1843 EFI_STATUS
1844 EmmcEraseBlock (
1845 IN EMMC_PARTITION *Partition,
1846 IN EFI_BLOCK_IO2_TOKEN *Token,
1847 IN BOOLEAN IsEnd
1848 )
1849 {
1850 EFI_STATUS Status;
1851 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1852 EMMC_DEVICE *Device;
1853 EMMC_REQUEST *EraseBlock;
1854 EFI_TPL OldTpl;
1855
1856 EraseBlock = NULL;
1857
1858 Device = Partition->Device;
1859 PassThru = Device->Private->PassThru;
1860
1861 EraseBlock = AllocateZeroPool (sizeof (EMMC_REQUEST));
1862 if (EraseBlock == NULL) {
1863 Status = EFI_OUT_OF_RESOURCES;
1864 goto Error;
1865 }
1866
1867 EraseBlock->Signature = EMMC_REQUEST_SIGNATURE;
1868 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1869 InsertTailList (&Partition->Queue, &EraseBlock->Link);
1870 gBS->RestoreTPL (OldTpl);
1871 EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
1872 EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
1873 EraseBlock->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
1874
1875 EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_ERASE;
1876 EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1877 EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
1878 if ((Device->ExtCsd.SecFeatureSupport & BIT4) != 0) {
1879 //
1880 // Perform a Trim operation which applies the erase operation to write blocks
1881 // instead of erase groups. (Spec JESD84-B51, eMMC Electrical Standard 5.1,
1882 // Section 6.6.10 and 6.10.4)
1883 //
1884 EraseBlock->SdMmcCmdBlk.CommandArgument = 1;
1885 }
1886
1887 EraseBlock->IsEnd = IsEnd;
1888 EraseBlock->Token = Token;
1889
1890 if ((Token != NULL) && (Token->Event != NULL)) {
1891 Status = gBS->CreateEvent (
1892 EVT_NOTIFY_SIGNAL,
1893 TPL_NOTIFY,
1894 AsyncIoCallback,
1895 EraseBlock,
1896 &EraseBlock->Event
1897 );
1898 if (EFI_ERROR (Status)) {
1899 goto Error;
1900 }
1901 } else {
1902 EraseBlock->Event = NULL;
1903 }
1904
1905 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
1906
1907 Error:
1908 if ((Token != NULL) && (Token->Event != NULL)) {
1909 //
1910 // For asynchronous operation, only free request and event in error case.
1911 // The request and event will be freed in asynchronous callback for success case.
1912 //
1913 if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
1914 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1915 RemoveEntryList (&EraseBlock->Link);
1916 gBS->RestoreTPL (OldTpl);
1917 if (EraseBlock->Event != NULL) {
1918 gBS->CloseEvent (EraseBlock->Event);
1919 }
1920
1921 FreePool (EraseBlock);
1922 }
1923 } else {
1924 //
1925 // For synchronous operation, free request whatever the execution result is.
1926 //
1927 if (EraseBlock != NULL) {
1928 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1929 RemoveEntryList (&EraseBlock->Link);
1930 gBS->RestoreTPL (OldTpl);
1931 FreePool (EraseBlock);
1932 }
1933 }
1934
1935 return Status;
1936 }
1937
1938 /**
1939 Write zeros to specified blocks.
1940
1941 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1942 @param[in] StartLba The starting logical block address to write zeros.
1943 @param[in] Size The size in bytes to fill with zeros. This must be a multiple of
1944 the physical block size of the device.
1945
1946 @retval EFI_SUCCESS The request is executed successfully.
1947 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1948 @retval Others The request could not be executed successfully.
1949
1950 **/
1951 EFI_STATUS
1952 EmmcWriteZeros (
1953 IN EMMC_PARTITION *Partition,
1954 IN EFI_LBA StartLba,
1955 IN UINTN Size
1956 )
1957 {
1958 EFI_STATUS Status;
1959 UINT8 *Buffer;
1960 UINT32 MediaId;
1961
1962 Buffer = AllocateZeroPool (Size);
1963 if (Buffer == NULL) {
1964 return EFI_OUT_OF_RESOURCES;
1965 }
1966
1967 MediaId = Partition->BlockMedia.MediaId;
1968
1969 Status = EmmcReadWrite (Partition, MediaId, StartLba, Buffer, Size, FALSE, NULL);
1970 FreePool (Buffer);
1971
1972 return Status;
1973 }
1974
1975 /**
1976 Erase a specified number of device blocks.
1977
1978 @param[in] This Indicates a pointer to the calling context.
1979 @param[in] MediaId The media ID that the erase request is for.
1980 @param[in] Lba The starting logical block address to be
1981 erased. The caller is responsible for erasing
1982 only legitimate locations.
1983 @param[in, out] Token A pointer to the token associated with the
1984 transaction.
1985 @param[in] Size The size in bytes to be erased. This must be
1986 a multiple of the physical block size of the
1987 device.
1988
1989 @retval EFI_SUCCESS The erase request was queued if Event is not
1990 NULL. The data was erased correctly to the
1991 device if the Event is NULL.to the device.
1992 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1993 protection.
1994 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1995 to perform the erase operation.
1996 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1997 valid.
1998 @retval EFI_NO_MEDIA There is no media in the device.
1999 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
2000
2001 **/
2002 EFI_STATUS
2003 EFIAPI
2004 EmmcEraseBlocks (
2005 IN EFI_ERASE_BLOCK_PROTOCOL *This,
2006 IN UINT32 MediaId,
2007 IN EFI_LBA Lba,
2008 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
2009 IN UINTN Size
2010 )
2011 {
2012 EFI_STATUS Status;
2013 EFI_BLOCK_IO_MEDIA *Media;
2014 UINTN BlockSize;
2015 UINTN BlockNum;
2016 EFI_LBA FirstLba;
2017 EFI_LBA LastLba;
2018 EFI_LBA StartGroupLba;
2019 EFI_LBA EndGroupLba;
2020 UINT32 EraseGroupSize;
2021 UINT32 Remainder;
2022 UINTN WriteZeroSize;
2023 UINT8 PartitionConfig;
2024 EMMC_PARTITION *Partition;
2025 EMMC_DEVICE *Device;
2026
2027 Status = EFI_SUCCESS;
2028 Partition = EMMC_PARTITION_DATA_FROM_ERASEBLK (This);
2029 Device = Partition->Device;
2030 Media = &Partition->BlockMedia;
2031
2032 if (MediaId != Media->MediaId) {
2033 return EFI_MEDIA_CHANGED;
2034 }
2035
2036 if (Media->ReadOnly) {
2037 return EFI_WRITE_PROTECTED;
2038 }
2039
2040 //
2041 // Check parameters.
2042 //
2043 BlockSize = Media->BlockSize;
2044 if ((Size % BlockSize) != 0) {
2045 return EFI_INVALID_PARAMETER;
2046 }
2047
2048 BlockNum = Size / BlockSize;
2049 if ((Lba + BlockNum - 1) > Media->LastBlock) {
2050 return EFI_INVALID_PARAMETER;
2051 }
2052
2053 if ((Token != NULL) && (Token->Event != NULL)) {
2054 Token->TransactionStatus = EFI_SUCCESS;
2055 }
2056
2057 FirstLba = Lba;
2058 LastLba = Lba + BlockNum - 1;
2059
2060 //
2061 // Check if needs to switch partition access.
2062 //
2063 PartitionConfig = Device->ExtCsd.PartitionConfig;
2064 if ((PartitionConfig & 0x7) != Partition->PartitionType) {
2065 PartitionConfig &= (UINT8) ~0x7;
2066 PartitionConfig |= Partition->PartitionType;
2067 Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE);
2068 if (EFI_ERROR (Status)) {
2069 return Status;
2070 }
2071
2072 Device->ExtCsd.PartitionConfig = PartitionConfig;
2073 }
2074
2075 if ((Device->ExtCsd.SecFeatureSupport & BIT4) == 0) {
2076 //
2077 // If the Trim operation is not supported by the device, handle the erase
2078 // of blocks that do not form a complete erase group separately.
2079 //
2080 EraseGroupSize = This->EraseLengthGranularity;
2081
2082 DivU64x32Remainder (FirstLba, EraseGroupSize, &Remainder);
2083 StartGroupLba = (Remainder == 0) ? FirstLba : (FirstLba + EraseGroupSize - Remainder);
2084
2085 DivU64x32Remainder (LastLba + 1, EraseGroupSize, &Remainder);
2086 EndGroupLba = LastLba + 1 - Remainder;
2087
2088 //
2089 // If the size to erase is smaller than the erase group size, the whole
2090 // erase operation is performed by writing zeros.
2091 //
2092 if (BlockNum < EraseGroupSize) {
2093 Status = EmmcWriteZeros (Partition, FirstLba, Size);
2094 if (EFI_ERROR (Status)) {
2095 return Status;
2096 }
2097
2098 DEBUG ((
2099 DEBUG_INFO,
2100 "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2101 Lba,
2102 BlockNum,
2103 (Token != NULL) ? Token->Event : NULL,
2104 Status
2105 ));
2106
2107 if ((Token != NULL) && (Token->Event != NULL)) {
2108 Token->TransactionStatus = EFI_SUCCESS;
2109 gBS->SignalEvent (Token->Event);
2110 }
2111
2112 return EFI_SUCCESS;
2113 }
2114
2115 //
2116 // If the starting LBA to erase is not aligned with the start of an erase
2117 // group, write zeros to erase the data from starting LBA to the end of the
2118 // current erase group.
2119 //
2120 if (StartGroupLba > FirstLba) {
2121 WriteZeroSize = (UINTN)(StartGroupLba - FirstLba) * BlockSize;
2122 Status = EmmcWriteZeros (Partition, FirstLba, WriteZeroSize);
2123 if (EFI_ERROR (Status)) {
2124 return Status;
2125 }
2126 }
2127
2128 //
2129 // If the ending LBA to erase is not aligned with the end of an erase
2130 // group, write zeros to erase the data from the start of the erase group
2131 // to the ending LBA.
2132 //
2133 if (EndGroupLba <= LastLba) {
2134 WriteZeroSize = (UINTN)(LastLba + 1 - EndGroupLba) * BlockSize;
2135 Status = EmmcWriteZeros (Partition, EndGroupLba, WriteZeroSize);
2136 if (EFI_ERROR (Status)) {
2137 return Status;
2138 }
2139 }
2140
2141 //
2142 // Check whether there is erase group to erase.
2143 //
2144 if (EndGroupLba <= StartGroupLba) {
2145 DEBUG ((
2146 DEBUG_INFO,
2147 "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2148 Lba,
2149 BlockNum,
2150 (Token != NULL) ? Token->Event : NULL,
2151 Status
2152 ));
2153
2154 if ((Token != NULL) && (Token->Event != NULL)) {
2155 Token->TransactionStatus = EFI_SUCCESS;
2156 gBS->SignalEvent (Token->Event);
2157 }
2158
2159 return EFI_SUCCESS;
2160 }
2161
2162 FirstLba = StartGroupLba;
2163 LastLba = EndGroupLba - 1;
2164 }
2165
2166 Status = EmmcEraseBlockStart (Partition, FirstLba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE);
2167 if (EFI_ERROR (Status)) {
2168 return Status;
2169 }
2170
2171 Status = EmmcEraseBlockEnd (Partition, LastLba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE);
2172 if (EFI_ERROR (Status)) {
2173 return Status;
2174 }
2175
2176 Status = EmmcEraseBlock (Partition, (EFI_BLOCK_IO2_TOKEN *)Token, TRUE);
2177 if (EFI_ERROR (Status)) {
2178 return Status;
2179 }
2180
2181 DEBUG ((
2182 DEBUG_INFO,
2183 "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2184 Lba,
2185 BlockNum,
2186 (Token != NULL) ? Token->Event : NULL,
2187 Status
2188 ));
2189
2190 return Status;
2191 }