]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
Merge branch 'master' of https://github.com/tianocore/edk2
[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
3b1d8241 343 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339
FT
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
3b1d8241 385 TPL_NOTIFY,\r
48555339
FT
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
3b1d8241 406 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 407 RemoveEntryList (&RwSingleBlkReq->Link);\r
3b1d8241 408 gBS->RestoreTPL (OldTpl);\r
48555339
FT
409 if (RwSingleBlkReq->Event != NULL) {\r
410 gBS->CloseEvent (RwSingleBlkReq->Event);\r
411 }\r
412 FreePool (RwSingleBlkReq);\r
413 }\r
414 } else {\r
415 //\r
416 // For synchronous operation, free request whatever the execution result is.\r
417 //\r
418 if (RwSingleBlkReq != NULL) {\r
3b1d8241 419 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 420 RemoveEntryList (&RwSingleBlkReq->Link);\r
3b1d8241 421 gBS->RestoreTPL (OldTpl);\r
48555339
FT
422 FreePool (RwSingleBlkReq);\r
423 }\r
424 }\r
425\r
426 return Status;\r
427}\r
428\r
429/**\r
430 Read/write multiple blocks through sync or async I/O request.\r
431\r
432 @param[in] Device A pointer to the SD_DEVICE instance.\r
433 @param[in] Lba The starting logical block address to be read/written.\r
434 The caller is responsible for reading/writing to only\r
435 legitimate locations.\r
436 @param[in] Buffer A pointer to the destination/source buffer for the data.\r
437 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
438 @param[in] IsRead Indicates it is a read or write operation.\r
439 @param[in] Token A pointer to the token associated with the transaction.\r
440 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
441 This parameter is only meaningful in async I/O request.\r
442\r
443 @retval EFI_SUCCESS The request is executed successfully.\r
444 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
445 @retval Others The request could not be executed successfully.\r
446\r
447**/\r
448EFI_STATUS\r
449SdRwMultiBlocks (\r
450 IN SD_DEVICE *Device,\r
451 IN EFI_LBA Lba,\r
452 IN VOID *Buffer,\r
453 IN UINTN BufferSize,\r
454 IN BOOLEAN IsRead,\r
455 IN EFI_BLOCK_IO2_TOKEN *Token,\r
456 IN BOOLEAN IsEnd\r
457 )\r
458{\r
459 EFI_STATUS Status;\r
460 SD_REQUEST *RwMultiBlkReq;\r
461 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
462 EFI_TPL OldTpl;\r
463\r
464 RwMultiBlkReq = NULL;\r
465\r
466 PassThru = Device->Private->PassThru;\r
467\r
468 RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
469 if (RwMultiBlkReq == NULL) {\r
470 Status = EFI_OUT_OF_RESOURCES;\r
471 goto Error;\r
472 }\r
473\r
474 RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 475 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339
FT
476 InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);\r
477 gBS->RestoreTPL (OldTpl);\r
478 RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;\r
479 RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;\r
480 //\r
481 // Calculate timeout value through the below formula.\r
482 // Timeout = (transfer size) / (2MB/s).\r
483 // Taking 2MB/s as divisor as it's the lowest transfer speed\r
484 // above class 2.\r
485 // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
486 //\r
487 RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
488\r
489 if (IsRead) {\r
490 RwMultiBlkReq->Packet.InDataBuffer = Buffer;\r
491 RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
492\r
493 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;\r
494 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
495 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
496 } else {\r
497 RwMultiBlkReq->Packet.OutDataBuffer = Buffer;\r
498 RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
499\r
500 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;\r
501 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
502 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
503 }\r
504\r
505 if (Device->SectorAddressing) {\r
506 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
507 } else {\r
508 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
509 }\r
510\r
511 RwMultiBlkReq->IsEnd = IsEnd;\r
512 RwMultiBlkReq->Token = Token;\r
513\r
514 if ((Token != NULL) && (Token->Event != NULL)) {\r
515 Status = gBS->CreateEvent (\r
516 EVT_NOTIFY_SIGNAL,\r
3b1d8241 517 TPL_NOTIFY,\r
48555339
FT
518 AsyncIoCallback,\r
519 RwMultiBlkReq,\r
520 &RwMultiBlkReq->Event\r
521 );\r
522 if (EFI_ERROR (Status)) {\r
523 goto Error;\r
524 }\r
525 } else {\r
526 RwMultiBlkReq->Event = NULL;\r
527 }\r
528\r
529 Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);\r
530\r
531Error:\r
532 if ((Token != NULL) && (Token->Event != NULL)) {\r
533 //\r
534 // For asynchronous operation, only free request and event in error case.\r
535 // The request and event will be freed in asynchronous callback for success case.\r
536 //\r
537 if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
3b1d8241 538 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 539 RemoveEntryList (&RwMultiBlkReq->Link);\r
3b1d8241 540 gBS->RestoreTPL (OldTpl);\r
48555339
FT
541 if (RwMultiBlkReq->Event != NULL) {\r
542 gBS->CloseEvent (RwMultiBlkReq->Event);\r
543 }\r
544 FreePool (RwMultiBlkReq);\r
545 }\r
546 } else {\r
547 //\r
548 // For synchronous operation, free request whatever the execution result is.\r
549 //\r
550 if (RwMultiBlkReq != NULL) {\r
3b1d8241 551 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339 552 RemoveEntryList (&RwMultiBlkReq->Link);\r
3b1d8241 553 gBS->RestoreTPL (OldTpl);\r
48555339
FT
554 FreePool (RwMultiBlkReq);\r
555 }\r
556 }\r
557\r
558 return Status;\r
559}\r
560\r
561/**\r
562 This function transfers data from/to the sd memory card device.\r
563\r
564 @param[in] Device A pointer to the SD_DEVICE instance.\r
565 @param[in] MediaId The media ID that the read/write request is for.\r
566 @param[in] Lba The starting logical block address to be read/written.\r
567 The caller is responsible for reading/writing to only\r
568 legitimate locations.\r
569 @param[in, out] Buffer A pointer to the destination/source buffer for the data.\r
570 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
571 @param[in] IsRead Indicates it is a read or write operation.\r
572 @param[in, out] Token A pointer to the token associated with the transaction.\r
573\r
574 @retval EFI_SUCCESS The data was read/written correctly to the device.\r
575 @retval EFI_WRITE_PROTECTED The device can not be read/written to.\r
576 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.\r
577 @retval EFI_NO_MEDIA There is no media in the device.\r
578 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
579 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
580 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
581 or the buffer is not on proper alignment.\r
582\r
583**/\r
584EFI_STATUS\r
585SdReadWrite (\r
586 IN SD_DEVICE *Device,\r
587 IN UINT32 MediaId,\r
588 IN EFI_LBA Lba,\r
589 IN OUT VOID *Buffer,\r
590 IN UINTN BufferSize,\r
591 IN BOOLEAN IsRead,\r
592 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
593 )\r
594{\r
595 EFI_STATUS Status;\r
596 EFI_BLOCK_IO_MEDIA *Media;\r
597 UINTN BlockSize;\r
598 UINTN BlockNum;\r
599 UINTN IoAlign;\r
600 UINTN Remaining;\r
601 UINT32 MaxBlock;\r
602 BOOLEAN LastRw;\r
603\r
604 Status = EFI_SUCCESS;\r
605 Media = &Device->BlockMedia;\r
606 LastRw = FALSE;\r
607\r
608 if (MediaId != Media->MediaId) {\r
609 return EFI_MEDIA_CHANGED;\r
610 }\r
611\r
612 if (!IsRead && Media->ReadOnly) {\r
613 return EFI_WRITE_PROTECTED;\r
614 }\r
615\r
616 //\r
617 // Check parameters.\r
618 //\r
619 if (Buffer == NULL) {\r
620 return EFI_INVALID_PARAMETER;\r
621 }\r
622\r
623 if (BufferSize == 0) {\r
624 if ((Token != NULL) && (Token->Event != NULL)) {\r
625 Token->TransactionStatus = EFI_SUCCESS;\r
626 gBS->SignalEvent (Token->Event);\r
627 }\r
628 return EFI_SUCCESS;\r
629 }\r
630\r
631 BlockSize = Media->BlockSize;\r
632 if ((BufferSize % BlockSize) != 0) {\r
633 return EFI_BAD_BUFFER_SIZE;\r
634 }\r
635\r
636 BlockNum = BufferSize / BlockSize;\r
637 if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
638 return EFI_INVALID_PARAMETER;\r
639 }\r
640\r
641 IoAlign = Media->IoAlign;\r
642 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
643 return EFI_INVALID_PARAMETER;\r
644 }\r
645\r
646 if ((Token != NULL) && (Token->Event != NULL)) {\r
647 Token->TransactionStatus = EFI_SUCCESS;\r
648 }\r
649\r
650 //\r
651 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
652 //\r
653 Remaining = BlockNum;\r
654 MaxBlock = 0xFFFF;\r
655\r
656 while (Remaining > 0) {\r
657 if (Remaining <= MaxBlock) {\r
658 BlockNum = Remaining;\r
659 LastRw = TRUE;\r
660 } else {\r
661 BlockNum = MaxBlock;\r
662 }\r
663\r
664 BufferSize = BlockNum * BlockSize;\r
665 if (BlockNum == 1) {\r
666 Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
667 } else {\r
668 Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
669 }\r
670 if (EFI_ERROR (Status)) {\r
671 return Status;\r
672 }\r
673 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
674\r
675 Lba += BlockNum;\r
676 Buffer = (UINT8*)Buffer + BufferSize;\r
677 Remaining -= BlockNum;\r
678 }\r
679\r
680 return Status;\r
681}\r
682\r
683/**\r
684 Reset the Block Device.\r
685\r
686 @param This Indicates a pointer to the calling context.\r
687 @param ExtendedVerification Driver may perform diagnostics on reset.\r
688\r
689 @retval EFI_SUCCESS The device was reset.\r
690 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
691 not be reset.\r
692\r
693**/\r
694EFI_STATUS\r
695EFIAPI\r
696SdReset (\r
697 IN EFI_BLOCK_IO_PROTOCOL *This,\r
698 IN BOOLEAN ExtendedVerification\r
699 )\r
700{\r
701 EFI_STATUS Status;\r
702 SD_DEVICE *Device;\r
703 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
704\r
705 Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
706\r
707 PassThru = Device->Private->PassThru;\r
708 Status = PassThru->ResetDevice (PassThru, Device->Slot);\r
709 if (EFI_ERROR (Status)) {\r
710 Status = EFI_DEVICE_ERROR;\r
711 }\r
712\r
713 return Status;\r
714}\r
715\r
716/**\r
717 Read BufferSize bytes from Lba into Buffer.\r
718\r
719 @param This Indicates a pointer to the calling context.\r
720 @param MediaId Id of the media, changes every time the media is replaced.\r
721 @param Lba The starting Logical Block Address to read from\r
722 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
723 @param Buffer A pointer to the destination buffer for the data. The caller is\r
724 responsible for either having implicit or explicit ownership of the buffer.\r
725\r
726 @retval EFI_SUCCESS The data was read correctly from the device.\r
727 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
728 @retval EFI_NO_MEDIA There is no media in the device.\r
729 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
730 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
731 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
732 or the buffer is not on proper alignment.\r
733\r
734**/\r
735EFI_STATUS\r
736EFIAPI\r
737SdReadBlocks (\r
738 IN EFI_BLOCK_IO_PROTOCOL *This,\r
739 IN UINT32 MediaId,\r
740 IN EFI_LBA Lba,\r
741 IN UINTN BufferSize,\r
742 OUT VOID *Buffer\r
743 )\r
744{\r
745 EFI_STATUS Status;\r
746 SD_DEVICE *Device;\r
747\r
748 Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
749\r
750 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);\r
751 return Status;\r
752}\r
753\r
754/**\r
755 Write BufferSize bytes from Lba into Buffer.\r
756\r
757 @param This Indicates a pointer to the calling context.\r
758 @param MediaId The media ID that the write request is for.\r
759 @param Lba The starting logical block address to be written. The caller is\r
760 responsible for writing to only legitimate locations.\r
761 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
762 @param Buffer A pointer to the source buffer for the data.\r
763\r
764 @retval EFI_SUCCESS The data was written correctly to the device.\r
765 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
766 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
767 @retval EFI_NO_MEDIA There is no media in the device.\r
768 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
769 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
770 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
771 or the buffer is not on proper alignment.\r
772\r
773**/\r
774EFI_STATUS\r
775EFIAPI\r
776SdWriteBlocks (\r
777 IN EFI_BLOCK_IO_PROTOCOL *This,\r
778 IN UINT32 MediaId,\r
779 IN EFI_LBA Lba,\r
780 IN UINTN BufferSize,\r
781 IN VOID *Buffer\r
782 )\r
783{\r
784 EFI_STATUS Status;\r
785 SD_DEVICE *Device;\r
786\r
787 Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
788\r
789 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);\r
790 return Status;\r
791}\r
792\r
793/**\r
794 Flush the Block Device.\r
795\r
796 @param This Indicates a pointer to the calling context.\r
797\r
798 @retval EFI_SUCCESS All outstanding data was written to the device\r
799 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
800 @retval EFI_NO_MEDIA There is no media in the device.\r
801\r
802**/\r
803EFI_STATUS\r
804EFIAPI\r
805SdFlushBlocks (\r
806 IN EFI_BLOCK_IO_PROTOCOL *This\r
807 )\r
808{\r
809 //\r
810 // return directly\r
811 //\r
812 return EFI_SUCCESS;\r
813}\r
814\r
815/**\r
816 Reset the Block Device.\r
817\r
818 @param[in] This Indicates a pointer to the calling context.\r
819 @param[in] ExtendedVerification Driver may perform diagnostics on reset.\r
820\r
821 @retval EFI_SUCCESS The device was reset.\r
822 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
823 not be reset.\r
824\r
825**/\r
826EFI_STATUS\r
827EFIAPI\r
828SdResetEx (\r
829 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
830 IN BOOLEAN ExtendedVerification\r
831 )\r
832{\r
833 SD_DEVICE *Device;\r
834 LIST_ENTRY *Link;\r
835 LIST_ENTRY *NextLink;\r
836 SD_REQUEST *Request;\r
837 EFI_TPL OldTpl;\r
838\r
839 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
840\r
3b1d8241 841 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339
FT
842 for (Link = GetFirstNode (&Device->Queue);\r
843 !IsNull (&Device->Queue, Link);\r
844 Link = NextLink) {\r
845 NextLink = GetNextNode (&Device->Queue, Link);\r
846 RemoveEntryList (Link);\r
847\r
848 Request = SD_REQUEST_FROM_LINK (Link);\r
849\r
850 gBS->CloseEvent (Request->Event);\r
851 Request->Token->TransactionStatus = EFI_ABORTED;\r
852\r
853 if (Request->IsEnd) {\r
854 gBS->SignalEvent (Request->Token->Event);\r
855 }\r
856\r
857 FreePool (Request);\r
858 }\r
859 gBS->RestoreTPL (OldTpl);\r
860\r
861 return EFI_SUCCESS;\r
862}\r
863\r
864/**\r
865 Read BufferSize bytes from Lba into Buffer.\r
866\r
867 @param[in] This Indicates a pointer to the calling context.\r
868 @param[in] MediaId Id of the media, changes every time the media is replaced.\r
869 @param[in] Lba The starting Logical Block Address to read from.\r
870 @param[in, out] Token A pointer to the token associated with the transaction.\r
871 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
872 @param[out] Buffer A pointer to the destination buffer for the data. The caller is\r
873 responsible for either having implicit or explicit ownership of the buffer.\r
874\r
875 @retval EFI_SUCCESS The read request was queued if Event is not NULL.\r
876 The data was read correctly from the device if\r
877 the Event is NULL.\r
878 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
879 the read.\r
880 @retval EFI_NO_MEDIA There is no media in the device.\r
881 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
882 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
883 intrinsic block size of the device.\r
884 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
885 or the buffer is not on proper alignment.\r
886 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
887 of resources.\r
888\r
889**/\r
890EFI_STATUS\r
891EFIAPI\r
892SdReadBlocksEx (\r
893 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
894 IN UINT32 MediaId,\r
895 IN EFI_LBA Lba,\r
896 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
897 IN UINTN BufferSize,\r
898 OUT VOID *Buffer\r
899 )\r
900{\r
901 EFI_STATUS Status;\r
902 SD_DEVICE *Device;\r
903\r
904 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
905\r
906 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);\r
907 return Status;\r
908}\r
909\r
910/**\r
911 Write BufferSize bytes from Lba into Buffer.\r
912\r
913 @param[in] This Indicates a pointer to the calling context.\r
914 @param[in] MediaId The media ID that the write request is for.\r
915 @param[in] Lba The starting logical block address to be written. The\r
916 caller is responsible for writing to only legitimate\r
917 locations.\r
918 @param[in, out] Token A pointer to the token associated with the transaction.\r
919 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
920 @param[in] Buffer A pointer to the source buffer for the data.\r
921\r
922 @retval EFI_SUCCESS The data was written correctly to the device.\r
923 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
924 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
925 @retval EFI_NO_MEDIA There is no media in the device.\r
926 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
927 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
928 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
929 or the buffer is not on proper alignment.\r
930\r
931**/\r
932EFI_STATUS\r
933EFIAPI\r
934SdWriteBlocksEx (\r
935 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
936 IN UINT32 MediaId,\r
937 IN EFI_LBA Lba,\r
938 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
939 IN UINTN BufferSize,\r
940 IN VOID *Buffer\r
941 )\r
942{\r
943 EFI_STATUS Status;\r
944 SD_DEVICE *Device;\r
945\r
946 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
947\r
948 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);\r
949 return Status;\r
950}\r
951\r
952/**\r
953 Flush the Block Device.\r
954\r
955 @param[in] This Indicates a pointer to the calling context.\r
956 @param[in, out] Token A pointer to the token associated with the transaction.\r
957\r
958 @retval EFI_SUCCESS All outstanding data was written to the device\r
959 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
960 @retval EFI_NO_MEDIA There is no media in the device.\r
961\r
962**/\r
963EFI_STATUS\r
964EFIAPI\r
965SdFlushBlocksEx (\r
966 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
967 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
968 )\r
969{\r
970 //\r
971 // Signal event and return directly.\r
972 //\r
973 if (Token != NULL && Token->Event != NULL) {\r
974 Token->TransactionStatus = EFI_SUCCESS;\r
975 gBS->SignalEvent (Token->Event);\r
976 }\r
977\r
978 return EFI_SUCCESS;\r
979}\r
980\r
275d5136
FT
981/**\r
982 Set the erase start address through sync or async I/O request.\r
983\r
984 @param[in] Device A pointer to the SD_DEVICE instance.\r
985 @param[in] StartLba The starting logical block address to be erased.\r
986 @param[in] Token A pointer to the token associated with the transaction.\r
987 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
988 This parameter is only meaningful in async I/O request.\r
989\r
990 @retval EFI_SUCCESS The request is executed successfully.\r
991 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
992 @retval Others The request could not be executed successfully.\r
993\r
994**/\r
995EFI_STATUS\r
996SdEraseBlockStart (\r
997 IN SD_DEVICE *Device,\r
998 IN EFI_LBA StartLba,\r
999 IN EFI_BLOCK_IO2_TOKEN *Token,\r
1000 IN BOOLEAN IsEnd\r
1001 )\r
1002{\r
1003 EFI_STATUS Status;\r
1004 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1005 SD_REQUEST *EraseBlockStart;\r
1006 EFI_TPL OldTpl;\r
1007\r
1008 EraseBlockStart = NULL;\r
1009 PassThru = Device->Private->PassThru;\r
1010\r
1011 EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));\r
1012 if (EraseBlockStart == NULL) {\r
1013 Status = EFI_OUT_OF_RESOURCES;\r
1014 goto Error;\r
1015 }\r
1016\r
1017 EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 1018 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136
FT
1019 InsertTailList (&Device->Queue, &EraseBlockStart->Link);\r
1020 gBS->RestoreTPL (OldTpl);\r
1021 EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;\r
1022 EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;\r
1023 EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
1024\r
1025 EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;\r
1026 EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
1027 EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
1028\r
1029 if (Device->SectorAddressing) {\r
1030 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;\r
1031 } else {\r
1032 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);\r
1033 }\r
1034\r
1035 EraseBlockStart->IsEnd = IsEnd;\r
1036 EraseBlockStart->Token = Token;\r
1037\r
1038 if ((Token != NULL) && (Token->Event != NULL)) {\r
1039 Status = gBS->CreateEvent (\r
1040 EVT_NOTIFY_SIGNAL,\r
3b1d8241 1041 TPL_NOTIFY,\r
275d5136
FT
1042 AsyncIoCallback,\r
1043 EraseBlockStart,\r
1044 &EraseBlockStart->Event\r
1045 );\r
1046 if (EFI_ERROR (Status)) {\r
1047 goto Error;\r
1048 }\r
1049 } else {\r
1050 EraseBlockStart->Event = NULL;\r
1051 }\r
1052\r
1053 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);\r
1054\r
1055Error:\r
1056 if ((Token != NULL) && (Token->Event != NULL)) {\r
1057 //\r
1058 // For asynchronous operation, only free request and event in error case.\r
1059 // The request and event will be freed in asynchronous callback for success case.\r
1060 //\r
1061 if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {\r
3b1d8241 1062 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1063 RemoveEntryList (&EraseBlockStart->Link);\r
3b1d8241 1064 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1065 if (EraseBlockStart->Event != NULL) {\r
1066 gBS->CloseEvent (EraseBlockStart->Event);\r
1067 }\r
1068 FreePool (EraseBlockStart);\r
1069 }\r
1070 } else {\r
1071 //\r
1072 // For synchronous operation, free request whatever the execution result is.\r
1073 //\r
1074 if (EraseBlockStart != NULL) {\r
3b1d8241 1075 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1076 RemoveEntryList (&EraseBlockStart->Link);\r
3b1d8241 1077 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1078 FreePool (EraseBlockStart);\r
1079 }\r
1080 }\r
1081\r
1082 return Status;\r
1083}\r
1084\r
1085/**\r
1086 Set the erase end address through sync or async I/O request.\r
1087\r
1088 @param[in] Device A pointer to the SD_DEVICE instance.\r
1089 @param[in] EndLba The ending logical block address to be erased.\r
1090 @param[in] Token A pointer to the token associated with the transaction.\r
1091 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
1092 This parameter is only meaningful in async I/O request.\r
1093\r
1094 @retval EFI_SUCCESS The request is executed successfully.\r
1095 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
1096 @retval Others The request could not be executed successfully.\r
1097\r
1098**/\r
1099EFI_STATUS\r
1100SdEraseBlockEnd (\r
1101 IN SD_DEVICE *Device,\r
1102 IN EFI_LBA EndLba,\r
1103 IN EFI_BLOCK_IO2_TOKEN *Token,\r
1104 IN BOOLEAN IsEnd\r
1105 )\r
1106{\r
1107 EFI_STATUS Status;\r
1108 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1109 SD_REQUEST *EraseBlockEnd;\r
1110 EFI_TPL OldTpl;\r
1111\r
1112 EraseBlockEnd = NULL;\r
1113 PassThru = Device->Private->PassThru;\r
1114\r
1115 EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));\r
1116 if (EraseBlockEnd == NULL) {\r
1117 Status = EFI_OUT_OF_RESOURCES;\r
1118 goto Error;\r
1119 }\r
1120\r
1121 EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 1122 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136
FT
1123 InsertTailList (&Device->Queue, &EraseBlockEnd->Link);\r
1124 gBS->RestoreTPL (OldTpl);\r
1125 EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;\r
1126 EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;\r
1127 EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
1128\r
1129 EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;\r
1130 EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
1131 EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
1132\r
1133 if (Device->SectorAddressing) {\r
1134 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;\r
1135 } else {\r
1136 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);\r
1137 }\r
1138\r
1139 EraseBlockEnd->IsEnd = IsEnd;\r
1140 EraseBlockEnd->Token = Token;\r
1141\r
1142 if ((Token != NULL) && (Token->Event != NULL)) {\r
1143 Status = gBS->CreateEvent (\r
1144 EVT_NOTIFY_SIGNAL,\r
3b1d8241 1145 TPL_NOTIFY,\r
275d5136
FT
1146 AsyncIoCallback,\r
1147 EraseBlockEnd,\r
1148 &EraseBlockEnd->Event\r
1149 );\r
1150 if (EFI_ERROR (Status)) {\r
1151 goto Error;\r
1152 }\r
1153 } else {\r
1154 EraseBlockEnd->Event = NULL;\r
1155 }\r
1156\r
1157 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);\r
1158\r
1159Error:\r
1160 if ((Token != NULL) && (Token->Event != NULL)) {\r
1161 //\r
1162 // For asynchronous operation, only free request and event in error case.\r
1163 // The request and event will be freed in asynchronous callback for success case.\r
1164 //\r
1165 if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {\r
3b1d8241 1166 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1167 RemoveEntryList (&EraseBlockEnd->Link);\r
3b1d8241 1168 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1169 if (EraseBlockEnd->Event != NULL) {\r
1170 gBS->CloseEvent (EraseBlockEnd->Event);\r
1171 }\r
1172 FreePool (EraseBlockEnd);\r
1173 }\r
1174 } else {\r
1175 //\r
1176 // For synchronous operation, free request whatever the execution result is.\r
1177 //\r
1178 if (EraseBlockEnd != NULL) {\r
3b1d8241 1179 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1180 RemoveEntryList (&EraseBlockEnd->Link);\r
3b1d8241 1181 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1182 FreePool (EraseBlockEnd);\r
1183 }\r
1184 }\r
1185\r
1186 return Status;\r
1187}\r
1188\r
1189/**\r
1190 Erase specified blocks through sync or async I/O request.\r
1191\r
1192 @param[in] Device A pointer to the SD_DEVICE instance.\r
1193 @param[in] Token A pointer to the token associated with the transaction.\r
1194 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
1195 This parameter is only meaningful in async I/O request.\r
1196\r
1197 @retval EFI_SUCCESS The request is executed successfully.\r
1198 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
1199 @retval Others The request could not be executed successfully.\r
1200\r
1201**/\r
1202EFI_STATUS\r
1203SdEraseBlock (\r
1204 IN SD_DEVICE *Device,\r
1205 IN EFI_BLOCK_IO2_TOKEN *Token,\r
1206 IN BOOLEAN IsEnd\r
1207 )\r
1208{\r
1209 EFI_STATUS Status;\r
1210 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1211 SD_REQUEST *EraseBlock;\r
1212 EFI_TPL OldTpl;\r
1213\r
1214 EraseBlock = NULL;\r
1215 PassThru = Device->Private->PassThru;\r
1216\r
1217 EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));\r
1218 if (EraseBlock == NULL) {\r
1219 Status = EFI_OUT_OF_RESOURCES;\r
1220 goto Error;\r
1221 }\r
1222\r
1223 EraseBlock->Signature = SD_REQUEST_SIGNATURE;\r
3b1d8241 1224 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136
FT
1225 InsertTailList (&Device->Queue, &EraseBlock->Link);\r
1226 gBS->RestoreTPL (OldTpl);\r
1227 EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;\r
1228 EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;\r
1229 EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
1230\r
1231 EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;\r
1232 EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
1233 EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
1234\r
1235 EraseBlock->IsEnd = IsEnd;\r
1236 EraseBlock->Token = Token;\r
1237\r
1238 if ((Token != NULL) && (Token->Event != NULL)) {\r
1239 Status = gBS->CreateEvent (\r
1240 EVT_NOTIFY_SIGNAL,\r
3b1d8241 1241 TPL_NOTIFY,\r
275d5136
FT
1242 AsyncIoCallback,\r
1243 EraseBlock,\r
1244 &EraseBlock->Event\r
1245 );\r
1246 if (EFI_ERROR (Status)) {\r
1247 goto Error;\r
1248 }\r
1249 } else {\r
1250 EraseBlock->Event = NULL;\r
1251 }\r
1252\r
1253 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);\r
1254\r
1255Error:\r
1256 if ((Token != NULL) && (Token->Event != NULL)) {\r
1257 //\r
1258 // For asynchronous operation, only free request and event in error case.\r
1259 // The request and event will be freed in asynchronous callback for success case.\r
1260 //\r
1261 if (EFI_ERROR (Status) && (EraseBlock != NULL)) {\r
3b1d8241 1262 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1263 RemoveEntryList (&EraseBlock->Link);\r
3b1d8241 1264 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1265 if (EraseBlock->Event != NULL) {\r
1266 gBS->CloseEvent (EraseBlock->Event);\r
1267 }\r
1268 FreePool (EraseBlock);\r
1269 }\r
1270 } else {\r
1271 //\r
1272 // For synchronous operation, free request whatever the execution result is.\r
1273 //\r
1274 if (EraseBlock != NULL) {\r
3b1d8241 1275 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
275d5136 1276 RemoveEntryList (&EraseBlock->Link);\r
3b1d8241 1277 gBS->RestoreTPL (OldTpl);\r
275d5136
FT
1278 FreePool (EraseBlock);\r
1279 }\r
1280 }\r
1281\r
1282 return Status;\r
1283}\r
1284\r
1285/**\r
1286 Erase a specified number of device blocks.\r
1287\r
1288 @param[in] This Indicates a pointer to the calling context.\r
1289 @param[in] MediaId The media ID that the erase request is for.\r
1290 @param[in] Lba The starting logical block address to be\r
1291 erased. The caller is responsible for erasing\r
1292 only legitimate locations.\r
1293 @param[in, out] Token A pointer to the token associated with the\r
1294 transaction.\r
1295 @param[in] Size The size in bytes to be erased. This must be\r
1296 a multiple of the physical block size of the\r
1297 device.\r
1298\r
1299 @retval EFI_SUCCESS The erase request was queued if Event is not\r
1300 NULL. The data was erased correctly to the\r
1301 device if the Event is NULL.to the device.\r
1302 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write\r
1303 protection.\r
1304 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
1305 to perform the erase operation.\r
1306 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not\r
1307 valid.\r
1308 @retval EFI_NO_MEDIA There is no media in the device.\r
1309 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1310\r
1311**/\r
1312EFI_STATUS\r
1313EFIAPI\r
1314SdEraseBlocks (\r
1315 IN EFI_ERASE_BLOCK_PROTOCOL *This,\r
1316 IN UINT32 MediaId,\r
1317 IN EFI_LBA Lba,\r
1318 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,\r
1319 IN UINTN Size\r
1320 )\r
1321{\r
1322 EFI_STATUS Status;\r
1323 EFI_BLOCK_IO_MEDIA *Media;\r
1324 UINTN BlockSize;\r
1325 UINTN BlockNum;\r
1326 EFI_LBA LastLba;\r
1327 SD_DEVICE *Device;\r
1328\r
1329 Status = EFI_SUCCESS;\r
1330 Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);\r
1331 Media = &Device->BlockMedia;\r
1332\r
1333 if (MediaId != Media->MediaId) {\r
1334 return EFI_MEDIA_CHANGED;\r
1335 }\r
1336\r
1337 if (Media->ReadOnly) {\r
1338 return EFI_WRITE_PROTECTED;\r
1339 }\r
1340\r
1341 //\r
1342 // Check parameters.\r
1343 //\r
1344 BlockSize = Media->BlockSize;\r
1345 if ((Size % BlockSize) != 0) {\r
1346 return EFI_INVALID_PARAMETER;\r
1347 }\r
1348\r
1349 BlockNum = Size / BlockSize;\r
1350 if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
1351 return EFI_INVALID_PARAMETER;\r
1352 }\r
1353\r
1354 if ((Token != NULL) && (Token->Event != NULL)) {\r
1355 Token->TransactionStatus = EFI_SUCCESS;\r
1356 }\r
1357\r
1358 LastLba = Lba + BlockNum - 1;\r
1359\r
1360 Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
1361 if (EFI_ERROR (Status)) {\r
1362 return Status;\r
1363 }\r
1364\r
1365 Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
1366 if (EFI_ERROR (Status)) {\r
1367 return Status;\r
1368 }\r
1369\r
1370 Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);\r
1371 if (EFI_ERROR (Status)) {\r
1372 return Status;\r
1373 }\r
1374\r
1375 DEBUG ((EFI_D_ERROR, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));\r
1376\r
1377 return Status;\r
1378}\r
48555339 1379\r