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