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