mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 21:41:59 -04:00
199 lines
6 KiB
C
199 lines
6 KiB
C
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
|
|
|
|
Copyright (c) 2014-2015 Datalight, Inc.
|
|
All Rights Reserved Worldwide.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; use version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
|
|
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/* Businesses and individuals that for commercial or other reasons cannot
|
|
comply with the terms of the GPLv2 license may obtain a commercial license
|
|
before incorporating Reliance Edge into proprietary software for
|
|
distribution in any form. Visit http://www.datalight.com/reliance-edge for
|
|
more information.
|
|
*/
|
|
/** @file
|
|
@brief Implements block device I/O using logical blocks as the units.
|
|
|
|
The OS block device implementations operate on sectors. The core does I/O
|
|
in terms of logical blocks: this module translates from logical blocks to
|
|
sectors.
|
|
|
|
If bBlockIoRetries is greater than 0 for the current volume, then this
|
|
module will retry block device calls on failure up to the configured number
|
|
of times. This behavior caters to the type of unreliable hardware and
|
|
drivers that are sometimes found in the IoT world, where one operation may
|
|
fail but the next may still succeed.
|
|
*/
|
|
#include <redfs.h>
|
|
#include <redcore.h>
|
|
|
|
|
|
/** @brief Read a range of logical blocks.
|
|
|
|
@param bVolNum The volume whose block device is being read from.
|
|
@param ulBlockStart The first block to read.
|
|
@param ulBlockCount The number of blocks to read.
|
|
@param pBuffer The buffer to populate with the data read.
|
|
|
|
@return A negated ::REDSTATUS code indicating the operation result.
|
|
|
|
@retval 0 Operation was successful.
|
|
@retval -RED_EIO A disk I/O error occurred.
|
|
@retval -RED_EINVAL Invalid parameters.
|
|
*/
|
|
REDSTATUS RedIoRead(
|
|
uint8_t bVolNum,
|
|
uint32_t ulBlockStart,
|
|
uint32_t ulBlockCount,
|
|
void *pBuffer)
|
|
{
|
|
REDSTATUS ret = 0;
|
|
|
|
if( (bVolNum >= REDCONF_VOLUME_COUNT)
|
|
|| (ulBlockStart >= gaRedVolume[bVolNum].ulBlockCount)
|
|
|| ((gaRedVolume[bVolNum].ulBlockCount - ulBlockStart) < ulBlockCount)
|
|
|| (ulBlockCount == 0U)
|
|
|| (pBuffer == NULL))
|
|
{
|
|
REDERROR();
|
|
ret = -RED_EINVAL;
|
|
}
|
|
else
|
|
{
|
|
uint8_t bSectorShift = gaRedVolume[bVolNum].bBlockSectorShift;
|
|
uint64_t ullSectorStart = (uint64_t)ulBlockStart << bSectorShift;
|
|
uint32_t ulSectorCount = ulBlockCount << bSectorShift;
|
|
uint8_t bRetryIdx;
|
|
|
|
REDASSERT(bSectorShift < 32U);
|
|
REDASSERT((ulSectorCount >> bSectorShift) == ulBlockCount);
|
|
|
|
for(bRetryIdx = 0U; bRetryIdx <= gpRedVolConf->bBlockIoRetries; bRetryIdx++)
|
|
{
|
|
ret = RedOsBDevRead(bVolNum, ullSectorStart, ulSectorCount, pBuffer);
|
|
|
|
if(ret == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CRITICAL_ASSERT(ret == 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
#if REDCONF_READ_ONLY == 0
|
|
/** @brief Write a range of logical blocks.
|
|
|
|
@param bVolNum The volume whose block device is being written to.
|
|
@param ulBlockStart The first block to write.
|
|
@param ulBlockCount The number of blocks to write.
|
|
@param pBuffer The buffer containing the data to write.
|
|
|
|
@return A negated ::REDSTATUS code indicating the operation result.
|
|
|
|
@retval 0 Operation was successful.
|
|
@retval -RED_EIO A disk I/O error occurred.
|
|
@retval -RED_EINVAL Invalid parameters.
|
|
*/
|
|
REDSTATUS RedIoWrite(
|
|
uint8_t bVolNum,
|
|
uint32_t ulBlockStart,
|
|
uint32_t ulBlockCount,
|
|
const void *pBuffer)
|
|
{
|
|
REDSTATUS ret = 0;
|
|
|
|
if( (bVolNum >= REDCONF_VOLUME_COUNT)
|
|
|| (ulBlockStart >= gaRedVolume[bVolNum].ulBlockCount)
|
|
|| ((gaRedVolume[bVolNum].ulBlockCount - ulBlockStart) < ulBlockCount)
|
|
|| (ulBlockCount == 0U)
|
|
|| (pBuffer == NULL))
|
|
{
|
|
REDERROR();
|
|
ret = -RED_EINVAL;
|
|
}
|
|
else
|
|
{
|
|
uint8_t bSectorShift = gaRedVolume[bVolNum].bBlockSectorShift;
|
|
uint64_t ullSectorStart = (uint64_t)ulBlockStart << bSectorShift;
|
|
uint32_t ulSectorCount = ulBlockCount << bSectorShift;
|
|
uint8_t bRetryIdx;
|
|
|
|
REDASSERT(bSectorShift < 32U);
|
|
REDASSERT((ulSectorCount >> bSectorShift) == ulBlockCount);
|
|
|
|
for(bRetryIdx = 0U; bRetryIdx <= gpRedVolConf->bBlockIoRetries; bRetryIdx++)
|
|
{
|
|
ret = RedOsBDevWrite(bVolNum, ullSectorStart, ulSectorCount, pBuffer);
|
|
|
|
if(ret == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CRITICAL_ASSERT(ret == 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/** @brief Flush any caches beneath the file system.
|
|
|
|
@param bVolNum The volume number of the volume whose block device is being
|
|
flushed.
|
|
|
|
@return A negated ::REDSTATUS code indicating the operation result.
|
|
|
|
@retval 0 Operation was successful.
|
|
@retval -RED_EINVAL @p bVolNum is an invalid volume number.
|
|
@retval -RED_EIO A disk I/O error occurred.
|
|
*/
|
|
REDSTATUS RedIoFlush(
|
|
uint8_t bVolNum)
|
|
{
|
|
REDSTATUS ret = 0;
|
|
|
|
if(bVolNum >= REDCONF_VOLUME_COUNT)
|
|
{
|
|
REDERROR();
|
|
ret = -RED_EINVAL;
|
|
}
|
|
else
|
|
{
|
|
uint8_t bRetryIdx;
|
|
|
|
for(bRetryIdx = 0U; bRetryIdx <= gpRedVolConf->bBlockIoRetries; bRetryIdx++)
|
|
{
|
|
ret = RedOsBDevFlush(bVolNum);
|
|
|
|
if(ret == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CRITICAL_ASSERT(ret == 0);
|
|
|
|
return ret;
|
|
}
|
|
#endif /* REDCONF_READ_ONLY == 0 */
|
|
|