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   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 **/
319 EFI_STATUS
CEATABlockIoInit(IN CARD_DATA * CardData)320 CEATABlockIoInit (
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 
390 Exit:
391   return Status;
392 
393 }
394 
395 
396 
397