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