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