1 /** @file
2
3 Block I/O protocol for CE-ATA device
4
5 Copyright (c) 2013-2015 Intel Corporation.
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "SDMediaDevice.h"
18
19 /**
20 Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
21
22 @param This The EFI_BLOCK_IO_PROTOCOL instance.
23 @param ExtendedVerification Indicates that the driver may perform a more exhaustive.
24 verification operation of the device during reset.
25 (This parameter is ingored in this driver.)
26
27 @retval EFI_SUCCESS Success
28 **/
29 EFI_STATUS
30 EFIAPI
CEATABlockReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)31 CEATABlockReset (
32 IN EFI_BLOCK_IO_PROTOCOL *This,
33 IN BOOLEAN ExtendedVerification
34 )
35 {
36 EFI_STATUS Status;
37 CARD_DATA *CardData;
38 EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
39
40 CardData = CARD_DATA_FROM_THIS(This);
41 SDHostIo = CardData->SDHostIo;
42
43 if (!ExtendedVerification) {
44 Status = SoftwareReset (CardData);
45 } else {
46 Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
47 if (EFI_ERROR (Status)) {
48 DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));
49 return Status;
50 }
51 Status = MMCSDCardInit (CardData);
52 }
53
54
55 return Status;
56
57 }
58
59 /**
60 Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
61
62 @param This The EFI_BLOCK_IO_PROTOCOL instance.
63 @param MediaId The media id that the write request is for.
64 @param LBA The starting logical block address to read from on the device.
65 The caller is responsible for writing to only legitimate locations.
66 @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
67 intrinsic block size of the device.
68 @param Buffer A pointer to the destination buffer for the data. The caller
69 is responsible for either having implicit or explicit ownership
70 of the buffer.
71
72 @retval EFI_SUCCESS Success
73 @retval EFI_DEVICE_ERROR Hardware Error
74 @retval EFI_INVALID_PARAMETER Parameter is error
75 @retval EFI_NO_MEDIA No media
76 @retval EFI_MEDIA_CHANGED Media Change
77 @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
78 **/
79 EFI_STATUS
80 EFIAPI
CEATABlockReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,OUT VOID * Buffer)81 CEATABlockReadBlocks (
82 IN EFI_BLOCK_IO_PROTOCOL *This,
83 IN UINT32 MediaId,
84 IN EFI_LBA LBA,
85 IN UINTN BufferSize,
86 OUT VOID *Buffer
87 )
88 {
89 EFI_STATUS Status;
90 CARD_DATA *CardData;
91 UINT32 TransferSize;
92 UINT8 *pBuf;
93 UINT32 Index;
94 UINT64 Address;
95 UINT32 Remainder;
96 UINT64 CEATALBA;
97 UINT32 BoundarySize;
98
99 Status = EFI_SUCCESS;
100 CardData = CARD_DATA_FROM_THIS(This);
101 pBuf = Buffer;
102 Index = 0;
103 Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
104 BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
105
106 if (!Buffer) {
107 Status = EFI_INVALID_PARAMETER;
108 DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
109 goto Exit;
110 }
111
112 if (MediaId != CardData->BlockIoMedia.MediaId) {
113 Status = EFI_MEDIA_CHANGED;
114 DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));
115 goto Exit;
116 }
117
118 if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
119 Status = EFI_BAD_BUFFER_SIZE;
120 DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));
121 goto Exit;
122 }
123
124 if (BufferSize == 0) {
125 Status = EFI_SUCCESS;
126 goto Exit;
127 }
128
129 if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
130 Status = EFI_INVALID_PARAMETER;
131 DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
132 goto Exit;
133 }
134
135
136 do {
137 if (BufferSize < BoundarySize) {
138 TransferSize = (UINT32)BufferSize;
139 } else {
140 TransferSize = BoundarySize;
141 }
142
143 Address += Index * TransferSize;
144 CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
145 ASSERT(Remainder == 0);
146
147 Status = ReadDMAExt (
148 CardData,
149 CEATALBA,
150 pBuf,
151 (UINT16)(TransferSize / DATA_UNIT_SIZE)
152 );
153 if (EFI_ERROR (Status)) {
154 DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
155 This->Reset (This, TRUE);
156 goto Exit;
157 }
158 BufferSize -= TransferSize;
159 pBuf += TransferSize;
160 Index ++;
161 } while (BufferSize != 0);
162
163
164 Exit:
165 return Status;
166 }
167
168 /**
169 Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
170
171 @param This The EFI_BLOCK_IO_PROTOCOL instance.
172 @param MediaId The media id that the write request is for.
173 @param LBA The starting logical block address to read from on the device.
174 The caller is responsible for writing to only legitimate locations.
175 @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
176 intrinsic block size of the device.
177 @param Buffer A pointer to the destination buffer for the data. The caller
178 is responsible for either having implicit or explicit ownership
179 of the buffer.
180
181 @retval EFI_SUCCESS Success
182 @retval EFI_DEVICE_ERROR Hardware Error
183 @retval EFI_INVALID_PARAMETER Parameter is error
184 @retval EFI_NO_MEDIA No media
185 @retval EFI_MEDIA_CHANGED Media Change
186 @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
187 **/
188 EFI_STATUS
189 EFIAPI
CEATABlockWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,IN VOID * Buffer)190 CEATABlockWriteBlocks (
191 IN EFI_BLOCK_IO_PROTOCOL *This,
192 IN UINT32 MediaId,
193 IN EFI_LBA LBA,
194 IN UINTN BufferSize,
195 IN VOID *Buffer
196 )
197 {
198 EFI_STATUS Status;
199 CARD_DATA *CardData;
200 UINT32 TransferSize;
201 UINT8 *pBuf;
202 UINT32 Index;
203 UINT64 Address;
204 UINT32 Remainder;
205 UINT64 CEATALBA;
206 UINT32 BoundarySize;
207
208
209 Status = EFI_SUCCESS;
210 CardData = CARD_DATA_FROM_THIS(This);
211 pBuf = Buffer;
212 Index = 0;
213 Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
214 BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
215
216
217 if (!Buffer) {
218 Status = EFI_INVALID_PARAMETER;
219 goto Exit;
220 }
221
222 if (MediaId != CardData->BlockIoMedia.MediaId) {
223 Status = EFI_MEDIA_CHANGED;
224 goto Exit;
225 }
226
227 if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
228 Status = EFI_BAD_BUFFER_SIZE;
229 goto Exit;
230 }
231
232 if (BufferSize == 0) {
233 Status = EFI_SUCCESS;
234 goto Exit;
235 }
236
237 if (CardData->BlockIoMedia.ReadOnly) {
238 Status = EFI_WRITE_PROTECTED;
239 goto Exit;
240 }
241
242 if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
243 Status = EFI_INVALID_PARAMETER;
244 goto Exit;
245 }
246
247 CardData->NeedFlush = TRUE;
248
249 do {
250 if (BufferSize < BoundarySize) {
251 TransferSize = (UINT32)BufferSize;
252 } else {
253 TransferSize = BoundarySize;
254 }
255
256 Address += Index * TransferSize;
257 CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
258 ASSERT(Remainder == 0);
259
260 Status = WriteDMAExt (
261 CardData,
262 CEATALBA,
263 pBuf,
264 (UINT16)(TransferSize / DATA_UNIT_SIZE)
265 );
266 if (EFI_ERROR (Status)) {
267 DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
268 This->Reset (This, TRUE);
269 goto Exit;
270 }
271 BufferSize -= TransferSize;
272 pBuf += TransferSize;
273 Index ++;
274 } while (BufferSize != 0);
275
276
277 Exit:
278 return Status;
279 }
280
281 /**
282 Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
283 (In this driver, this function just returns EFI_SUCCESS.)
284
285 @param This The EFI_BLOCK_IO_PROTOCOL instance.
286
287 @retval EFI_SUCCESS
288 @retval Others
289 **/
290 EFI_STATUS
291 EFIAPI
CEATABlockFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)292 CEATABlockFlushBlocks (
293 IN EFI_BLOCK_IO_PROTOCOL *This
294 )
295 {
296
297 CARD_DATA *CardData;
298
299 CardData = CARD_DATA_FROM_THIS(This);
300
301 if (CardData->NeedFlush) {
302 CardData->NeedFlush = FALSE;
303 FlushCache (CardData);
304 }
305
306 return EFI_SUCCESS;
307 }
308
309
310 /**
311 CEATA card BlockIo init function.
312
313 @param CardData Pointer to CARD_DATA.
314
315 @retval EFI_SUCCESS
316 @retval Others
317 **/
318 EFI_STATUS
CEATABlockIoInit(IN CARD_DATA * CardData)319 CEATABlockIoInit (
320 IN CARD_DATA *CardData
321 )
322 /*++
323
324 Routine Description:
325 CEATA card BlockIo init function
326
327 Arguments:
328 CardData - Pointer to CARD_DATA
329
330 Returns:
331 EFI_SUCCESS - Success
332 --*/
333 {
334 EFI_STATUS Status;
335 UINT64 MaxSize;
336 UINT32 Remainder;
337 //
338 //BlockIO protocol
339 //
340 CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
341 CardData->BlockIo.Media = &(CardData->BlockIoMedia);
342 CardData->BlockIo.Reset = CEATABlockReset;
343 CardData->BlockIo.ReadBlocks = CEATABlockReadBlocks ;
344 CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
345 CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
346
347 CardData->BlockIoMedia.MediaId = 0;
348 CardData->BlockIoMedia.RemovableMedia = FALSE;
349 CardData->BlockIoMedia.MediaPresent = TRUE;
350 CardData->BlockIoMedia.LogicalPartition = FALSE;
351
352 if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
353 CardData->BlockIoMedia.ReadOnly = TRUE;
354 } else {
355 CardData->BlockIoMedia.ReadOnly = FALSE;
356 }
357
358
359 CardData->BlockIoMedia.WriteCaching = FALSE;
360 CardData->BlockIoMedia.IoAlign = 1;
361
362 Status = IndentifyDevice (CardData);
363 if (EFI_ERROR (Status)) {
364 goto Exit;
365 }
366
367 //
368 //Some device does not support this feature
369 //
370
371 if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
372 CardData->BlockIoMedia.ReadOnly = TRUE;
373 }
374
375 CardData->BlockIoMedia.BlockSize = (1 << CardData->IndentifyDeviceData.Sectorsize);
376 ASSERT(CardData->BlockIoMedia.BlockSize >= 12);
377
378
379 MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA);
380 MaxSize = MultU64x32 (MaxSize, 512);
381
382 Remainder = 0;
383 CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
384 ASSERT(Remainder == 0);
385
386 CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);
387
388
389 Exit:
390 return Status;
391
392 }
393
394
395
396