git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10980 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
Giovanni Di Sirio 2017-11-10 15:40:32 +00:00
parent 4ba55d0c38
commit 681a0de4c1
2 changed files with 264 additions and 144 deletions

View File

@ -65,14 +65,10 @@
/** /**
* @brief Type of a records scan callback function. * @brief Type of a records scan callback function.
*/ */
typedef void (*foundrec_t)(mfs_data_header_t *dhdrp); typedef void (*mfs_scan_cb_t)(MFSDriver *mfsp, flash_offset_t offset);
/**
* @brief Type of a records scan callback function.
*/
typedef void (*endrec_t)(mfs_data_header_t *dhdrp);
const uint16_t crc16_table[256] = { static const uint16_t crc16_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
@ -122,6 +118,20 @@ uint16_t crc16(uint16_t crc, const uint8_t *data, size_t n) {
return crc; return crc;
} }
static void mfs_state_reset(MFSDriver *mfsp) {
unsigned i;
mfsp->current_bank = MFS_BANK_0;
mfsp->current_counter = 0U;
mfsp->next_offset = 0U;
mfsp->used_space = 0U;
for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
mfsp->descriptors[i].offset = 0U;
mfsp->descriptors[i].size = 0U;
}
}
static flash_offset_t mfs_flash_get_bank_offset(MFSDriver *mfsp, static flash_offset_t mfs_flash_get_bank_offset(MFSDriver *mfsp,
mfs_bank_t bank) { mfs_bank_t bank) {
@ -187,6 +197,54 @@ static mfs_error_t mfs_flash_write(MFSDriver *mfsp,
return MFS_NO_ERROR; return MFS_NO_ERROR;
} }
/**
* @brief Verifies integrity of a record.
*
* @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] dhdrp pointer to the header to be checked
* @param[in] offset flash offset of the header to be checked
* @param[in] limit flash limit offset
* @param[out] sts assessed record state
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures.
*
* @notapi
*/
static mfs_error_t mfs_record_check(MFSDriver *mfsp,
mfs_data_header_t *dhdrp,
flash_offset_t offset,
flash_offset_t limit,
mfs_record_state_t *sts) {
unsigned i;
for (i = 0; i < 3; i++) {
if (dhdrp->hdr32[i] != mfsp->config->erased) {
/* Not erased must verify the header.*/
if ((dhdrp->fields.magic != MFS_HEADER_MAGIC) ||
(dhdrp->fields.id < (uint16_t)1) ||
(dhdrp->fields.id > (uint16_t)MFS_CFG_MAX_RECORDS) ||
(dhdrp->fields.size + sizeof (mfs_data_header_t) > limit - offset)) {
*sts = MFS_RECORD_GARBAGE;
return MFS_NO_ERROR;
}
#if MFS_CFG_STRONG_CHECKING == TRUE
{
/* Checking the CRC while reading the record data.*/
(void)mfsp;
}
#else
(void)mfsp;
#endif
}
}
/* It is fully erased.*/
*sts = MFS_RECORD_ERASED;
return MFS_NO_ERROR;
}
/** /**
* @brief Erases and verifies all sectors belonging to a bank. * @brief Erases and verifies all sectors belonging to a bank.
* *
@ -237,7 +295,7 @@ static mfs_error_t mfs_bank_erase(MFSDriver *mfsp, mfs_bank_t bank) {
* @brief Erases and verifies all sectors belonging to a bank. * @brief Erases and verifies all sectors belonging to a bank.
* *
* @param[in] mfsp pointer to the @p MFSDriver object * @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] bank bank to be erased * @param[in] bank bank to be verified
* @return The operation status. * @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed. * @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_NOT_ERASED if the bank is not erased * @retval MFS_ERR_NOT_ERASED if the bank is not erased
@ -314,80 +372,6 @@ static mfs_error_t mfs_bank_write_header(MFSDriver *mfsp,
bhdr.hdr8); bhdr.hdr8);
} }
/**
* @brief Copies all records from a bank to another.
*
* @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] sbank source bank
* @param[in] dbank destination bank
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures.
*
* @notapi
*/
static mfs_error_t mfs_bank_copy(MFSDriver *mfsp,
mfs_bank_t sbank,
mfs_bank_t dbank) {
(void)mfsp;
(void)sbank;
(void)dbank;
return MFS_NO_ERROR;
}
/**
* @brief Selects a bank as current.
*
* @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] bank bank to be erased
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
*
* @notapi
*/
static mfs_error_t mfs_bank_mount(MFSDriver *mfsp, mfs_bank_t bank) {
(void)mfsp;
(void)bank;
return MFS_NO_ERROR;
}
static mfs_error_t mfs_check_record(MFSDriver *mfsp,
mfs_data_header_t *dhdrp,
flash_offset_t offset,
flash_offset_t limit,
mfs_record_state_t *sts) {
unsigned i;
for (i = 0; i < 3; i++) {
if (dhdrp->hdr32[i] != mfsp->config->erased) {
/* Not erased must verify the header.*/
if ((dhdrp->fields.magic != MFS_HEADER_MAGIC) ||
(dhdrp->fields.id >= (uint16_t)MFS_CFG_MAX_RECORDS) ||
(dhdrp->fields.size + sizeof (mfs_data_header_t) > limit - offset)) {
*sts = MFS_RECORD_GARBAGE;
return MFS_NO_ERROR;
}
#if MFS_CFG_STRONG_CHECKING == TRUE
{
/* Checking the CRC while reading the record data.*/
(void)mfsp;
}
#else
(void)mfsp;
#endif
}
}
/* It is fully erased.*/
*sts = MFS_RECORD_ERASED;
return MFS_NO_ERROR;
}
/** /**
* @brief Scans blocks searching for records. * @brief Scans blocks searching for records.
* @note The block integrity is strongly checked. * @note The block integrity is strongly checked.
@ -405,12 +389,12 @@ static mfs_error_t mfs_check_record(MFSDriver *mfsp,
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures. * failures.
*/ */
static mfs_error_t mfs_scan_records(MFSDriver *mfsp, static mfs_error_t mfs_bank_scan_records(MFSDriver *mfsp,
mfs_bank_t bank, mfs_bank_t bank,
mfs_bank_state_t *statep, mfs_bank_state_t *statep,
uint32_t *cntp, uint32_t *cntp,
foundrec_t foundcb, mfs_scan_cb_t foundcb,
endrec_t endcb) { mfs_scan_cb_t endcb) {
flash_offset_t hdr_offset, start_offset, end_offset; flash_offset_t hdr_offset, start_offset, end_offset;
mfs_record_state_t sts; mfs_record_state_t sts;
uint16_t crc; uint16_t crc;
@ -456,7 +440,7 @@ static mfs_error_t mfs_scan_records(MFSDriver *mfsp,
(void *)&mfsp->buffer.dhdr)); (void *)&mfsp->buffer.dhdr));
/* Checking header/data integrity.*/ /* Checking header/data integrity.*/
RET_ON_ERROR(mfs_check_record(mfsp, &mfsp->buffer.dhdr, RET_ON_ERROR(mfs_record_check(mfsp, &mfsp->buffer.dhdr,
hdr_offset, end_offset, &sts)); hdr_offset, end_offset, &sts));
if (sts == MFS_RECORD_ERASED) { if (sts == MFS_RECORD_ERASED) {
/* Record area fully erased, stopping scan.*/ /* Record area fully erased, stopping scan.*/
@ -465,7 +449,7 @@ static mfs_error_t mfs_scan_records(MFSDriver *mfsp,
else if (sts == MFS_RECORD_OK) { else if (sts == MFS_RECORD_OK) {
/* Record OK.*/ /* Record OK.*/
if (foundcb != NULL) { if (foundcb != NULL) {
foundcb(&mfsp->buffer.dhdr); foundcb(mfsp, hdr_offset);
} }
} }
else if (sts == MFS_RECORD_CRC) { else if (sts == MFS_RECORD_CRC) {
@ -486,7 +470,7 @@ static mfs_error_t mfs_scan_records(MFSDriver *mfsp,
/* Final callback.*/ /* Final callback.*/
if (endcb != NULL) { if (endcb != NULL) {
endcb(&mfsp->buffer.dhdr); endcb(mfsp, hdr_offset);
} }
if (warning) { if (warning) {
@ -514,7 +498,7 @@ static mfs_error_t mfs_scan_records(MFSDriver *mfsp,
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures. * failures.
*/ */
static mfs_error_t mfs_get_bank_state(MFSDriver *mfsp, static mfs_error_t mfs_bank_get_state(MFSDriver *mfsp,
mfs_bank_t bank, mfs_bank_t bank,
mfs_bank_state_t *statep, mfs_bank_state_t *statep,
uint32_t *cntp) { uint32_t *cntp) {
@ -527,10 +511,93 @@ static mfs_error_t mfs_get_bank_state(MFSDriver *mfsp,
return MFS_BANK_OK; return MFS_BANK_OK;
} }
return mfs_scan_records(mfsp, bank, return mfs_bank_scan_records(mfsp, bank, statep, cntp, NULL, NULL);
statep, cntp, }
NULL,
NULL); /**
* @brief Private callback of @p mfs_bank_mount().
*/
static void mfs_bank_mount_found_cb(MFSDriver *mfsp, flash_offset_t offset) {
uint32_t size = mfsp->buffer.dhdr.fields.size;
/* Zero-sized records are erase markers.*/
if (size == 0U) {
mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1].offset = 0U;
mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1].size = 0U;
}
else {
mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1].offset = offset;
mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1].size = size;
}
}
/**
* @brief Private callback of @p mfs_bank_mount().
*/
static void mfs_bank_mount_end_cb(MFSDriver *mfsp, flash_offset_t offset) {
mfsp->next_offset = offset;
}
/**
* @brief Selects a bank as current.
*
* @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] bank bank to be scanned
* @param[out] statep bank state
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures.
*
* @notapi
*/
static mfs_error_t mfs_bank_mount(MFSDriver *mfsp,
mfs_bank_t bank,
mfs_bank_state_t *statep) {
unsigned i;
/* Resetting previous state.*/
mfs_state_reset(mfsp);
RET_ON_ERROR(mfs_bank_scan_records(mfsp, bank, statep,
&mfsp->current_counter,
mfs_bank_mount_found_cb,
mfs_bank_mount_end_cb));
/* Calculating the effective used size.*/
mfsp->current_bank = bank;
for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
if (mfsp->descriptors[i].offset != 0U) {
mfsp->used_space += mfsp->descriptors[i].size + sizeof (mfs_data_header_t);
}
}
return MFS_NO_ERROR;
}
/**
* @brief Copies all records from a bank to another.
*
* @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] sbank source bank
* @param[in] dbank destination bank
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures.
*
* @notapi
*/
static mfs_error_t mfs_bank_copy(MFSDriver *mfsp,
mfs_bank_t sbank,
mfs_bank_t dbank) {
(void)mfsp;
(void)sbank;
(void)dbank;
return MFS_NO_ERROR;
} }
/** /**
@ -547,12 +614,13 @@ static mfs_error_t mfs_get_bank_state(MFSDriver *mfsp,
* @api * @api
*/ */
static mfs_error_t mfs_try_mount(MFSDriver *mfsp) { static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
mfs_bank_state_t sts0, sts1; mfs_bank_state_t sts, sts0, sts1;
uint32_t cnt0 = 0, cnt1 = 0; uint32_t cnt0 = 0, cnt1 = 0;
mfs_error_t err = MFS_NO_ERROR;
/* Assessing the state of the two banks.*/ /* Assessing the state of the two banks.*/
RET_ON_ERROR(mfs_get_bank_state(mfsp, MFS_BANK_0, &sts0, &cnt0)); RET_ON_ERROR(mfs_bank_get_state(mfsp, MFS_BANK_0, &sts0, &cnt0));
RET_ON_ERROR(mfs_get_bank_state(mfsp, MFS_BANK_1, &sts1, &cnt1)); RET_ON_ERROR(mfs_bank_get_state(mfsp, MFS_BANK_1, &sts1, &cnt1));
/* Handling all possible scenarios, each one requires its own recovery /* Handling all possible scenarios, each one requires its own recovery
strategy.*/ strategy.*/
@ -561,33 +629,35 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
case PAIR(MFS_BANK_ERASED, MFS_BANK_ERASED): case PAIR(MFS_BANK_ERASED, MFS_BANK_ERASED):
/* Both banks erased, first initialization.*/ /* Both banks erased, first initialization.*/
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_NO_ERROR; break;
case PAIR(MFS_BANK_ERASED, MFS_BANK_OK): case PAIR(MFS_BANK_ERASED, MFS_BANK_OK):
/* Normal situation, bank one is used.*/ /* Normal situation, bank one is used.*/
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
return MFS_NO_ERROR; break;
case PAIR(MFS_BANK_ERASED, MFS_BANK_PARTIAL): case PAIR(MFS_BANK_ERASED, MFS_BANK_PARTIAL):
/* Bank zero is erased, bank one has problems.*/ /* Bank zero is erased, bank one has problems.*/
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt1 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt1 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_ERASED, MFS_BANK_GARBAGE): case PAIR(MFS_BANK_ERASED, MFS_BANK_GARBAGE):
/* Bank zero is erased, bank one is not readable.*/ /* Bank zero is erased, bank one is not readable.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_OK, MFS_BANK_ERASED): case PAIR(MFS_BANK_OK, MFS_BANK_ERASED):
/* Normal situation, bank zero is used.*/ /* Normal situation, bank zero is used.*/
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_NO_ERROR; break;
case PAIR(MFS_BANK_OK, MFS_BANK_OK): case PAIR(MFS_BANK_OK, MFS_BANK_OK):
/* Both banks appear to be valid but one must be newer, erasing the /* Both banks appear to be valid but one must be newer, erasing the
@ -595,14 +665,15 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
if (cnt0 > cnt1) { if (cnt0 > cnt1) {
/* Bank 0 is newer.*/ /* Bank 0 is newer.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
} }
else { else {
/* Bank 1 is newer.*/ /* Bank 1 is newer.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
} }
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_OK, MFS_BANK_PARTIAL): case PAIR(MFS_BANK_OK, MFS_BANK_PARTIAL):
/* Bank zero is normal, bank one has problems.*/ /* Bank zero is normal, bank one has problems.*/
@ -610,7 +681,7 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
/* Normal bank zero is more recent than the partial bank one, the /* Normal bank zero is more recent than the partial bank one, the
partial bank needs to be erased.*/ partial bank needs to be erased.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
} }
else { else {
/* Partial bank one is more recent than the normal bank zero.*/ /* Partial bank one is more recent than the normal bank zero.*/
@ -618,23 +689,26 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt1 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt1 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
} }
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_OK, MFS_BANK_GARBAGE): case PAIR(MFS_BANK_OK, MFS_BANK_GARBAGE):
/* Bank zero is normal, bank one is unreadable.*/ /* Bank zero is normal, bank one is unreadable.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_PARTIAL, MFS_BANK_ERASED): case PAIR(MFS_BANK_PARTIAL, MFS_BANK_ERASED):
/* Bank zero has problems, bank one is erased.*/ /* Bank zero has problems, bank one is erased.*/
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_PARTIAL, MFS_BANK_OK): case PAIR(MFS_BANK_PARTIAL, MFS_BANK_OK):
/* Bank zero has problems, bank one is normal.*/ /* Bank zero has problems, bank one is normal.*/
@ -642,7 +716,7 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
/* Normal bank one is more recent than the partial bank zero, the /* Normal bank one is more recent than the partial bank zero, the
partial bank has to be erased.*/ partial bank has to be erased.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
} }
else { else {
/* Partial bank zero is more recent than the normal bank one.*/ /* Partial bank zero is more recent than the normal bank one.*/
@ -650,9 +724,10 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
} }
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_PARTIAL, MFS_BANK_PARTIAL): case PAIR(MFS_BANK_PARTIAL, MFS_BANK_PARTIAL):
/* Both banks have problems.*/ /* Both banks have problems.*/
@ -662,7 +737,7 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
} }
else { else {
/* Bank one is newer, copying in bank zero and using it.*/ /* Bank one is newer, copying in bank zero and using it.*/
@ -670,9 +745,10 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt1 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt1 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
} }
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_PARTIAL, MFS_BANK_GARBAGE): case PAIR(MFS_BANK_PARTIAL, MFS_BANK_GARBAGE):
/* Bank zero has problems, bank one is unreadable.*/ /* Bank zero has problems, bank one is unreadable.*/
@ -680,21 +756,24 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_0, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, cnt0 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_GARBAGE, MFS_BANK_ERASED): case PAIR(MFS_BANK_GARBAGE, MFS_BANK_ERASED):
/* Bank zero is unreadable, bank one is erased.*/ /* Bank zero is unreadable, bank one is erased.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_GARBAGE, MFS_BANK_OK): case PAIR(MFS_BANK_GARBAGE, MFS_BANK_OK):
/* Bank zero is unreadable, bank one is normal.*/ /* Bank zero is unreadable, bank one is normal.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_GARBAGE, MFS_BANK_PARTIAL): case PAIR(MFS_BANK_GARBAGE, MFS_BANK_PARTIAL):
/* Bank zero is unreadable, bank one has problems.*/ /* Bank zero is unreadable, bank one has problems.*/
@ -702,23 +781,31 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_copy(mfsp, MFS_BANK_1, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt0 + 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, cnt0 + 1));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
case PAIR(MFS_BANK_GARBAGE, MFS_BANK_GARBAGE): case PAIR(MFS_BANK_GARBAGE, MFS_BANK_GARBAGE):
/* Both banks are unreadable, reinitializing.*/ /* Both banks are unreadable, reinitializing.*/
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1)); RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1)); RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0)); RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
return MFS_WARN_REPAIR; err = MFS_WARN_REPAIR;
break;
default: default:
osalSysHalt("internal error"); osalSysHalt("internal error");
} }
/* Never reached.*/ /* If the last mount reported an anomaly then this is an error
return MFS_ERR_INTERNAL; because the bank has just been checked/repaired.*/
if (sts != MFS_BANK_OK) {
mfs_state_reset(mfsp);
return MFS_ERR_FLASH_FAILURE;
}
return err;
} }
/*===========================================================================*/ /*===========================================================================*/
@ -822,7 +909,8 @@ mfs_error_t mfsUnmount(MFSDriver *mfsp) {
* @brief Retrieves and reads a data record. * @brief Retrieves and reads a data record.
* *
* @param[in] mfsp pointer to the @p MFSDriver object * @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] id record numeric identifier * @param[in] id record numeric identifier, the valid range is between
* @p 1 and @p MFS_CFG_MAX_RECORDS
* @param[in,out] np on input is the maximum buffer size, on return it is * @param[in,out] np on input is the maximum buffer size, on return it is
* the size of the data copied into the buffer * the size of the data copied into the buffer
* @param[in] buffer pointer to a buffer for record data * @param[in] buffer pointer to a buffer for record data
@ -830,6 +918,8 @@ mfs_error_t mfsUnmount(MFSDriver *mfsp) {
* @retval MFS_NO_ERROR if the operation has been successfully completed. * @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_NOT_FOUND if the specified id does not exists. * @retval MFS_ERR_NOT_FOUND if the specified id does not exists.
* @retval MFS_ERR_CRC if retrieved data has a CRC error. * @retval MFS_ERR_CRC if retrieved data has a CRC error.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures.
* *
* @api * @api
*/ */
@ -848,7 +938,8 @@ mfs_error_t mfsReadRecord(MFSDriver *mfsp, uint32_t id,
* @brief Creates or updates a data record. * @brief Creates or updates a data record.
* *
* @param[in] mfsp pointer to the @p MFSDriver object * @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] id record numeric identifier * @param[in] id record numeric identifier, the valid range is between
* @p 1 and @p MFS_CFG_MAX_RECORDS
* @param[in] n size of data to be written, it cannot be zero * @param[in] n size of data to be written, it cannot be zero
* @param[in] buffer pointer to a buffer for record data * @param[in] buffer pointer to a buffer for record data
* @return The operation status. * @return The operation status.
@ -873,7 +964,8 @@ mfs_error_t mfsWriteRecord(MFSDriver *mfsp, uint32_t id,
* @brief Erases a data record. * @brief Erases a data record.
* *
* @param[in] mfsp pointer to the @p MFSDriver object * @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] id record numeric identifier * @param[in] id record numeric identifier, the valid range is between
* @p 1 and @p MFS_CFG_MAX_RECORDS
* @return The operation status. * @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed. * @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
@ -889,4 +981,24 @@ mfs_error_t mfsEraseRecord(MFSDriver *mfsp, uint32_t id) {
return MFS_NO_ERROR; return MFS_NO_ERROR;
} }
/**
* @brief Enforces a garbage collection operation.
* @details Garbage collection is usually performed on mount, it involves:
* integrity check, removal of obsolete data and a flash bank swap.
*
* @param[in] mfsp pointer to the @p MFSDriver object
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures.
*
* @api
*/
mfs_error_t mfsPerformGarbageCollection(MFSDriver *mfsp) {
(void)mfsp;
return MFS_NO_ERROR;
}
/** @} */ /** @} */

