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