1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu #include <string.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <platform_def.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <common/debug.h> 14*91f16700Schasinglulu #include <drivers/io/io_block.h> 15*91f16700Schasinglulu #include <drivers/io/io_driver.h> 16*91f16700Schasinglulu #include <drivers/io/io_storage.h> 17*91f16700Schasinglulu #include <lib/utils.h> 18*91f16700Schasinglulu 19*91f16700Schasinglulu typedef struct { 20*91f16700Schasinglulu io_block_dev_spec_t *dev_spec; 21*91f16700Schasinglulu uintptr_t base; 22*91f16700Schasinglulu unsigned long long file_pos; 23*91f16700Schasinglulu unsigned long long size; 24*91f16700Schasinglulu } block_dev_state_t; 25*91f16700Schasinglulu 26*91f16700Schasinglulu #define is_power_of_2(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U)) 27*91f16700Schasinglulu 28*91f16700Schasinglulu io_type_t device_type_block(void); 29*91f16700Schasinglulu 30*91f16700Schasinglulu static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 31*91f16700Schasinglulu io_entity_t *entity); 32*91f16700Schasinglulu static int block_seek(io_entity_t *entity, int mode, signed long long offset); 33*91f16700Schasinglulu static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 34*91f16700Schasinglulu size_t *length_read); 35*91f16700Schasinglulu static int block_write(io_entity_t *entity, const uintptr_t buffer, 36*91f16700Schasinglulu size_t length, size_t *length_written); 37*91f16700Schasinglulu static int block_close(io_entity_t *entity); 38*91f16700Schasinglulu static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 39*91f16700Schasinglulu static int block_dev_close(io_dev_info_t *dev_info); 40*91f16700Schasinglulu 41*91f16700Schasinglulu static const io_dev_connector_t block_dev_connector = { 42*91f16700Schasinglulu .dev_open = block_dev_open 43*91f16700Schasinglulu }; 44*91f16700Schasinglulu 45*91f16700Schasinglulu static const io_dev_funcs_t block_dev_funcs = { 46*91f16700Schasinglulu .type = device_type_block, 47*91f16700Schasinglulu .open = block_open, 48*91f16700Schasinglulu .seek = block_seek, 49*91f16700Schasinglulu .size = NULL, 50*91f16700Schasinglulu .read = block_read, 51*91f16700Schasinglulu .write = block_write, 52*91f16700Schasinglulu .close = block_close, 53*91f16700Schasinglulu .dev_init = NULL, 54*91f16700Schasinglulu .dev_close = block_dev_close, 55*91f16700Schasinglulu }; 56*91f16700Schasinglulu 57*91f16700Schasinglulu static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES]; 58*91f16700Schasinglulu static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES]; 59*91f16700Schasinglulu 60*91f16700Schasinglulu /* Track number of allocated block state */ 61*91f16700Schasinglulu static unsigned int block_dev_count; 62*91f16700Schasinglulu 63*91f16700Schasinglulu io_type_t device_type_block(void) 64*91f16700Schasinglulu { 65*91f16700Schasinglulu return IO_TYPE_BLOCK; 66*91f16700Schasinglulu } 67*91f16700Schasinglulu 68*91f16700Schasinglulu /* Locate a block state in the pool, specified by address */ 69*91f16700Schasinglulu static int find_first_block_state(const io_block_dev_spec_t *dev_spec, 70*91f16700Schasinglulu unsigned int *index_out) 71*91f16700Schasinglulu { 72*91f16700Schasinglulu unsigned int index; 73*91f16700Schasinglulu int result = -ENOENT; 74*91f16700Schasinglulu 75*91f16700Schasinglulu for (index = 0U; index < MAX_IO_BLOCK_DEVICES; ++index) { 76*91f16700Schasinglulu /* dev_spec is used as identifier since it's unique */ 77*91f16700Schasinglulu if (state_pool[index].dev_spec == dev_spec) { 78*91f16700Schasinglulu result = 0; 79*91f16700Schasinglulu *index_out = index; 80*91f16700Schasinglulu break; 81*91f16700Schasinglulu } 82*91f16700Schasinglulu } 83*91f16700Schasinglulu return result; 84*91f16700Schasinglulu } 85*91f16700Schasinglulu 86*91f16700Schasinglulu /* Allocate a device info from the pool and return a pointer to it */ 87*91f16700Schasinglulu static int allocate_dev_info(io_dev_info_t **dev_info) 88*91f16700Schasinglulu { 89*91f16700Schasinglulu int result = -ENOMEM; 90*91f16700Schasinglulu assert(dev_info != NULL); 91*91f16700Schasinglulu 92*91f16700Schasinglulu if (block_dev_count < MAX_IO_BLOCK_DEVICES) { 93*91f16700Schasinglulu unsigned int index = 0; 94*91f16700Schasinglulu result = find_first_block_state(NULL, &index); 95*91f16700Schasinglulu assert(result == 0); 96*91f16700Schasinglulu /* initialize dev_info */ 97*91f16700Schasinglulu dev_info_pool[index].funcs = &block_dev_funcs; 98*91f16700Schasinglulu dev_info_pool[index].info = (uintptr_t)&state_pool[index]; 99*91f16700Schasinglulu *dev_info = &dev_info_pool[index]; 100*91f16700Schasinglulu ++block_dev_count; 101*91f16700Schasinglulu } 102*91f16700Schasinglulu 103*91f16700Schasinglulu return result; 104*91f16700Schasinglulu } 105*91f16700Schasinglulu 106*91f16700Schasinglulu 107*91f16700Schasinglulu /* Release a device info to the pool */ 108*91f16700Schasinglulu static int free_dev_info(io_dev_info_t *dev_info) 109*91f16700Schasinglulu { 110*91f16700Schasinglulu int result; 111*91f16700Schasinglulu unsigned int index = 0; 112*91f16700Schasinglulu block_dev_state_t *state; 113*91f16700Schasinglulu assert(dev_info != NULL); 114*91f16700Schasinglulu 115*91f16700Schasinglulu state = (block_dev_state_t *)dev_info->info; 116*91f16700Schasinglulu result = find_first_block_state(state->dev_spec, &index); 117*91f16700Schasinglulu if (result == 0) { 118*91f16700Schasinglulu /* free if device info is valid */ 119*91f16700Schasinglulu zeromem(state, sizeof(block_dev_state_t)); 120*91f16700Schasinglulu zeromem(dev_info, sizeof(io_dev_info_t)); 121*91f16700Schasinglulu --block_dev_count; 122*91f16700Schasinglulu } 123*91f16700Schasinglulu 124*91f16700Schasinglulu return result; 125*91f16700Schasinglulu } 126*91f16700Schasinglulu 127*91f16700Schasinglulu static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 128*91f16700Schasinglulu io_entity_t *entity) 129*91f16700Schasinglulu { 130*91f16700Schasinglulu block_dev_state_t *cur; 131*91f16700Schasinglulu io_block_spec_t *region; 132*91f16700Schasinglulu 133*91f16700Schasinglulu assert((dev_info->info != (uintptr_t)NULL) && 134*91f16700Schasinglulu (spec != (uintptr_t)NULL) && 135*91f16700Schasinglulu (entity->info == (uintptr_t)NULL)); 136*91f16700Schasinglulu 137*91f16700Schasinglulu region = (io_block_spec_t *)spec; 138*91f16700Schasinglulu cur = (block_dev_state_t *)dev_info->info; 139*91f16700Schasinglulu assert(((region->offset % cur->dev_spec->block_size) == 0) && 140*91f16700Schasinglulu ((region->length % cur->dev_spec->block_size) == 0)); 141*91f16700Schasinglulu 142*91f16700Schasinglulu cur->base = region->offset; 143*91f16700Schasinglulu cur->size = region->length; 144*91f16700Schasinglulu cur->file_pos = 0; 145*91f16700Schasinglulu 146*91f16700Schasinglulu entity->info = (uintptr_t)cur; 147*91f16700Schasinglulu return 0; 148*91f16700Schasinglulu } 149*91f16700Schasinglulu 150*91f16700Schasinglulu /* parameter offset is relative address at here */ 151*91f16700Schasinglulu static int block_seek(io_entity_t *entity, int mode, signed long long offset) 152*91f16700Schasinglulu { 153*91f16700Schasinglulu block_dev_state_t *cur; 154*91f16700Schasinglulu 155*91f16700Schasinglulu assert(entity->info != (uintptr_t)NULL); 156*91f16700Schasinglulu 157*91f16700Schasinglulu cur = (block_dev_state_t *)entity->info; 158*91f16700Schasinglulu assert((offset >= 0) && ((unsigned long long)offset < cur->size)); 159*91f16700Schasinglulu 160*91f16700Schasinglulu switch (mode) { 161*91f16700Schasinglulu case IO_SEEK_SET: 162*91f16700Schasinglulu cur->file_pos = (unsigned long long)offset; 163*91f16700Schasinglulu break; 164*91f16700Schasinglulu case IO_SEEK_CUR: 165*91f16700Schasinglulu cur->file_pos += (unsigned long long)offset; 166*91f16700Schasinglulu break; 167*91f16700Schasinglulu default: 168*91f16700Schasinglulu return -EINVAL; 169*91f16700Schasinglulu } 170*91f16700Schasinglulu assert(cur->file_pos < cur->size); 171*91f16700Schasinglulu return 0; 172*91f16700Schasinglulu } 173*91f16700Schasinglulu 174*91f16700Schasinglulu /* 175*91f16700Schasinglulu * This function allows the caller to read any number of bytes 176*91f16700Schasinglulu * from any position. It hides from the caller that the low level 177*91f16700Schasinglulu * driver only can read aligned blocks of data. For this reason 178*91f16700Schasinglulu * we need to handle the use case where the first byte to be read is not 179*91f16700Schasinglulu * aligned to start of the block, the last byte to be read is also not 180*91f16700Schasinglulu * aligned to the end of a block, and there are zero or more blocks-worth 181*91f16700Schasinglulu * of data in between. 182*91f16700Schasinglulu * 183*91f16700Schasinglulu * In such a case we need to read more bytes than requested (i.e. full 184*91f16700Schasinglulu * blocks) and strip-out the leading bytes (aka skip) and the trailing 185*91f16700Schasinglulu * bytes (aka padding). See diagram below 186*91f16700Schasinglulu * 187*91f16700Schasinglulu * cur->file_pos ------------ 188*91f16700Schasinglulu * | 189*91f16700Schasinglulu * cur->base | 190*91f16700Schasinglulu * | | 191*91f16700Schasinglulu * v v<---- length ----> 192*91f16700Schasinglulu * -------------------------------------------------------------- 193*91f16700Schasinglulu * | | block#1 | | block#n | 194*91f16700Schasinglulu * | block#0 | + | ... | + | 195*91f16700Schasinglulu * | | <- skip -> + | | + <- padding ->| 196*91f16700Schasinglulu * ------------------------+----------------------+-------------- 197*91f16700Schasinglulu * ^ ^ 198*91f16700Schasinglulu * | | 199*91f16700Schasinglulu * v iteration#1 iteration#n v 200*91f16700Schasinglulu * -------------------------------------------------- 201*91f16700Schasinglulu * | | | | 202*91f16700Schasinglulu * |<---- request ---->| ... |<----- request ---->| 203*91f16700Schasinglulu * | | | | 204*91f16700Schasinglulu * -------------------------------------------------- 205*91f16700Schasinglulu * / / | | 206*91f16700Schasinglulu * / / | | 207*91f16700Schasinglulu * / / | | 208*91f16700Schasinglulu * / / | | 209*91f16700Schasinglulu * / / | | 210*91f16700Schasinglulu * / / | | 211*91f16700Schasinglulu * / / | | 212*91f16700Schasinglulu * / / | | 213*91f16700Schasinglulu * / / | | 214*91f16700Schasinglulu * / / | | 215*91f16700Schasinglulu * <---- request ------> <------ request -----> 216*91f16700Schasinglulu * --------------------- ----------------------- 217*91f16700Schasinglulu * | | | | | | 218*91f16700Schasinglulu * |<-skip->|<-nbytes->| -------->|<-nbytes->|<-padding->| 219*91f16700Schasinglulu * | | | | | | | 220*91f16700Schasinglulu * --------------------- | ----------------------- 221*91f16700Schasinglulu * ^ \ \ | | | 222*91f16700Schasinglulu * | \ \ | | | 223*91f16700Schasinglulu * | \ \ | | | 224*91f16700Schasinglulu * buf->offset \ \ buf->offset | | 225*91f16700Schasinglulu * \ \ | | 226*91f16700Schasinglulu * \ \ | | 227*91f16700Schasinglulu * \ \ | | 228*91f16700Schasinglulu * \ \ | | 229*91f16700Schasinglulu * \ \ | | 230*91f16700Schasinglulu * \ \ | | 231*91f16700Schasinglulu * \ \ | | 232*91f16700Schasinglulu * -------------------------------- 233*91f16700Schasinglulu * | | | | 234*91f16700Schasinglulu * buffer-------------->| | ... | | 235*91f16700Schasinglulu * | | | | 236*91f16700Schasinglulu * -------------------------------- 237*91f16700Schasinglulu * <-count#1->| | 238*91f16700Schasinglulu * <---------- count#n --------> 239*91f16700Schasinglulu * <---------- length ----------> 240*91f16700Schasinglulu * 241*91f16700Schasinglulu * Additionally, the IO driver has an underlying buffer that is at least 242*91f16700Schasinglulu * one block-size and may be big enough to allow. 243*91f16700Schasinglulu */ 244*91f16700Schasinglulu static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 245*91f16700Schasinglulu size_t *length_read) 246*91f16700Schasinglulu { 247*91f16700Schasinglulu block_dev_state_t *cur; 248*91f16700Schasinglulu io_block_spec_t *buf; 249*91f16700Schasinglulu io_block_ops_t *ops; 250*91f16700Schasinglulu int lba; 251*91f16700Schasinglulu size_t block_size, left; 252*91f16700Schasinglulu size_t nbytes; /* number of bytes read in one iteration */ 253*91f16700Schasinglulu size_t request; /* number of requested bytes in one iteration */ 254*91f16700Schasinglulu size_t count; /* number of bytes already read */ 255*91f16700Schasinglulu /* 256*91f16700Schasinglulu * number of leading bytes from start of the block 257*91f16700Schasinglulu * to the first byte to be read 258*91f16700Schasinglulu */ 259*91f16700Schasinglulu size_t skip; 260*91f16700Schasinglulu 261*91f16700Schasinglulu /* 262*91f16700Schasinglulu * number of trailing bytes between the last byte 263*91f16700Schasinglulu * to be read and the end of the block 264*91f16700Schasinglulu */ 265*91f16700Schasinglulu size_t padding; 266*91f16700Schasinglulu 267*91f16700Schasinglulu assert(entity->info != (uintptr_t)NULL); 268*91f16700Schasinglulu cur = (block_dev_state_t *)entity->info; 269*91f16700Schasinglulu ops = &(cur->dev_spec->ops); 270*91f16700Schasinglulu buf = &(cur->dev_spec->buffer); 271*91f16700Schasinglulu block_size = cur->dev_spec->block_size; 272*91f16700Schasinglulu assert((length <= cur->size) && 273*91f16700Schasinglulu (length > 0U) && 274*91f16700Schasinglulu (ops->read != NULL)); 275*91f16700Schasinglulu 276*91f16700Schasinglulu /* 277*91f16700Schasinglulu * We don't know the number of bytes that we are going 278*91f16700Schasinglulu * to read in every iteration, because it will depend 279*91f16700Schasinglulu * on the low level driver. 280*91f16700Schasinglulu */ 281*91f16700Schasinglulu count = 0; 282*91f16700Schasinglulu for (left = length; left > 0U; left -= nbytes) { 283*91f16700Schasinglulu /* 284*91f16700Schasinglulu * We must only request operations aligned to the block 285*91f16700Schasinglulu * size. Therefore if file_pos is not block-aligned, 286*91f16700Schasinglulu * we have to request the operation to start at the 287*91f16700Schasinglulu * previous block boundary and skip the leading bytes. And 288*91f16700Schasinglulu * similarly, the number of bytes requested must be a 289*91f16700Schasinglulu * block size multiple 290*91f16700Schasinglulu */ 291*91f16700Schasinglulu skip = cur->file_pos & (block_size - 1U); 292*91f16700Schasinglulu 293*91f16700Schasinglulu /* 294*91f16700Schasinglulu * Calculate the block number containing file_pos 295*91f16700Schasinglulu * - e.g. block 3. 296*91f16700Schasinglulu */ 297*91f16700Schasinglulu lba = (cur->file_pos + cur->base) / block_size; 298*91f16700Schasinglulu 299*91f16700Schasinglulu if ((skip + left) > buf->length) { 300*91f16700Schasinglulu /* 301*91f16700Schasinglulu * The underlying read buffer is too small to 302*91f16700Schasinglulu * read all the required data - limit to just 303*91f16700Schasinglulu * fill the buffer, and then read again. 304*91f16700Schasinglulu */ 305*91f16700Schasinglulu request = buf->length; 306*91f16700Schasinglulu } else { 307*91f16700Schasinglulu /* 308*91f16700Schasinglulu * The underlying read buffer is big enough to 309*91f16700Schasinglulu * read all the required data. Calculate the 310*91f16700Schasinglulu * number of bytes to read to align with the 311*91f16700Schasinglulu * block size. 312*91f16700Schasinglulu */ 313*91f16700Schasinglulu request = skip + left; 314*91f16700Schasinglulu request = (request + (block_size - 1U)) & 315*91f16700Schasinglulu ~(block_size - 1U); 316*91f16700Schasinglulu } 317*91f16700Schasinglulu request = ops->read(lba, buf->offset, request); 318*91f16700Schasinglulu 319*91f16700Schasinglulu if (request <= skip) { 320*91f16700Schasinglulu /* 321*91f16700Schasinglulu * We couldn't read enough bytes to jump over 322*91f16700Schasinglulu * the skip bytes, so we should have to read 323*91f16700Schasinglulu * again the same block, thus generating 324*91f16700Schasinglulu * the same error. 325*91f16700Schasinglulu */ 326*91f16700Schasinglulu return -EIO; 327*91f16700Schasinglulu } 328*91f16700Schasinglulu 329*91f16700Schasinglulu /* 330*91f16700Schasinglulu * Need to remove skip and padding bytes,if any, from 331*91f16700Schasinglulu * the read data when copying to the user buffer. 332*91f16700Schasinglulu */ 333*91f16700Schasinglulu nbytes = request - skip; 334*91f16700Schasinglulu padding = (nbytes > left) ? nbytes - left : 0U; 335*91f16700Schasinglulu nbytes -= padding; 336*91f16700Schasinglulu 337*91f16700Schasinglulu memcpy((void *)(buffer + count), 338*91f16700Schasinglulu (void *)(buf->offset + skip), 339*91f16700Schasinglulu nbytes); 340*91f16700Schasinglulu 341*91f16700Schasinglulu cur->file_pos += nbytes; 342*91f16700Schasinglulu count += nbytes; 343*91f16700Schasinglulu } 344*91f16700Schasinglulu assert(count == length); 345*91f16700Schasinglulu *length_read = count; 346*91f16700Schasinglulu 347*91f16700Schasinglulu return 0; 348*91f16700Schasinglulu } 349*91f16700Schasinglulu 350*91f16700Schasinglulu /* 351*91f16700Schasinglulu * This function allows the caller to write any number of bytes 352*91f16700Schasinglulu * from any position. It hides from the caller that the low level 353*91f16700Schasinglulu * driver only can write aligned blocks of data. 354*91f16700Schasinglulu * See comments for block_read for more details. 355*91f16700Schasinglulu */ 356*91f16700Schasinglulu static int block_write(io_entity_t *entity, const uintptr_t buffer, 357*91f16700Schasinglulu size_t length, size_t *length_written) 358*91f16700Schasinglulu { 359*91f16700Schasinglulu block_dev_state_t *cur; 360*91f16700Schasinglulu io_block_spec_t *buf; 361*91f16700Schasinglulu io_block_ops_t *ops; 362*91f16700Schasinglulu int lba; 363*91f16700Schasinglulu size_t block_size, left; 364*91f16700Schasinglulu size_t nbytes; /* number of bytes read in one iteration */ 365*91f16700Schasinglulu size_t request; /* number of requested bytes in one iteration */ 366*91f16700Schasinglulu size_t count; /* number of bytes already read */ 367*91f16700Schasinglulu /* 368*91f16700Schasinglulu * number of leading bytes from start of the block 369*91f16700Schasinglulu * to the first byte to be read 370*91f16700Schasinglulu */ 371*91f16700Schasinglulu size_t skip; 372*91f16700Schasinglulu 373*91f16700Schasinglulu /* 374*91f16700Schasinglulu * number of trailing bytes between the last byte 375*91f16700Schasinglulu * to be read and the end of the block 376*91f16700Schasinglulu */ 377*91f16700Schasinglulu size_t padding; 378*91f16700Schasinglulu 379*91f16700Schasinglulu assert(entity->info != (uintptr_t)NULL); 380*91f16700Schasinglulu cur = (block_dev_state_t *)entity->info; 381*91f16700Schasinglulu ops = &(cur->dev_spec->ops); 382*91f16700Schasinglulu buf = &(cur->dev_spec->buffer); 383*91f16700Schasinglulu block_size = cur->dev_spec->block_size; 384*91f16700Schasinglulu assert((length <= cur->size) && 385*91f16700Schasinglulu (length > 0U) && 386*91f16700Schasinglulu (ops->read != NULL) && 387*91f16700Schasinglulu (ops->write != NULL)); 388*91f16700Schasinglulu 389*91f16700Schasinglulu /* 390*91f16700Schasinglulu * We don't know the number of bytes that we are going 391*91f16700Schasinglulu * to write in every iteration, because it will depend 392*91f16700Schasinglulu * on the low level driver. 393*91f16700Schasinglulu */ 394*91f16700Schasinglulu count = 0; 395*91f16700Schasinglulu for (left = length; left > 0U; left -= nbytes) { 396*91f16700Schasinglulu /* 397*91f16700Schasinglulu * We must only request operations aligned to the block 398*91f16700Schasinglulu * size. Therefore if file_pos is not block-aligned, 399*91f16700Schasinglulu * we have to request the operation to start at the 400*91f16700Schasinglulu * previous block boundary and skip the leading bytes. And 401*91f16700Schasinglulu * similarly, the number of bytes requested must be a 402*91f16700Schasinglulu * block size multiple 403*91f16700Schasinglulu */ 404*91f16700Schasinglulu skip = cur->file_pos & (block_size - 1U); 405*91f16700Schasinglulu 406*91f16700Schasinglulu /* 407*91f16700Schasinglulu * Calculate the block number containing file_pos 408*91f16700Schasinglulu * - e.g. block 3. 409*91f16700Schasinglulu */ 410*91f16700Schasinglulu lba = (cur->file_pos + cur->base) / block_size; 411*91f16700Schasinglulu 412*91f16700Schasinglulu if ((skip + left) > buf->length) { 413*91f16700Schasinglulu /* 414*91f16700Schasinglulu * The underlying read buffer is too small to 415*91f16700Schasinglulu * read all the required data - limit to just 416*91f16700Schasinglulu * fill the buffer, and then read again. 417*91f16700Schasinglulu */ 418*91f16700Schasinglulu request = buf->length; 419*91f16700Schasinglulu } else { 420*91f16700Schasinglulu /* 421*91f16700Schasinglulu * The underlying read buffer is big enough to 422*91f16700Schasinglulu * read all the required data. Calculate the 423*91f16700Schasinglulu * number of bytes to read to align with the 424*91f16700Schasinglulu * block size. 425*91f16700Schasinglulu */ 426*91f16700Schasinglulu request = skip + left; 427*91f16700Schasinglulu request = (request + (block_size - 1U)) & 428*91f16700Schasinglulu ~(block_size - 1U); 429*91f16700Schasinglulu } 430*91f16700Schasinglulu 431*91f16700Schasinglulu /* 432*91f16700Schasinglulu * The number of bytes that we are going to write 433*91f16700Schasinglulu * from the user buffer will depend of the size 434*91f16700Schasinglulu * of the current request. 435*91f16700Schasinglulu */ 436*91f16700Schasinglulu nbytes = request - skip; 437*91f16700Schasinglulu padding = (nbytes > left) ? nbytes - left : 0U; 438*91f16700Schasinglulu nbytes -= padding; 439*91f16700Schasinglulu 440*91f16700Schasinglulu /* 441*91f16700Schasinglulu * If we have skip or padding bytes then we have to preserve 442*91f16700Schasinglulu * some content and it means that we have to read before 443*91f16700Schasinglulu * writing 444*91f16700Schasinglulu */ 445*91f16700Schasinglulu if ((skip > 0U) || (padding > 0U)) { 446*91f16700Schasinglulu request = ops->read(lba, buf->offset, request); 447*91f16700Schasinglulu /* 448*91f16700Schasinglulu * The read may return size less than 449*91f16700Schasinglulu * requested. Round down to the nearest block 450*91f16700Schasinglulu * boundary 451*91f16700Schasinglulu */ 452*91f16700Schasinglulu request &= ~(block_size - 1U); 453*91f16700Schasinglulu if (request <= skip) { 454*91f16700Schasinglulu /* 455*91f16700Schasinglulu * We couldn't read enough bytes to jump over 456*91f16700Schasinglulu * the skip bytes, so we should have to read 457*91f16700Schasinglulu * again the same block, thus generating 458*91f16700Schasinglulu * the same error. 459*91f16700Schasinglulu */ 460*91f16700Schasinglulu return -EIO; 461*91f16700Schasinglulu } 462*91f16700Schasinglulu nbytes = request - skip; 463*91f16700Schasinglulu padding = (nbytes > left) ? nbytes - left : 0U; 464*91f16700Schasinglulu nbytes -= padding; 465*91f16700Schasinglulu } 466*91f16700Schasinglulu 467*91f16700Schasinglulu memcpy((void *)(buf->offset + skip), 468*91f16700Schasinglulu (void *)(buffer + count), 469*91f16700Schasinglulu nbytes); 470*91f16700Schasinglulu 471*91f16700Schasinglulu request = ops->write(lba, buf->offset, request); 472*91f16700Schasinglulu if (request <= skip) 473*91f16700Schasinglulu return -EIO; 474*91f16700Schasinglulu 475*91f16700Schasinglulu /* 476*91f16700Schasinglulu * And the previous write operation may modify the size 477*91f16700Schasinglulu * of the request, so again, we have to calculate the 478*91f16700Schasinglulu * number of bytes that we consumed from the user 479*91f16700Schasinglulu * buffer 480*91f16700Schasinglulu */ 481*91f16700Schasinglulu nbytes = request - skip; 482*91f16700Schasinglulu padding = (nbytes > left) ? nbytes - left : 0U; 483*91f16700Schasinglulu nbytes -= padding; 484*91f16700Schasinglulu 485*91f16700Schasinglulu cur->file_pos += nbytes; 486*91f16700Schasinglulu count += nbytes; 487*91f16700Schasinglulu } 488*91f16700Schasinglulu assert(count == length); 489*91f16700Schasinglulu *length_written = count; 490*91f16700Schasinglulu 491*91f16700Schasinglulu return 0; 492*91f16700Schasinglulu } 493*91f16700Schasinglulu 494*91f16700Schasinglulu static int block_close(io_entity_t *entity) 495*91f16700Schasinglulu { 496*91f16700Schasinglulu entity->info = (uintptr_t)NULL; 497*91f16700Schasinglulu return 0; 498*91f16700Schasinglulu } 499*91f16700Schasinglulu 500*91f16700Schasinglulu static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) 501*91f16700Schasinglulu { 502*91f16700Schasinglulu block_dev_state_t *cur; 503*91f16700Schasinglulu io_block_spec_t *buffer; 504*91f16700Schasinglulu io_dev_info_t *info; 505*91f16700Schasinglulu size_t block_size; 506*91f16700Schasinglulu int result; 507*91f16700Schasinglulu 508*91f16700Schasinglulu assert(dev_info != NULL); 509*91f16700Schasinglulu result = allocate_dev_info(&info); 510*91f16700Schasinglulu if (result != 0) 511*91f16700Schasinglulu return -ENOENT; 512*91f16700Schasinglulu 513*91f16700Schasinglulu cur = (block_dev_state_t *)info->info; 514*91f16700Schasinglulu /* dev_spec is type of io_block_dev_spec_t. */ 515*91f16700Schasinglulu cur->dev_spec = (io_block_dev_spec_t *)dev_spec; 516*91f16700Schasinglulu buffer = &(cur->dev_spec->buffer); 517*91f16700Schasinglulu block_size = cur->dev_spec->block_size; 518*91f16700Schasinglulu assert((block_size > 0U) && 519*91f16700Schasinglulu (is_power_of_2(block_size) != 0U) && 520*91f16700Schasinglulu ((buffer->offset % block_size) == 0U) && 521*91f16700Schasinglulu ((buffer->length % block_size) == 0U)); 522*91f16700Schasinglulu 523*91f16700Schasinglulu *dev_info = info; /* cast away const */ 524*91f16700Schasinglulu (void)block_size; 525*91f16700Schasinglulu (void)buffer; 526*91f16700Schasinglulu return 0; 527*91f16700Schasinglulu } 528*91f16700Schasinglulu 529*91f16700Schasinglulu static int block_dev_close(io_dev_info_t *dev_info) 530*91f16700Schasinglulu { 531*91f16700Schasinglulu return free_dev_info(dev_info); 532*91f16700Schasinglulu } 533*91f16700Schasinglulu 534*91f16700Schasinglulu /* Exported functions */ 535*91f16700Schasinglulu 536*91f16700Schasinglulu /* Register the Block driver with the IO abstraction */ 537*91f16700Schasinglulu int register_io_dev_block(const io_dev_connector_t **dev_con) 538*91f16700Schasinglulu { 539*91f16700Schasinglulu int result; 540*91f16700Schasinglulu 541*91f16700Schasinglulu assert(dev_con != NULL); 542*91f16700Schasinglulu 543*91f16700Schasinglulu /* 544*91f16700Schasinglulu * Since dev_info isn't really used in io_register_device, always 545*91f16700Schasinglulu * use the same device info at here instead. 546*91f16700Schasinglulu */ 547*91f16700Schasinglulu result = io_register_device(&dev_info_pool[0]); 548*91f16700Schasinglulu if (result == 0) 549*91f16700Schasinglulu *dev_con = &block_dev_connector; 550*91f16700Schasinglulu return result; 551*91f16700Schasinglulu } 552