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