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 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 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 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 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 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