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