View File

@ -217,6 +217,17 @@ typedef struct {
uint32_t hdr32[3]; uint32_t hdr32[3];
} mfs_data_header_t; } mfs_data_header_t;
typedef struct {
/**
* @brief Offset of the record header.
*/
flash_offset_t offset;
/**
* @brief Record data size.
*/
uint32_t size;
} mfs_record_descriptor_t;
/** /**
* @brief Type of a MFS configuration structure. * @brief Type of a MFS configuration structure.
*/ */
@ -277,10 +288,6 @@ typedef struct {
* @brief Usage counter of the current bank. * @brief Usage counter of the current bank.
*/ */
uint32_t current_counter; uint32_t current_counter;
/**
* @brief Size in bytes of banks.
*/
uint32_t banks_size;
/** /**
* @brief Pointer to the next free position in the current bank. * @brief Pointer to the next free position in the current bank.
*/ */
@ -293,7 +300,7 @@ typedef struct {
* @brief Offsets of the most recent instance of the records. * @brief Offsets of the most recent instance of the records.
* @note Zero means that ther is not a record with that id. * @note Zero means that ther is not a record with that id.
*/ */
flash_offset_t instances[MFS_CFG_MAX_RECORDS]; mfs_record_descriptor_t descriptors[MFS_CFG_MAX_RECORDS];
/** /**
* @brief Transient buffer. * @brief Transient buffer.
*/ */
@ -333,6 +340,7 @@ extern "C" {
mfs_error_t mfsWriteRecord(MFSDriver *devp, uint32_t id, mfs_error_t mfsWriteRecord(MFSDriver *devp, uint32_t id,
uint32_t n, const uint8_t *buffer); uint32_t n, const uint8_t *buffer);
mfs_error_t mfsEraseRecord(MFSDriver *devp, uint32_t id); mfs_error_t mfsEraseRecord(MFSDriver *devp, uint32_t id);
mfs_error_t mfsPerformGarbageCollection(MFSDriver *mfsp);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif