]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
MdeModulePkg/SdDxe: Check the Token to avoid null pointer
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdDxe / SdBlockIo.c
CommitLineData
48555339
FT
1/** @file\r
2 The helper functions for BlockIo and BlockIo2 protocol.\r
3\r
0f4387e5 4 Copyright (c) 2015 - 2018, 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 "SdDxe.h"\r
10\r
11/**\r
b854b075 12 Nonblocking I/O callback function when the event is signaled.\r
48555339
FT
13\r
14 @param[in] Event The Event this notify function registered to.\r
15 @param[in] Context Pointer to the context data registered to the\r
16 Event.\r
17\r
18**/\r
19VOID\r
20EFIAPI\r
21AsyncIoCallback (\r
22 IN EFI_EVENT Event,\r
23 IN VOID *Context\r
24 )\r
25{\r
26 SD_REQUEST *Request;\r
27\r
28 gBS->CloseEvent (Event);\r
29\r
30 Request = (SD_REQUEST *) Context;\r
31\r
32 DEBUG_CODE_BEGIN ();\r
33 DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",\r
34 Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,\r
35 Request->Packet.TransactionStatus));\r
36 DEBUG_CODE_END ();\r
37\r
38 if (EFI_ERROR (Request->Packet.TransactionStatus)) {\r
39 Request->Token->TransactionStatus = Request->Packet.TransactionStatus;\r
40 }\r
41\r
42 RemoveEntryList (&Request->Link);\r
43\r
44 if (Request->IsEnd) {\r
45 gBS->SignalEvent (Request->Token->Event);\r
46 }\r
47\r
48 FreePool (Request);\r
49}\r
50\r
51/**\r
52 Send command SET_RELATIVE_ADDRESS to the device to set the device address.\r
53\r
54 @param[in] Device A pointer to the SD_DEVICE instance.\r
55 @param[out] Rca The relative device address to assign.\r
56\r
57 @retval EFI_SUCCESS The request is executed successfully.\r
58 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
59 @retval Others The request could not be executed successfully.\r
60\r
61**/\r
62EFI_STATUS\r
63SdSetRca (\r
64 IN SD_DEVICE *Device,\r
65 OUT UINT16 *Rca\r
66 )\r
67{\r
68 EFI_STATUS Status;\r
69 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
70 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
71 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
72 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
73\r
74 PassThru = Device->Private->PassThru;\r
75\r
76 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
77 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
78 ZeroMem (&Packet, sizeof (Packet));\r
79 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
80 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
81 Packet.Timeout = SD_GENERIC_TIMEOUT;\r
82\r
83 SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
84 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
85 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;\r
86\r
87 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
88 if (!EFI_ERROR (Status)) {\r
89 DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));\r
90 *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);\r
91 }\r
92\r
93 return Status;\r
94}\r
95\r
96/**\r
97 Send command SELECT to the device to select/deselect the device.\r
98\r
99 @param[in] Device A pointer to the SD_DEVICE instance.\r
100 @param[in] Rca The relative device address to use.\r
101\r
102 @retval EFI_SUCCESS The request is executed successfully.\r
103 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
104 @retval Others The request could not be executed successfully.\r
105\r
106**/\r
107EFI_STATUS\r
108SdSelect (\r
109 IN SD_DEVICE *Device,\r
110 IN UINT16 Rca\r
111 )\r
112{\r
113 EFI_STATUS Status;\r
114 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
115 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
116 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
117 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
118\r
119 PassThru = Device->Private->PassThru;\r
120\r
121 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
122 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
123 ZeroMem (&Packet, sizeof (Packet));\r
124 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
125 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
126 Packet.Timeout = SD_GENERIC_TIMEOUT;\r
127\r
128 SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
129 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
ac30e4c1
FT
130 if (Rca != 0) {\r
131 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
132 }\r
48555339
FT
133 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
134\r
135 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
136\r
137 return Status;\r
138}\r
139\r
140/**\r
141 Send command SEND_STATUS to the device to get device status.\r
142\r
143 @param[in] Device A pointer to the SD_DEVICE instance.\r
144 @param[in] Rca The relative device address to use.\r
145 @param[out] DevStatus The buffer to store the device status.\r
146\r
147 @retval EFI_SUCCESS The request is executed successfully.\r
148 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
149 @retval Others The request could not be executed successfully.\r
150\r
151**/\r
152EFI_STATUS\r
153SdSendStatus (\r
154 IN SD_DEVICE *Device,\r
155 IN UINT16 Rca,\r
156 OUT UINT32 *DevStatus\r
157 )\r
158{\r
159 EFI_STATUS Status;\r
160 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
161 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
162 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
163 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
164\r
165 PassThru = Device->Private->PassThru;\r
166\r
167 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
168 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
169 ZeroMem (&Packet, sizeof (Packet));\r
170 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
171 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
172 Packet.Timeout = SD_GENERIC_TIMEOUT;\r
173\r
174 SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;\r
175 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
176 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
177 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
178\r
179 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
180 if (!EFI_ERROR (Status)) {\r
181 CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));\r
182 }\r
183 return Status;\r
184}\r
185\r
186/**\r
187 Send command SEND_CSD to the device to get the CSD register data.\r
188\r
189 @param[in] Device A pointer to the SD_DEVICE instance.\r
190 @param[in] Rca The relative device address to use.\r
191 @param[out] Csd The buffer to store the SD_CSD register data.\r
192\r
193 @retval EFI_SUCCESS The request is executed successfully.\r
194 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
195 @retval Others The request could not be executed successfully.\r
196\r
197**/\r
198EFI_STATUS\r
199SdGetCsd (\r
200 IN SD_DEVICE *Device,\r
201 IN UINT16 Rca,\r
202 OUT SD_CSD *Csd\r
203 )\r
204{\r
205 EFI_STATUS Status;\r
206 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
207 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
208 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
209 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
210\r
211 PassThru = Device->Private->PassThru;\r
212\r
213 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
214 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
215 ZeroMem (&Packet, sizeof (Packet));\r
216 ZeroMem (Csd, sizeof (SD_CSD));\r
217\r
218 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
219 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
220 Packet.Timeout = SD_GENERIC_TIMEOUT;\r
221\r
222 SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;\r
223 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
224 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
225 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
226\r
227 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
228\r
229 if (!EFI_ERROR (Status)) {\r
230 //\r
231 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
232 //\r
233 CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
234 }\r
235\r
236 return Status;\r
237}\r
238\r
239/**\r
240 Send command SEND_CID to the device to get the CID register data.\r
241\r
242 @param[in] Device A pointer to the SD_DEVICE instance.\r
243 @param[in] Rca The relative device address to use.\r
244 @param[out] Cid The buffer to store the SD_CID register data.\r
245\r
246 @retval EFI_SUCCESS The request is executed successfully.\r
247 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
248 @retval Others The request could not be executed successfully.\r
249\r
250**/\r
251EFI_STATUS\r
252SdGetCid (\r
253 IN SD_DEVICE *Device,\r
254 IN UINT16 Rca,\r
255 OUT SD_CID *Cid\r
256 )\r
257{\r
258 EFI_STATUS Status;\r
259 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
260 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
261 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
262 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
263\r
264 PassThru = Device->Private->PassThru;\r
265\r
266 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
267 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
268 ZeroMem (&Packet, sizeof (Packet));\r
269 ZeroMem (Cid, sizeof (SD_CID));\r
270\r
271 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
272 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
273 Packet.Timeout = SD_GENERIC_TIMEOUT;\r
274\r
275 SdMmcCmdBlk.CommandIndex = SD_SEND_CID;\r
276 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
277 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
278 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
279\r
280 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
281\r
282 if (!EFI_ERROR (Status)) {\r
283 //\r
284 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
285 //\r
286 CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);\r
287 }\r
288\r
289 return Status;\r
290}\r
291\r
292/**\r
293 Read/write single block through sync or async I/O request.\r
294\r
295 @param[in] Device A pointer to the SD_DEVICE instance.\r
296 @param[in] Lba The starting logical block address to be read/written.\r
297 The caller is responsible for reading/writing to only\r
298 legitimate locations.\r
299 @param[in] Buffer A pointer to the destination/source buffer for the data.\r
300 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
301 @param[in] IsRead Indicates it is a read or write operation.\r
302 @param[in] Token A pointer to the token associated with the transaction.\r
303 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
304 This parameter is only meaningful in async I/O request.\r
305\r
306 @retval EFI_SUCCESS The request is executed successfully.\r
307 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
308 @retval Others The request could not be executed successfully.\r
309\r
310**/\r
311EFI_STATUS\r
312SdRwSingleBlock (\r
313 IN SD_DEVICE *Device,\r
314 IN EFI_LBA Lba,\r
315 IN VOID *Buffer,\r
316 IN UINTN BufferSize,\r
317 IN BOOLEAN IsRead,\r
318 IN EFI_BLOCK_IO2_TOKEN *Token,\r
319 IN BOOLEAN IsEnd\r
320 )\r
321{\r
322 EFI_STATUS Status;\r
323 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
324 SD_REQUEST *RwSingleBlkReq;\r
325 EFI_TPL OldTpl;\r
326\r
327 RwSingleBlkReq = NULL;\r
328 PassThru = Device->Private->PassThru;\r
329\r
330 RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
331 if (RwSingleBlkReq == NULL) {\r
332 Status = EFI_OUT_OF_RESOURCES;\r
333 goto Error;\r
334 }\r
335\r
336 RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 337 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339
FT
338 InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);\r
339 gBS->RestoreTPL (OldTpl);\r
340 RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;\r
341 RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;\r
342 //\r
343 // Calculate timeout value through the below formula.\r
344 // Timeout = (transfer size) / (2MB/s).\r
345 // Taking 2MB/s as divisor as it's the lowest transfer speed\r
346 // above class 2.\r
347 // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
348 //\r
349 RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
350\r
351 if (IsRead) {\r
352 RwSingleBlkReq->Packet.InDataBuffer = Buffer;\r
353 RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
354\r
355 RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;\r
356 RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
357 RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
358 } else {\r
359 RwSingleBlkReq->Packet.OutDataBuffer = Buffer;\r
360 RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
361\r
362 RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;\r
363 RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
364 RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
365 }\r
366\r
367 if (Device->SectorAddressing) {\r
368 RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
369 } else {\r
370 RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
371 }\r
372\r
373 RwSingleBlkReq->IsEnd = IsEnd;\r
374 RwSingleBlkReq->Token = Token;\r
375\r
376 if ((Token != NULL) && (Token->Event != NULL)) {\r
377 Status = gBS->CreateEvent (\r
378 EVT_NOTIFY_SIGNAL,\r
3b1d8241 379 TPL_NOTIFY,\r
48555339
FT
380 AsyncIoCallback,\r
381 RwSingleBlkReq,\r
382 &RwSingleBlkReq->Event\r
383 );\r
384 if (EFI_ERROR (Status)) {\r
385 goto Error;\r
386 }\r
387 } else {\r
388 RwSingleBlkReq->Event = NULL;\r
389 }\r
390\r
391 Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);\r
392\r
393Error:\r
394 if ((Token != NULL) && (Token->Event != NULL)) {\r
395 //\r
396 // For asynchronous operation, only free request and event in error case.\r
397 // The request and event will be freed in asynchronous callback for success case.\r
398 //\r
399 if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {\r
3b1d8241 400 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 401 RemoveEntryList (&RwSingleBlkReq->Link);\r
3b1d8241 402 gBS->RestoreTPL (OldTpl);\r
48555339
FT
403 if (RwSingleBlkReq->Event != NULL) {\r
404 gBS->CloseEvent (RwSingleBlkReq->Event);\r
405 }\r
406 FreePool (RwSingleBlkReq);\r
407 }\r
408 } else {\r
409 //\r
410 // For synchronous operation, free request whatever the execution result is.\r
411 //\r
412 if (RwSingleBlkReq != NULL) {\r
3b1d8241 413 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 414 RemoveEntryList (&RwSingleBlkReq->Link);\r
3b1d8241 415 gBS->RestoreTPL (OldTpl);\r
48555339
FT
416 FreePool (RwSingleBlkReq);\r
417 }\r
418 }\r
419\r
420 return Status;\r
421}\r
422\r
423/**\r
424 Read/write multiple blocks through sync or async I/O request.\r
425\r
426 @param[in] Device A pointer to the SD_DEVICE instance.\r
427 @param[in] Lba The starting logical block address to be read/written.\r
428 The caller is responsible for reading/writing to only\r
429 legitimate locations.\r
430 @param[in] Buffer A pointer to the destination/source buffer for the data.\r
431 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
432 @param[in] IsRead Indicates it is a read or write operation.\r
433 @param[in] Token A pointer to the token associated with the transaction.\r
434 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
435 This parameter is only meaningful in async I/O request.\r
436\r
437 @retval EFI_SUCCESS The request is executed successfully.\r
438 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
439 @retval Others The request could not be executed successfully.\r
440\r
441**/\r
442EFI_STATUS\r
443SdRwMultiBlocks (\r
444 IN SD_DEVICE *Device,\r
445 IN EFI_LBA Lba,\r
446 IN VOID *Buffer,\r
447 IN UINTN BufferSize,\r
448 IN BOOLEAN IsRead,\r
449 IN EFI_BLOCK_IO2_TOKEN *Token,\r
450 IN BOOLEAN IsEnd\r
451 )\r
452{\r
453 EFI_STATUS Status;\r
454 SD_REQUEST *RwMultiBlkReq;\r
455 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
456 EFI_TPL OldTpl;\r
457\r
458 RwMultiBlkReq = NULL;\r
459\r
460 PassThru = Device->Private->PassThru;\r
461\r
462 RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
463 if (RwMultiBlkReq == NULL) {\r
464 Status = EFI_OUT_OF_RESOURCES;\r
465 goto Error;\r
466 }\r
467\r
468 RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 469 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339
FT
470 InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);\r
471 gBS->RestoreTPL (OldTpl);\r
472 RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;\r
473 RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;\r
474 //\r
475 // Calculate timeout value through the below formula.\r
476 // Timeout = (transfer size) / (2MB/s).\r
477 // Taking 2MB/s as divisor as it's the lowest transfer speed\r
478 // above class 2.\r
479 // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
480 //\r
481 RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
482\r
483 if (IsRead) {\r
484 RwMultiBlkReq->Packet.InDataBuffer = Buffer;\r
485 RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
486\r
487 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;\r
488 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
489 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
490 } else {\r
491 RwMultiBlkReq->Packet.OutDataBuffer = Buffer;\r
492 RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
493\r
494 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;\r
495 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
496 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
497 }\r
498\r
499 if (Device->SectorAddressing) {\r
500 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
501 } else {\r
502 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
503 }\r
504\r
505 RwMultiBlkReq->IsEnd = IsEnd;\r
506 RwMultiBlkReq->Token = Token;\r
507\r
508 if ((Token != NULL) && (Token->Event != NULL)) {\r
509 Status = gBS->CreateEvent (\r
510 EVT_NOTIFY_SIGNAL,\r
3b1d8241 511 TPL_NOTIFY,\r
48555339
FT
512 AsyncIoCallback,\r
513 RwMultiBlkReq,\r
514 &RwMultiBlkReq->Event\r
515 );\r
516 if (EFI_ERROR (Status)) {\r
517 goto Error;\r
518 }\r
519 } else {\r
520 RwMultiBlkReq->Event = NULL;\r
521 }\r
522\r
523 Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);\r
524\r
525Error:\r
526 if ((Token != NULL) && (Token->Event != NULL)) {\r
527 //\r
528 // For asynchronous operation, only free request and event in error case.\r
529 // The request and event will be freed in asynchronous callback for success case.\r
530 //\r
531 if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
3b1d8241 532 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 533 RemoveEntryList (&RwMultiBlkReq->Link);\r
3b1d8241 534 gBS->RestoreTPL (OldTpl);\r
48555339
FT
535 if (RwMultiBlkReq->Event != NULL) {\r
536 gBS->CloseEvent (RwMultiBlkReq->Event);\r
537 }\r
538 FreePool (RwMultiBlkReq);\r
539 }\r
540 } else {\r
541 //\r
542 // For synchronous operation, free request whatever the execution result is.\r
543 //\r
544 if (RwMultiBlkReq != NULL) {\r
3b1d8241 545 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 546 RemoveEntryList (&RwMultiBlkReq->Link);\r
3b1d8241 547 gBS->RestoreTPL (OldTpl);\r
48555339
FT
548 FreePool (RwMultiBlkReq);\r
549 }\r
550 }\r
551\r
552 return Status;\r
553}\r
554\r
555/**\r
556 This function transfers data from/to the sd memory card device.\r
557\r
558 @param[in] Device A pointer to the SD_DEVICE instance.\r
559 @param[in] MediaId The media ID that the read/write request is for.\r
560 @param[in] Lba The starting logical block address to be read/written.\r
561 The caller is responsible for reading/writing to only\r
562 legitimate locations.\r
563 @param[in, out] Buffer A pointer to the destination/source buffer for the data.\r
564 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
565 @param[in] IsRead Indicates it is a read or write operation.\r
566 @param[in, out] Token A pointer to the token associated with the transaction.\r
567\r
568 @retval EFI_SUCCESS The data was read/written correctly to the device.\r
569 @retval EFI_WRITE_PROTECTED The device can not be read/written to.\r
570 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.\r
571 @retval EFI_NO_MEDIA There is no media in the device.\r
b854b075 572 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
48555339
FT
573 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
574 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
575 or the buffer is not on proper alignment.\r
576\r
577**/\r
578EFI_STATUS\r
579SdReadWrite (\r
580 IN SD_DEVICE *Device,\r
581 IN UINT32 MediaId,\r
582 IN EFI_LBA Lba,\r
583 IN OUT VOID *Buffer,\r
584 IN UINTN BufferSize,\r
585 IN BOOLEAN IsRead,\r
586 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
587 )\r
588{\r
589 EFI_STATUS Status;\r
590 EFI_BLOCK_IO_MEDIA *Media;\r
591 UINTN BlockSize;\r
592 UINTN BlockNum;\r
593 UINTN IoAlign;\r
594 UINTN Remaining;\r
595 UINT32 MaxBlock;\r
596 BOOLEAN LastRw;\r
597\r
598 Status = EFI_SUCCESS;\r
599 Media = &Device->BlockMedia;\r
600 LastRw = FALSE;\r
601\r
602 if (MediaId != Media->MediaId) {\r
603 return EFI_MEDIA_CHANGED;\r
604 }\r
605\r
606 if (!IsRead && Media->ReadOnly) {\r
607 return EFI_WRITE_PROTECTED;\r
608 }\r
609\r
610 //\r
611 // Check parameters.\r
612 //\r
613 if (Buffer == NULL) {\r
614 return EFI_INVALID_PARAMETER;\r
615 }\r
616\r
617 if (BufferSize == 0) {\r
618 if ((Token != NULL) && (Token->Event != NULL)) {\r
619 Token->TransactionStatus = EFI_SUCCESS;\r
620 gBS->SignalEvent (Token->Event);\r
621 }\r
622 return EFI_SUCCESS;\r
623 }\r
624\r
625 BlockSize = Media->BlockSize;\r
626 if ((BufferSize % BlockSize) != 0) {\r
627 return EFI_BAD_BUFFER_SIZE;\r
628 }\r
629\r
630 BlockNum = BufferSize / BlockSize;\r
631 if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
632 return EFI_INVALID_PARAMETER;\r
633 }\r
634\r
635 IoAlign = Media->IoAlign;\r
636 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
637 return EFI_INVALID_PARAMETER;\r
638 }\r
639\r
640 if ((Token != NULL) && (Token->Event != NULL)) {\r
641 Token->TransactionStatus = EFI_SUCCESS;\r
642 }\r
643\r
644 //\r
645 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
646 //\r
647 Remaining = BlockNum;\r
648 MaxBlock = 0xFFFF;\r
649\r
650 while (Remaining > 0) {\r
651 if (Remaining <= MaxBlock) {\r
652 BlockNum = Remaining;\r
653 LastRw = TRUE;\r
654 } else {\r
655 BlockNum = MaxBlock;\r
656 }\r
657\r
658 BufferSize = BlockNum * BlockSize;\r
659 if (BlockNum == 1) {\r
660 Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
661 } else {\r
662 Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
663 }\r
664 if (EFI_ERROR (Status)) {\r
665 return Status;\r
666 }\r
5a16ba3a
JB
667 DEBUG ((DEBUG_BLKIO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",\r
668 IsRead ? "Read" : "Write", Lba, BlockNum,\r
669 (Token != NULL) ? Token->Event : NULL, Status));\r
48555339
FT
670 Lba += BlockNum;\r
671 Buffer = (UINT8*)Buffer + BufferSize;\r
672 Remaining -= BlockNum;\r
673 }\r
674\r
675 return Status;\r
676}\r
677\r
678/**\r
679 Reset the Block Device.\r
680\r
681 @param This Indicates a pointer to the calling context.\r
682 @param ExtendedVerification Driver may perform diagnostics on reset.\r
683\r
684 @retval EFI_SUCCESS The device was reset.\r
685 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
686 not be reset.\r
687\r
688**/\r
689EFI_STATUS\r
690EFIAPI\r
691SdReset (\r
692 IN EFI_BLOCK_IO_PROTOCOL *This,\r
693 IN BOOLEAN ExtendedVerification\r
694 )\r
695{\r
696 EFI_STATUS Status;\r
697 SD_DEVICE *Device;\r
698 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
699\r
700 Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
701\r
702 PassThru = Device->Private->PassThru;\r
703 Status = PassThru->ResetDevice (PassThru, Device->Slot);\r
704 if (EFI_ERROR (Status)) {\r
705 Status = EFI_DEVICE_ERROR;\r
706 }\r
707\r
708 return Status;\r
709}\r
710\r
711/**\r
712 Read BufferSize bytes from Lba into Buffer.\r
713\r
714 @param This Indicates a pointer to the calling context.\r
715 @param MediaId Id of the media, changes every time the media is replaced.\r
716 @param Lba The starting Logical Block Address to read from\r
717 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
718 @param Buffer A pointer to the destination buffer for the data. The caller is\r
719 responsible for either having implicit or explicit ownership of the buffer.\r
720\r
721 @retval EFI_SUCCESS The data was read correctly from the device.\r
722 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
723 @retval EFI_NO_MEDIA There is no media in the device.\r
b854b075 724 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
48555339
FT
725 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
726 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
727 or the buffer is not on proper alignment.\r
728\r
729**/\r
730EFI_STATUS\r
731EFIAPI\r
732SdReadBlocks (\r
733 IN EFI_BLOCK_IO_PROTOCOL *This,\r
734 IN UINT32 MediaId,\r
735 IN EFI_LBA Lba,\r
736 IN UINTN BufferSize,\r
737 OUT VOID *Buffer\r
738 )\r
739{\r
740 EFI_STATUS Status;\r
741 SD_DEVICE *Device;\r
742\r
743 Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
744\r
745 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);\r
746 return Status;\r
747}\r
748\r
749/**\r
750 Write BufferSize bytes from Lba into Buffer.\r
751\r
752 @param This Indicates a pointer to the calling context.\r
753 @param MediaId The media ID that the write request is for.\r
754 @param Lba The starting logical block address to be written. The caller is\r
755 responsible for writing to only legitimate locations.\r
756 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
757 @param Buffer A pointer to the source buffer for the data.\r
758\r
759 @retval EFI_SUCCESS The data was written correctly to the device.\r
760 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
761 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
762 @retval EFI_NO_MEDIA There is no media in the device.\r
b854b075 763 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
48555339
FT
764 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
765 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
766 or the buffer is not on proper alignment.\r
767\r
768**/\r
769EFI_STATUS\r
770EFIAPI\r
771SdWriteBlocks (\r
772 IN EFI_BLOCK_IO_PROTOCOL *This,\r
773 IN UINT32 MediaId,\r
774 IN EFI_LBA Lba,\r
775 IN UINTN BufferSize,\r
776 IN VOID *Buffer\r
777 )\r
778{\r
779 EFI_STATUS Status;\r
780 SD_DEVICE *Device;\r
781\r
782 Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
783\r
784 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);\r
785 return Status;\r
786}\r
787\r
788/**\r
789 Flush the Block Device.\r
790\r
791 @param This Indicates a pointer to the calling context.\r
792\r
793 @retval EFI_SUCCESS All outstanding data was written to the device\r
794 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
795 @retval EFI_NO_MEDIA There is no media in the device.\r
796\r
797**/\r
798EFI_STATUS\r
799EFIAPI\r
800SdFlushBlocks (\r
801 IN EFI_BLOCK_IO_PROTOCOL *This\r
802 )\r
803{\r
804 //\r
805 // return directly\r
806 //\r
807 return EFI_SUCCESS;\r
808}\r
809\r
810/**\r
811 Reset the Block Device.\r
812\r
813 @param[in] This Indicates a pointer to the calling context.\r
814 @param[in] ExtendedVerification Driver may perform diagnostics on reset.\r
815\r
816 @retval EFI_SUCCESS The device was reset.\r
817 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
818 not be reset.\r
819\r
820**/\r
821EFI_STATUS\r
822EFIAPI\r
823SdResetEx (\r
824 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
825 IN BOOLEAN ExtendedVerification\r
826 )\r
827{\r
828 SD_DEVICE *Device;\r
829 LIST_ENTRY *Link;\r
830 LIST_ENTRY *NextLink;\r
831 SD_REQUEST *Request;\r
832 EFI_TPL OldTpl;\r
833\r
834 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
835\r
3b1d8241 836 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339
FT
837 for (Link = GetFirstNode (&Device->Queue);\r
838 !IsNull (&Device->Queue, Link);\r
839 Link = NextLink) {\r
840 NextLink = GetNextNode (&Device->Queue, Link);\r
841 RemoveEntryList (Link);\r
842\r
843 Request = SD_REQUEST_FROM_LINK (Link);\r
844\r
845 gBS->CloseEvent (Request->Event);\r
846 Request->Token->TransactionStatus = EFI_ABORTED;\r
847\r
848 if (Request->IsEnd) {\r
849 gBS->SignalEvent (Request->Token->Event);\r
850 }\r
851\r
852 FreePool (Request);\r
853 }\r
854 gBS->RestoreTPL (OldTpl);\r
855\r
856 return EFI_SUCCESS;\r
857}\r
858\r
859/**\r
860 Read BufferSize bytes from Lba into Buffer.\r
861\r
862 @param[in] This Indicates a pointer to the calling context.\r
863 @param[in] MediaId Id of the media, changes every time the media is replaced.\r
864 @param[in] Lba The starting Logical Block Address to read from.\r
865 @param[in, out] Token A pointer to the token associated with the transaction.\r
866 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
867 @param[out] Buffer A pointer to the destination buffer for the data. The caller is\r
868 responsible for either having implicit or explicit ownership of the buffer.\r
869\r
870 @retval EFI_SUCCESS The read request was queued if Event is not NULL.\r
871 The data was read correctly from the device if\r
872 the Event is NULL.\r
873 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
874 the read.\r
875 @retval EFI_NO_MEDIA There is no media in the device.\r
876 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
877 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
878 intrinsic block size of the device.\r
879 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
880 or the buffer is not on proper alignment.\r
881 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
882 of resources.\r
883\r
884**/\r
885EFI_STATUS\r
886EFIAPI\r
887SdReadBlocksEx (\r
888 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
889 IN UINT32 MediaId,\r
890 IN EFI_LBA Lba,\r
891 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
892 IN UINTN BufferSize,\r
893 OUT VOID *Buffer\r
894 )\r
895{\r
896 EFI_STATUS Status;\r
897 SD_DEVICE *Device;\r
898\r
899 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
900\r
901 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);\r
902 return Status;\r
903}\r
904\r
905/**\r
906 Write BufferSize bytes from Lba into Buffer.\r
907\r
908 @param[in] This Indicates a pointer to the calling context.\r
909 @param[in] MediaId The media ID that the write request is for.\r
910 @param[in] Lba The starting logical block address to be written. The\r
911 caller is responsible for writing to only legitimate\r
912 locations.\r
913 @param[in, out] Token A pointer to the token associated with the transaction.\r
914 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
915 @param[in] Buffer A pointer to the source buffer for the data.\r
916\r
917 @retval EFI_SUCCESS The data was written correctly to the device.\r
918 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
919 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
920 @retval EFI_NO_MEDIA There is no media in the device.\r
b854b075 921 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
48555339
FT
922 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
923 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
924 or the buffer is not on proper alignment.\r
925\r
926**/\r
927EFI_STATUS\r
928EFIAPI\r
929SdWriteBlocksEx (\r
930 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
931 IN UINT32 MediaId,\r
932 IN EFI_LBA Lba,\r
933 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
934 IN UINTN BufferSize,\r
935 IN VOID *Buffer\r
936 )\r
937{\r
938 EFI_STATUS Status;\r
939 SD_DEVICE *Device;\r
940\r
941 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
942\r
943 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);\r
944 return Status;\r
945}\r
946\r
947/**\r
948 Flush the Block Device.\r
949\r
950 @param[in] This Indicates a pointer to the calling context.\r
951 @param[in, out] Token A pointer to the token associated with the transaction.\r
952\r
953 @retval EFI_SUCCESS All outstanding data was written to the device\r
954 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
955 @retval EFI_NO_MEDIA There is no media in the device.\r
956\r
957**/\r
958EFI_STATUS\r
959EFIAPI\r
960SdFlushBlocksEx (\r
961 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
962 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
963 )\r
964{\r
965 //\r
966 // Signal event and return directly.\r
967 //\r
968 if (Token != NULL && Token->Event != NULL) {\r
969 Token->TransactionStatus = EFI_SUCCESS;\r
970 gBS->SignalEvent (Token->Event);\r
971 }\r
972\r
973 return EFI_SUCCESS;\r
974}\r
975\r
275d5136
FT
976/**\r
977 Set the erase start address through sync or async I/O request.\r
978\r
979 @param[in] Device A pointer to the SD_DEVICE instance.\r
980 @param[in] StartLba The starting logical block address to be erased.\r
981 @param[in] Token A pointer to the token associated with the transaction.\r
982 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
983 This parameter is only meaningful in async I/O request.\r
984\r
985 @retval EFI_SUCCESS The request is executed successfully.\r
986 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
987 @retval Others The request could not be executed successfully.\r
988\r
989**/\r
990EFI_STATUS\r
991SdEraseBlockStart (\r
992 IN SD_DEVICE *Device,\r
993 IN EFI_LBA StartLba,\r
994 IN EFI_BLOCK_IO2_TOKEN *Token,\r
995 IN BOOLEAN IsEnd\r
996 )\r
997{\r
998 EFI_STATUS Status;\r
999 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1000 SD_REQUEST *EraseBlockStart;\r
1001 EFI_TPL OldTpl;\r
1002\r
1003 EraseBlockStart = NULL;\r
1004 PassThru = Device->Private->PassThru;\r
1005\r
1006 EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));\r
1007 if (EraseBlockStart == NULL) {\r
1008 Status = EFI_OUT_OF_RESOURCES;\r
1009 goto Error;\r
1010 }\r
1011\r
1012 EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 1013 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136
FT
1014 InsertTailList (&Device->Queue, &EraseBlockStart->Link);\r
1015 gBS->RestoreTPL (OldTpl);\r
1016 EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;\r
1017 EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;\r
1018 EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
1019\r
1020 EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;\r
1021 EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
1022 EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
1023\r
1024 if (Device->SectorAddressing) {\r
1025 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;\r
1026 } else {\r
1027 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);\r
1028 }\r
1029\r
1030 EraseBlockStart->IsEnd = IsEnd;\r
1031 EraseBlockStart->Token = Token;\r
1032\r
1033 if ((Token != NULL) && (Token->Event != NULL)) {\r
1034 Status = gBS->CreateEvent (\r
1035 EVT_NOTIFY_SIGNAL,\r
3b1d8241 1036 TPL_NOTIFY,\r
275d5136
FT
1037 AsyncIoCallback,\r
1038 EraseBlockStart,\r
1039 &EraseBlockStart->Event\r
1040 );\r
1041 if (EFI_ERROR (Status)) {\r
1042 goto Error;\r
1043 }\r
1044 } else {\r
1045 EraseBlockStart->Event = NULL;\r
1046 }\r
1047\r
1048 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);\r
1049\r
1050Error:\r
1051 if ((Token != NULL) && (Token->Event != NULL)) {\r
1052 //\r
1053 // For asynchronous operation, only free request and event in error case.\r
1054 // The request and event will be freed in asynchronous callback for success case.\r
1055 //\r
1056 if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {\r
3b1d8241 1057 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1058 RemoveEntryList (&EraseBlockStart->Link);\r
3b1d8241 1059 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1060 if (EraseBlockStart->Event != NULL) {\r
1061 gBS->CloseEvent (EraseBlockStart->Event);\r
1062 }\r
1063 FreePool (EraseBlockStart);\r
1064 }\r
1065 } else {\r
1066 //\r
1067 // For synchronous operation, free request whatever the execution result is.\r
1068 //\r
1069 if (EraseBlockStart != NULL) {\r
3b1d8241 1070 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1071 RemoveEntryList (&EraseBlockStart->Link);\r
3b1d8241 1072 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1073 FreePool (EraseBlockStart);\r
1074 }\r
1075 }\r
1076\r
1077 return Status;\r
1078}\r
1079\r
1080/**\r
1081 Set the erase end address through sync or async I/O request.\r
1082\r
1083 @param[in] Device A pointer to the SD_DEVICE instance.\r
1084 @param[in] EndLba The ending logical block address to be erased.\r
1085 @param[in] Token A pointer to the token associated with the transaction.\r
1086 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
1087 This parameter is only meaningful in async I/O request.\r
1088\r
1089 @retval EFI_SUCCESS The request is executed successfully.\r
1090 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
1091 @retval Others The request could not be executed successfully.\r
1092\r
1093**/\r
1094EFI_STATUS\r
1095SdEraseBlockEnd (\r
1096 IN SD_DEVICE *Device,\r
1097 IN EFI_LBA EndLba,\r
1098 IN EFI_BLOCK_IO2_TOKEN *Token,\r
1099 IN BOOLEAN IsEnd\r
1100 )\r
1101{\r
1102 EFI_STATUS Status;\r
1103 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1104 SD_REQUEST *EraseBlockEnd;\r
1105 EFI_TPL OldTpl;\r
1106\r
1107 EraseBlockEnd = NULL;\r
1108 PassThru = Device->Private->PassThru;\r
1109\r
1110 EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));\r
1111 if (EraseBlockEnd == NULL) {\r
1112 Status = EFI_OUT_OF_RESOURCES;\r
1113 goto Error;\r
1114 }\r
1115\r
1116 EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 1117 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136
FT
1118 InsertTailList (&Device->Queue, &EraseBlockEnd->Link);\r
1119 gBS->RestoreTPL (OldTpl);\r
1120 EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;\r
1121 EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;\r
1122 EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
1123\r
1124 EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;\r
1125 EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
1126 EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
1127\r
1128 if (Device->SectorAddressing) {\r
1129 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;\r
1130 } else {\r
1131 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);\r
1132 }\r
1133\r
1134 EraseBlockEnd->IsEnd = IsEnd;\r
1135 EraseBlockEnd->Token = Token;\r
1136\r
1137 if ((Token != NULL) && (Token->Event != NULL)) {\r
1138 Status = gBS->CreateEvent (\r
1139 EVT_NOTIFY_SIGNAL,\r
3b1d8241 1140 TPL_NOTIFY,\r
275d5136
FT
1141 AsyncIoCallback,\r
1142 EraseBlockEnd,\r
1143 &EraseBlockEnd->Event\r
1144 );\r
1145 if (EFI_ERROR (Status)) {\r
1146 goto Error;\r
1147 }\r
1148 } else {\r
1149 EraseBlockEnd->Event = NULL;\r
1150 }\r
1151\r
1152 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);\r
1153\r
1154Error:\r
1155 if ((Token != NULL) && (Token->Event != NULL)) {\r
1156 //\r
1157 // For asynchronous operation, only free request and event in error case.\r
1158 // The request and event will be freed in asynchronous callback for success case.\r
1159 //\r
1160 if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {\r
3b1d8241 1161 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1162 RemoveEntryList (&EraseBlockEnd->Link);\r
3b1d8241 1163 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1164 if (EraseBlockEnd->Event != NULL) {\r
1165 gBS->CloseEvent (EraseBlockEnd->Event);\r
1166 }\r
1167 FreePool (EraseBlockEnd);\r
1168 }\r
1169 } else {\r
1170 //\r
1171 // For synchronous operation, free request whatever the execution result is.\r
1172 //\r
1173 if (EraseBlockEnd != NULL) {\r
3b1d8241 1174 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1175 RemoveEntryList (&EraseBlockEnd->Link);\r
3b1d8241 1176 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1177 FreePool (EraseBlockEnd);\r
1178 }\r
1179 }\r
1180\r
1181 return Status;\r
1182}\r
1183\r
1184/**\r
1185 Erase specified blocks through sync or async I/O request.\r
1186\r
1187 @param[in] Device A pointer to the SD_DEVICE instance.\r
1188 @param[in] Token A pointer to the token associated with the transaction.\r
1189 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
1190 This parameter is only meaningful in async I/O request.\r
1191\r
1192 @retval EFI_SUCCESS The request is executed successfully.\r
1193 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
1194 @retval Others The request could not be executed successfully.\r
1195\r
1196**/\r
1197EFI_STATUS\r
1198SdEraseBlock (\r
1199 IN SD_DEVICE *Device,\r
1200 IN EFI_BLOCK_IO2_TOKEN *Token,\r
1201 IN BOOLEAN IsEnd\r
1202 )\r
1203{\r
1204 EFI_STATUS Status;\r
1205 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1206 SD_REQUEST *EraseBlock;\r
1207 EFI_TPL OldTpl;\r
1208\r
1209 EraseBlock = NULL;\r
1210 PassThru = Device->Private->PassThru;\r
1211\r
1212 EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));\r
1213 if (EraseBlock == NULL) {\r
1214 Status = EFI_OUT_OF_RESOURCES;\r
1215 goto Error;\r
1216 }\r
1217\r
1218 EraseBlock->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 1219 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136
FT
1220 InsertTailList (&Device->Queue, &EraseBlock->Link);\r
1221 gBS->RestoreTPL (OldTpl);\r
1222 EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;\r
1223 EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;\r
1224 EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
1225\r
1226 EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;\r
1227 EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
1228 EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
1229\r
1230 EraseBlock->IsEnd = IsEnd;\r
1231 EraseBlock->Token = Token;\r
1232\r
1233 if ((Token != NULL) && (Token->Event != NULL)) {\r
1234 Status = gBS->CreateEvent (\r
1235 EVT_NOTIFY_SIGNAL,\r
3b1d8241 1236 TPL_NOTIFY,\r
275d5136
FT
1237 AsyncIoCallback,\r
1238 EraseBlock,\r
1239 &EraseBlock->Event\r
1240 );\r
1241 if (EFI_ERROR (Status)) {\r
1242 goto Error;\r
1243 }\r
1244 } else {\r
1245 EraseBlock->Event = NULL;\r
1246 }\r
1247\r
1248 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);\r
1249\r
1250Error:\r
1251 if ((Token != NULL) && (Token->Event != NULL)) {\r
1252 //\r
1253 // For asynchronous operation, only free request and event in error case.\r
1254 // The request and event will be freed in asynchronous callback for success case.\r
1255 //\r
1256 if (EFI_ERROR (Status) && (EraseBlock != NULL)) {\r
3b1d8241 1257 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1258 RemoveEntryList (&EraseBlock->Link);\r
3b1d8241 1259 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1260 if (EraseBlock->Event != NULL) {\r
1261 gBS->CloseEvent (EraseBlock->Event);\r
1262 }\r
1263 FreePool (EraseBlock);\r
1264 }\r
1265 } else {\r
1266 //\r
1267 // For synchronous operation, free request whatever the execution result is.\r
1268 //\r
1269 if (EraseBlock != NULL) {\r
3b1d8241 1270 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1271 RemoveEntryList (&EraseBlock->Link);\r
3b1d8241 1272 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1273 FreePool (EraseBlock);\r
1274 }\r
1275 }\r
1276\r
1277 return Status;\r
1278}\r
1279\r
1280/**\r
1281 Erase a specified number of device blocks.\r
1282\r
1283 @param[in] This Indicates a pointer to the calling context.\r
1284 @param[in] MediaId The media ID that the erase request is for.\r
1285 @param[in] Lba The starting logical block address to be\r
1286 erased. The caller is responsible for erasing\r
1287 only legitimate locations.\r
1288 @param[in, out] Token A pointer to the token associated with the\r
1289 transaction.\r
1290 @param[in] Size The size in bytes to be erased. This must be\r
1291 a multiple of the physical block size of the\r
1292 device.\r
1293\r
1294 @retval EFI_SUCCESS The erase request was queued if Event is not\r
1295 NULL. The data was erased correctly to the\r
1296 device if the Event is NULL.to the device.\r
1297 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write\r
1298 protection.\r
1299 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
1300 to perform the erase operation.\r
1301 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not\r
1302 valid.\r
1303 @retval EFI_NO_MEDIA There is no media in the device.\r
1304 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1305\r
1306**/\r
1307EFI_STATUS\r
1308EFIAPI\r
1309SdEraseBlocks (\r
1310 IN EFI_ERASE_BLOCK_PROTOCOL *This,\r
1311 IN UINT32 MediaId,\r
1312 IN EFI_LBA Lba,\r
1313 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,\r
1314 IN UINTN Size\r
1315 )\r
1316{\r
1317 EFI_STATUS Status;\r
1318 EFI_BLOCK_IO_MEDIA *Media;\r
1319 UINTN BlockSize;\r
1320 UINTN BlockNum;\r
1321 EFI_LBA LastLba;\r
1322 SD_DEVICE *Device;\r
1323\r
1324 Status = EFI_SUCCESS;\r
1325 Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);\r
1326 Media = &Device->BlockMedia;\r
1327\r
1328 if (MediaId != Media->MediaId) {\r
1329 return EFI_MEDIA_CHANGED;\r
1330 }\r
1331\r
1332 if (Media->ReadOnly) {\r
1333 return EFI_WRITE_PROTECTED;\r
1334 }\r
1335\r
1336 //\r
1337 // Check parameters.\r
1338 //\r
1339 BlockSize = Media->BlockSize;\r
1340 if ((Size % BlockSize) != 0) {\r
1341 return EFI_INVALID_PARAMETER;\r
1342 }\r
1343\r
1344 BlockNum = Size / BlockSize;\r
1345 if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
1346 return EFI_INVALID_PARAMETER;\r
1347 }\r
1348\r
1349 if ((Token != NULL) && (Token->Event != NULL)) {\r
1350 Token->TransactionStatus = EFI_SUCCESS;\r
1351 }\r
1352\r
1353 LastLba = Lba + BlockNum - 1;\r
1354\r
1355 Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
1356 if (EFI_ERROR (Status)) {\r
1357 return Status;\r
1358 }\r
1359\r
1360 Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
1361 if (EFI_ERROR (Status)) {\r
1362 return Status;\r
1363 }\r
1364\r
1365 Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);\r
1366 if (EFI_ERROR (Status)) {\r
1367 return Status;\r
1368 }\r
1369\r
695d90b9
GJ
1370 DEBUG ((\r
1371 DEBUG_INFO,\r
1372 "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",\r
1373 Lba,\r
1374 BlockNum,\r
1375 (Token != NULL) ? Token->Event : NULL,\r
1376 Status\r
1377 ));\r
275d5136
FT
1378\r
1379 return Status;\r
1380}\r
48555339 1381\r