1/** @file
2
3Block I/O protocol for CE-ATA device
4
5Copyright (c) 2013-2015 Intel Corporation.
6
7This program and the accompanying materials
8are licensed and made available under the terms and conditions of the BSD License
9which accompanies this distribution.  The full text of the license may be found at
10http://opensource.org/licenses/bsd-license.php
11
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13WITHOUT 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**/
29EFI_STATUS
30EFIAPI
31CEATABlockReset (
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**/
79EFI_STATUS
80EFIAPI
81CEATABlockReadBlocks (
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
164Exit:
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**/
188EFI_STATUS
189EFIAPI
190CEATABlockWriteBlocks (
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
277Exit:
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**/
290EFI_STATUS
291EFIAPI
292CEATABlockFlushBlocks (
293  IN  EFI_BLOCK_IO_PROTOCOL   *This
294  )
295{
296
297  EFI_STATUS                  Status;
298  CARD_DATA                   *CardData;
299
300  CardData  = CARD_DATA_FROM_THIS(This);
301
302  if (CardData->NeedFlush) {
303    CardData->NeedFlush = FALSE;
304    Status = FlushCache (CardData);
305  }
306
307  return EFI_SUCCESS;
308}
309
310
311/**
312  CEATA card BlockIo init function.
313
314  @param  CardData               Pointer to CARD_DATA.
315
316  @retval EFI_SUCCESS
317  @retval Others
318**/
319EFI_STATUS
320CEATABlockIoInit (
321  IN  CARD_DATA    *CardData
322  )
323/*++
324
325  Routine Description:
326    CEATA card BlockIo init function
327
328  Arguments:
329    CardData  -   Pointer to CARD_DATA
330
331  Returns:
332    EFI_SUCCESS - Success
333--*/
334{
335  EFI_STATUS   Status;
336  UINT64       MaxSize;
337  UINT32       Remainder;
338  //
339  //BlockIO protocol
340  //
341  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
342  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
343  CardData->BlockIo.Reset       = CEATABlockReset;
344  CardData->BlockIo.ReadBlocks  = CEATABlockReadBlocks ;
345  CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
346  CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
347
348  CardData->BlockIoMedia.MediaId          = 0;
349  CardData->BlockIoMedia.RemovableMedia   = FALSE;
350  CardData->BlockIoMedia.MediaPresent     = TRUE;
351  CardData->BlockIoMedia.LogicalPartition = FALSE;
352
353  if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
354    CardData->BlockIoMedia.ReadOnly       = TRUE;
355  } else {
356    CardData->BlockIoMedia.ReadOnly       = FALSE;
357  }
358
359
360  CardData->BlockIoMedia.WriteCaching     = FALSE;
361  CardData->BlockIoMedia.IoAlign          = 1;
362
363  Status = IndentifyDevice (CardData);
364  if (EFI_ERROR (Status)) {
365   goto Exit;
366  }
367
368  //
369  //Some device does not support this feature
370  //
371
372  if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
373    CardData->BlockIoMedia.ReadOnly       = TRUE;
374  }
375
376  CardData->BlockIoMedia.BlockSize        = (1 << CardData->IndentifyDeviceData.Sectorsize);
377  ASSERT(CardData->BlockIoMedia.BlockSize >= 12);
378
379
380  MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA);
381  MaxSize = MultU64x32 (MaxSize, 512);
382
383  Remainder = 0;
384  CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
385  ASSERT(Remainder == 0);
386
387  CardData->BlockIoMedia.LastBlock        = (EFI_LBA)(CardData->BlockNumber - 1);
388
389
390Exit:
391  return Status;
392
393}
394
395
396
397