Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers support_funcs.c Source File

support_funcs.c

00001 /*
00002  * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "flash-journal-strategy-sequential/flash_journal_crc.h"
00019 #include "support_funcs.h"
00020 #include <string.h>
00021 #include <stdio.h>
00022 #include <inttypes.h>
00023 
00024 struct FormatInfo_t formatInfoSingleton;
00025 
00026 int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP)
00027 {
00028     ARM_STORAGE_BLOCK mtdBlock;
00029     if ((mtd->GetNextBlock(NULL, &mtdBlock)) != ARM_DRIVER_OK) {
00030         return JOURNAL_STATUS_STORAGE_API_ERROR;
00031     }
00032     if (!ARM_STORAGE_VALID_BLOCK(&mtdBlock)) {
00033         return JOURNAL_STATUS_ERROR;
00034     }
00035 
00036     *startAddrP = mtdBlock.addr;
00037     return JOURNAL_STATUS_OK;
00038 }
00039 
00040 /**
00041  * Check the sanity of a given slot
00042  * @param       journal
00043  * @param       slotOffset
00044  * @param [out] headSequenceNumberP
00045  *                  sequence number of the slot as read from the header.
00046  * @param [out] tailP
00047  *                  the tail of the slot
00048  * @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees.
00049  */
00050 int32_t slotIsSane(SequentialFlashJournal_t        *journal,
00051                    uint64_t                         slotOffset,
00052                    uint32_t                        *headSequenceNumberP,
00053                    SequentialFlashJournalLogTail_t *tailP)
00054 {
00055     int32_t rc;
00056     ARM_DRIVER_STORAGE *mtd = journal->mtd;
00057 
00058     SequentialFlashJournalLogHead_t head;
00059     /* TODO: add support for asynchronous read */
00060     if (((rc = mtd->ReadData(slotOffset, &head, sizeof(SequentialFlashJournalLogHead_t))) < ARM_DRIVER_OK) ||
00061         (rc != sizeof(SequentialFlashJournalLogHead_t))) {
00062         if ((rc == ARM_DRIVER_OK) && (journal->mtdCapabilities.asynchronous_ops)) {
00063             return JOURNAL_STATUS_UNSUPPORTED;
00064         }
00065 
00066         return JOURNAL_STATUS_STORAGE_IO_ERROR;
00067     }
00068 
00069     /* compute the CRC32 of the header */
00070     flashJournalCrcReset();
00071     flashJournalCrcCummulative((const unsigned char *)&head, sizeof(SequentialFlashJournalLogHead_t));
00072 
00073     // printf("head->version: %lu\n", journal->initScan.head.version);
00074     // printf("head->magic: %lx\n", journal->initScan.head.magic);
00075     // printf("head->sequenceNumber: %lu\n", journal->initScan.head.sequenceNumber);
00076     // printf("head->reserved: %lu\n", journal->initScan.head.reserved);
00077 
00078     if (SEQUENTIAL_JOURNAL_VALID_HEAD(&head)) {
00079         *headSequenceNumberP = head.sequenceNumber;
00080         // printf("found valid header with sequenceNumber %" PRIu32 "\n", *headSequenceNumberP);
00081 
00082         uint64_t tailoffset = slotOffset
00083                               - ((slotOffset - SLOT_ADDRESS(journal, 0)) % journal->sizeofSlot)
00084                               + journal->sizeofSlot
00085                               - sizeof(SequentialFlashJournalLogTail_t);
00086         // printf("hoping to read a tail at offset %lu\n", (uint32_t)tailoffset);
00087 
00088         /* TODO: add support for asynchronous read */
00089         if (((rc = mtd->ReadData(tailoffset, tailP, sizeof(SequentialFlashJournalLogTail_t))) < ARM_DRIVER_OK) ||
00090             (rc != sizeof(SequentialFlashJournalLogTail_t))) {
00091             return JOURNAL_STATUS_STORAGE_IO_ERROR;
00092         }
00093 
00094         if (SEQUENTIAL_JOURNAL_VALID_TAIL(tailP) && (tailP->sequenceNumber == *headSequenceNumberP)) {
00095             // printf("found valid tail\n");
00096 
00097             /* iterate over the body of the slot computing CRC */
00098             #define CRC_CHUNK_SIZE 64
00099             uint8_t crcBuffer[CRC_CHUNK_SIZE];
00100             uint64_t bodyIndex = 0;
00101             uint64_t bodyOffset = slotOffset + sizeof(SequentialFlashJournalLogHead_t);
00102             while (bodyIndex < tailP->sizeofBlob) {
00103                 size_t sizeofReadOperation;
00104                 if ((tailP->sizeofBlob - bodyIndex) > CRC_CHUNK_SIZE) {
00105                     sizeofReadOperation = CRC_CHUNK_SIZE;
00106                 } else {
00107                     sizeofReadOperation = (tailP->sizeofBlob - bodyIndex);
00108                 }
00109 
00110                 /* TODO: add support for asynchronous read */
00111                 rc = mtd->ReadData(bodyOffset + bodyIndex, crcBuffer, sizeofReadOperation);
00112                 if (rc != (int32_t)sizeofReadOperation) {
00113                     return JOURNAL_STATUS_STORAGE_IO_ERROR;
00114                 }
00115 
00116                 bodyIndex += sizeofReadOperation;
00117                 flashJournalCrcCummulative(crcBuffer, sizeofReadOperation);
00118             }
00119 
00120             /* compute CRC32 over the tail */
00121             /* extract existing CRC32 from the tail. The CRC32 field in the tail needs to contain 0 before CRC32 can be computed over it. */
00122             uint32_t expectedCRC32 = tailP->crc32;
00123             tailP->crc32 = 0;
00124 
00125             uint32_t crc32 = flashJournalCrcCummulative((const unsigned char *)tailP, sizeof(SequentialFlashJournalLogTail_t));
00126             flashJournalCrcReset();
00127             // printf("expectedCRC32: 0x%x, computedCRC32: 0x%x\n", expectedCRC32, crc32);
00128             if (crc32 == expectedCRC32) {
00129                 return 1;
00130             }
00131         }
00132     }
00133 
00134     return JOURNAL_STATUS_ERROR;
00135 }
00136 
00137 int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots)
00138 {
00139     ARM_STORAGE_INFO mtdInfo;
00140     if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
00141         return JOURNAL_STATUS_STORAGE_API_ERROR;
00142     }
00143 
00144     headerP->genericHeader.magic        = FLASH_JOURNAL_HEADER_MAGIC;
00145     headerP->genericHeader.version      = FLASH_JOURNAL_HEADER_VERSION;
00146     headerP->genericHeader.sizeofHeader = sizeof(SequentialFlashJournalHeader_t);
00147 
00148     /* Determine 'journalOffset'.
00149      * Constraint: journal header should start and terminate at an erase-boundary
00150      * (so that slot-0 can be erased independently), and also a program-unit boundary.
00151      */
00152     headerP->genericHeader.journalOffset = roundUp_uint32(headerP->genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
00153     if ((headerP->genericHeader.journalOffset % mtdInfo.program_unit) != 0) {
00154         //printf("setupSequentialJournalHeader: journalOffset is not a multiple of MTD's program_unit\r\n");
00155         return JOURNAL_STATUS_PARAMETER;
00156     }
00157 
00158     headerP->magic    = SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC;
00159     headerP->version  = SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION;
00160     headerP->numSlots = numSlots;
00161 
00162     /* Determine 'sizeofSlot'.
00163      * Constraint: slot-size should be a multiple of the erase-units of all involved storage blocks.
00164      */
00165     uint64_t spaceAvailableForSlots = totalSize - headerP->genericHeader.journalOffset;
00166     headerP->sizeofSlot = roundDown_uint32(spaceAvailableForSlots / numSlots, LCM_OF_ALL_ERASE_UNITS);
00167     if (headerP->sizeofSlot == 0) {
00168         //printf("setupSequentialJournalHeader: not enough space to create %" PRIu32 " slots\r\n", numSlots);
00169         return JOURNAL_STATUS_PARAMETER;
00170     }
00171 
00172     headerP->genericHeader.totalSize = headerP->genericHeader.journalOffset + (headerP->sizeofSlot * numSlots);
00173     //printf("setupSequentialJournalHeader: header size = %" PRIu32 ", journalOffset = %" PRIu32 ", sizeofSlot = %" PRIu32 ", totalSize = %lu\n", headerP->genericHeader.sizeofHeader, headerP->genericHeader.journalOffset, headerP->sizeofSlot, (uint32_t)headerP->genericHeader.totalSize);
00174 
00175     /* compute checksum over the entire header */
00176     headerP->genericHeader.checksum = 0;
00177     flashJournalCrcReset();
00178     headerP->genericHeader.checksum = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t));
00179 
00180     return JOURNAL_STATUS_OK;
00181 }
00182 
00183 int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal)
00184 {
00185     /* reset top level journal metadata prior to scanning headers. */
00186     journal->nextSequenceNumber       = SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER; /* we are currently unaware of previously written blobs */
00187     journal->currentBlobIndex         = journal->numSlots;
00188     journal->info.sizeofJournaledBlob = 0;
00189 
00190     /* begin header-scan from the first block of the MTD */
00191     journal->initScan.currentOffset   = SLOT_ADDRESS(journal, 0);
00192     journal->state                    = SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS;
00193 
00194     // printf("discoverLatestLoggedBlob: start of init scan\n");
00195     for (unsigned blobIndex = 0;
00196          blobIndex < journal->numSlots;
00197          blobIndex++, journal->initScan.currentOffset += journal->sizeofSlot) {
00198         // printf("discoverLatestLoggedBlob: blob index %u\n", blobIndex);
00199         /* TODO: it is possible that the header structure spans multiple blocks, needing multiple reads. */
00200 
00201         if (slotIsSane(journal,
00202                        journal->initScan.currentOffset,
00203                        &journal->initScan.headSequenceNumber,
00204                        &journal->initScan.tail) == 1) {
00205             // printf("found valid blob with sequence number %lu\n", journal->initScan.headSequenceNumber);
00206             uint32_t nextSequenceNumber = journal->initScan.headSequenceNumber + 1;
00207             if (nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
00208                 nextSequenceNumber = 0;
00209             }
00210 
00211             /* Have we found the best of the slots seen so far? */
00212             if ((journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) ||
00213                 /* We take advantage of properties of unsigned arithmetic in the following
00214                  * expression.
00215                  *
00216                  * We want to calculate if (nextSequenceNumber > journal->nextSequenceNumber),
00217                  * instead we use the expression ((nextSequenceNumber - journal->nextSequenceNumber) > 0)
00218                  * to take wraparounds into account.
00219                  */
00220                 ((int32_t)(nextSequenceNumber - journal->nextSequenceNumber) > 0)) {
00221                 journal->currentBlobIndex         = blobIndex;
00222                 journal->nextSequenceNumber       = nextSequenceNumber;
00223                 journal->info.sizeofJournaledBlob = journal->initScan.tail.sizeofBlob;
00224                 // printf("discoverLatestLoggedBlob: index %lu, sizeofBlob: %lu, nextSequenceNumber: %lu\n",
00225                 //        journal->currentBlobIndex, (uint32_t)journal->info.sizeofJournaledBlob, journal->nextSequenceNumber);
00226             }
00227         }
00228     }
00229     // printf("discoverLatestLoggedBlob: finished init scan\n");
00230 
00231     /* Handle the case where our scan hasn't yielded any results. */
00232     if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
00233         // printf("discoverLatestLoggedBlob: initializing to defaults\n");
00234         journal->currentBlobIndex   = (uint32_t)-1; /* to be incremented to 0 during the first attempt to log(). */
00235         journal->nextSequenceNumber = 0;
00236     }
00237 
00238     journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00239     return JOURNAL_STATUS_OK;
00240 }
00241 
00242 /**
00243  * Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler.
00244  * @return  < JOURNAL_STATUS_OK for error
00245  *          = JOURNAL_STATUS_OK to signal pending asynchronous activity
00246  *          > JOURNAL_STATUS_OK for completion
00247  */
00248 int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed)
00249 {
00250     int32_t rc;
00251     size_t sizeofWrite = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit);
00252     size_t sizeofErase = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
00253     switch (operationWhichJustFinshed) {
00254         case ARM_STORAGE_OPERATION_INITIALIZE:
00255             if (status != ARM_DRIVER_OK) {
00256                 return JOURNAL_STATUS_STORAGE_API_ERROR;
00257             }
00258 
00259             // printf("erasing %u bytes from offset %u\n", roundUp_uint32(header.genericHeader.sizeofHeader, mtdInfo.program_unit), mtdAddr);
00260             rc = (formatInfoSingleton.mtd)->Erase(formatInfoSingleton.mtdAddr, sizeofErase);
00261             if (rc < ARM_DRIVER_OK) {
00262                 if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
00263                     return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
00264                 } else {
00265                     return JOURNAL_STATUS_STORAGE_IO_ERROR;
00266                 }
00267             } else if (rc == ARM_DRIVER_OK) {
00268                 return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
00269                                            * where the rest of processing will take place. */
00270             }
00271             /* handle synchronous completion of programData */
00272             status = rc;
00273 
00274             /* intentional fall-through */
00275 
00276         case ARM_STORAGE_OPERATION_ERASE:
00277             if (status != (int32_t)sizeofErase) {
00278                 return JOURNAL_STATUS_STORAGE_IO_ERROR;
00279             }
00280 
00281             // printf("calling ProgramData at address %u for %u bytes\n",
00282             //        formatInfoSingleton.mtdAddr, roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit));
00283             rc = (formatInfoSingleton.mtd)->ProgramData(formatInfoSingleton.mtdAddr, &(formatInfoSingleton.header), sizeofWrite);
00284             if (rc < ARM_DRIVER_OK) {
00285                 if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
00286                     return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
00287                 } else {
00288                     return JOURNAL_STATUS_STORAGE_IO_ERROR;
00289                 }
00290             } else if (rc == ARM_DRIVER_OK) {
00291                 return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
00292                                            * where the rest of processing will take place. */
00293             }
00294             /* handle synchronous completion of programData */
00295             status = rc;
00296 
00297             /* intentional fall-through */
00298 
00299         case ARM_STORAGE_OPERATION_PROGRAM_DATA:
00300             if (status != (int32_t)sizeofWrite) {
00301                 return JOURNAL_STATUS_STORAGE_IO_ERROR;
00302             }
00303 
00304             return 1; /* acknowledge the completion of create */
00305 
00306         default:
00307             return JOURNAL_STATUS_STORAGE_API_ERROR; /* we don't expect to be here */
00308     }
00309 }
00310 
00311 int32_t flashJournalStrategySequential_reset_progress(void)
00312 {
00313     int32_t rc;
00314     SequentialFlashJournal_t *journal = activeJournal;
00315 
00316     if ((rc = journal->mtd->Erase(SLOT_ADDRESS(journal, 0), journal->numSlots * journal->sizeofSlot)) < ARM_DRIVER_OK) {
00317         journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00318         if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
00319             return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
00320         } else {
00321             return JOURNAL_STATUS_STORAGE_IO_ERROR;
00322         }
00323     }
00324     if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
00325         //printf("eturning JOURNAL_STATUS_OK\n");
00326         return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
00327     }
00328     /* else we fall through to handle synchronous completion */
00329 
00330     journal->nextSequenceNumber       = 0;
00331     journal->currentBlobIndex         = (uint32_t)-1;
00332     journal->info.sizeofJournaledBlob = 0;
00333     journal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00334     return 1;
00335 }
00336 
00337 int32_t flashJournalStrategySequential_read_progress(void)
00338 {
00339     SequentialFlashJournal_t *journal = activeJournal;
00340 
00341     // printf("flashJournalStrategySequential_read_progress\n");
00342     if (journal->state != SEQUENTIAL_JOURNAL_STATE_READING) {
00343         return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
00344     }
00345 
00346     int32_t rc;
00347     ARM_STORAGE_BLOCK storageBlock;
00348 
00349     if ((journal->read.amountLeftToRead) &&
00350         ((rc = journal->mtd->GetBlock(journal->read.mtdOffset, &storageBlock)) != ARM_DRIVER_OK)) {
00351         journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00352         return JOURNAL_STATUS_STORAGE_API_ERROR;
00353     }
00354     uint64_t storageBlockAvailableCapacity = storageBlock.size - (journal->read.mtdOffset - storageBlock.addr);
00355 
00356     while (journal->read.amountLeftToRead) {
00357         while (!storageBlockAvailableCapacity) {
00358             if ((rc = journal->mtd->GetNextBlock(&storageBlock, &storageBlock)) < ARM_DRIVER_OK) {
00359                 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00360                 return JOURNAL_STATUS_ERROR; /* We ran out of storage blocks. Journal is in an un-expected state. */
00361             }
00362             journal->read.mtdOffset       =  storageBlock.addr; /* This should not be necessary since we assume
00363                                                                  * storage map manages a contiguous address space. */
00364             storageBlockAvailableCapacity = storageBlock.size;
00365         }
00366 
00367         /* compute the transfer size for this iteration. */
00368         uint32_t xfer = (journal->read.amountLeftToRead < storageBlockAvailableCapacity) ?
00369                             journal->read.amountLeftToRead : storageBlockAvailableCapacity;
00370 
00371         /* perform the IO */
00372         //printf("reading %lu bytes at offset %lu\n", xfer, (uint32_t)journal->read.mtdOffset);
00373         rc = journal->mtd->ReadData(journal->read.mtdOffset, journal->read.dataBeingRead, xfer);
00374         if (rc < ARM_DRIVER_OK) {
00375             journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00376             return JOURNAL_STATUS_STORAGE_IO_ERROR;
00377         }
00378         if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
00379             return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
00380         } else {
00381             /* synchronous completion. 'rc' contains the actual number of bytes transferred. */
00382             journal->read.mtdOffset        += rc;
00383             journal->read.amountLeftToRead -= rc;
00384             journal->read.dataBeingRead    += rc;
00385             journal->read.logicalOffset    += rc;
00386         }
00387     }
00388 
00389     journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00390     return (journal->read.dataBeingRead - journal->read.blob);
00391 }
00392 
00393 /**
00394  * Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler.
00395  * @return  < JOURNAL_STATUS_OK for error
00396  *          = JOURNAL_STATUS_OK to signal pending asynchronous activity
00397  *          > JOURNAL_STATUS_OK for completion
00398  */
00399 int32_t flashJournalStrategySequential_log_progress(void)
00400 {
00401     SequentialFlashJournal_t *journal = activeJournal;
00402 
00403     if ((journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) &&
00404         (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD)  &&
00405         (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY)  &&
00406         (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL)) {
00407         return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
00408     }
00409 
00410     uint32_t blobIndexBeingLogged = journal->currentBlobIndex + 1;
00411     if (blobIndexBeingLogged == journal->numSlots) {
00412         blobIndexBeingLogged = 0;
00413     }
00414 
00415     while (true) {
00416         int32_t rc;
00417 
00418         if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) {
00419             uint64_t amountLeftToErase = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - journal->log.mtdEraseOffset;
00420             // printf("journal state: erasing; offset %lu [size %lu]\n",
00421             //        (uint32_t)journal->log.eraseOffset, (uint32_t)amountLeftToErase);
00422             while (amountLeftToErase) {
00423                 if ((rc = journal->mtd->Erase(journal->log.mtdEraseOffset, amountLeftToErase)) < ARM_DRIVER_OK) {
00424                     journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00425                     if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
00426                         return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
00427                     } else {
00428                         return JOURNAL_STATUS_ERROR;
00429                     }
00430                 }
00431                 if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
00432                     return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
00433                 } else {
00434                     /* synchronous completion. */
00435                     journal->log.mtdEraseOffset += rc;
00436                     amountLeftToErase           -= rc;
00437                 }
00438             }
00439         } else {
00440             ARM_STORAGE_BLOCK storageBlock;
00441 
00442             /* find the available capacity in the current storage block */
00443             while (journal->log.amountLeftToLog) {
00444                 if (journal->log.amountLeftToLog < journal->info.program_unit) {
00445                     /* We cannot log any smaller than info.program_unit. 'xfer'
00446                      * amount of data would remain unlogged. We'll break out of this loop and report
00447                      * the amount actually logged. */
00448                     break;
00449                 }
00450 
00451                 /* check for alignment of next log offset with program_unit */
00452                 if ((rc = journal->mtd->GetBlock(journal->log.mtdOffset, &storageBlock)) != ARM_DRIVER_OK) {
00453                     journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00454                     return JOURNAL_STATUS_STORAGE_API_ERROR;
00455                 }
00456                 if ((journal->log.mtdOffset - storageBlock.addr) % journal->info.program_unit) {
00457                     journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00458                     return JOURNAL_STATUS_ERROR; /* Program offset doesn't align with info.program_unit. This would result in an IO error if attempted. */
00459                 }
00460 
00461                 uint32_t xfer = journal->log.amountLeftToLog;
00462                 xfer -= xfer % journal->info.program_unit; /* align transfer-size with program_unit. */
00463 
00464                 /* perform the IO */
00465                 // printf("programming %lu bytes at offset %lu\n", xfer, (uint32_t)journal->log.mtdOffset);
00466                 rc = journal->mtd->ProgramData(journal->log.mtdOffset, journal->log.dataBeingLogged, xfer);
00467                 if (rc < ARM_DRIVER_OK) {
00468                     journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00469                     if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
00470                         return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
00471                     } else {
00472                         return JOURNAL_STATUS_STORAGE_IO_ERROR;
00473                     }
00474                 }
00475                 if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
00476                     return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
00477                 } else {
00478                     /* synchronous completion. 'rc' contains the actual number of bytes transferred. */
00479                     journal->log.mtdOffset       += rc;
00480                     journal->log.amountLeftToLog -= rc;
00481                     journal->log.dataBeingLogged += rc;
00482                     if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
00483                         journal->log.tail.sizeofBlob += rc;
00484                     }
00485                 }
00486             } /* while (journal->log.amountLeftToLog) */
00487         }
00488 
00489         // printf("flashJournalStrategySequential_log_progress: state switch\n");
00490 
00491         /* state transition */
00492         switch (journal->state) {
00493             case SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE:
00494                 journal->state                   = SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD;
00495                 journal->log.mtdOffset           = SLOT_ADDRESS(journal, blobIndexBeingLogged);
00496                 journal->log.head.version        = SEQUENTIAL_FLASH_JOURNAL_VERSION;
00497                 journal->log.head.magic          = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
00498                 journal->log.head.sequenceNumber = journal->nextSequenceNumber;
00499                 journal->log.head.reserved       = 0;
00500                 journal->log.dataBeingLogged     = (const uint8_t *)&journal->log.head;
00501                 journal->log.amountLeftToLog     = sizeof(SequentialFlashJournalLogHead_t);
00502                 // printf("newstate: program HEAD; amount to log %u\n", journal->log.amountLeftToLog);
00503                 break;
00504 
00505             case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: /* we've finished writing the head */
00506                 /* compute CRC32 on the header */
00507                 flashJournalCrcReset();
00508                 flashJournalCrcCummulative((const unsigned char *)&journal->log.head, sizeof(SequentialFlashJournalLogHead_t));
00509 
00510                 /* switch to writing the body */
00511 
00512                 /* Prepare for the tail to be written out at a later time.
00513                  * This will only be done once Commit() is called. */
00514                 journal->log.mtdTailOffset       = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - sizeof(SequentialFlashJournalLogTail_t);
00515 
00516                 journal->log.tail.magic          = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
00517                 journal->log.tail.sequenceNumber = journal->nextSequenceNumber;
00518                 journal->log.tail.sizeofBlob     = 0; /* we'll update this as we complete our writes. */
00519                 journal->log.tail.crc32          = 0;
00520 
00521                 if (journal->prevCommand == FLASH_JOURNAL_OPCODE_COMMIT) {
00522                     /* This branch is taken only when commit() is called without any preceding log() operations. */
00523                     journal->log.tail.crc32      = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t));
00524                     flashJournalCrcReset();
00525 
00526                     journal->state               = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL;
00527                     journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail;
00528                     journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t);
00529                     journal->log.mtdOffset       = journal->log.mtdTailOffset;
00530                     // printf("newstate: program TAIL at offset %lu\r\n", (uint32_t)journal->log.mtdOffset);
00531                 } else {
00532                     journal->state                   = SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY;
00533                     journal->log.dataBeingLogged     = journal->log.blob;
00534                     journal->log.amountLeftToLog     = journal->log.sizeofBlob;
00535                     // printf("newstate: program BODY; amount to log %u\n", journal->log.amountLeftToLog);
00536                 }
00537                 break;
00538 
00539             case SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY:
00540                 // printf("finished logging BODY; amount logged %u\n", journal->log.dataBeingLogged - journal->log.blob);
00541                 if (journal->log.dataBeingLogged == journal->log.blob) {
00542                     return JOURNAL_STATUS_SMALL_LOG_REQUEST;
00543                 } else {
00544                     uint32_t amountOfDataLogged = (journal->log.dataBeingLogged - journal->log.blob);
00545                     flashJournalCrcCummulative(journal->log.blob, amountOfDataLogged); /* compute CRC32 on logged data */
00546                     return amountOfDataLogged;
00547                 }
00548 
00549             case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL:
00550                 // printf("crc32 of slot: 0x%x\n", journal->log.tail.crc32);
00551 
00552                 journal->info.sizeofJournaledBlob = journal->log.tail.sizeofBlob;
00553                 journal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state to allow further operations */
00554 
00555                 ++journal->currentBlobIndex;
00556                 if (journal->currentBlobIndex == journal->numSlots) {
00557                     journal->currentBlobIndex = 0;
00558                 }
00559                 // printf("currentBlobIndex: %lu\n", journal->currentBlobIndex);
00560 
00561                 /* increment next sequence number */
00562                 ++journal->nextSequenceNumber;
00563                 if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
00564                     ++journal->nextSequenceNumber;
00565                 }
00566                 // printf("nextSequenceNumber %lu\n", journal->nextSequenceNumber);
00567 
00568                 return 1; /* commit returns 1 upon completion. */
00569 
00570             default:
00571                 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00572                 return JOURNAL_STATUS_ERROR;
00573         }
00574     }
00575 }
00576 
00577 void formatHandler(int32_t status, ARM_STORAGE_OPERATION operation)
00578 {
00579     if (status < ARM_DRIVER_OK) {
00580         if (formatInfoSingleton.callback) {
00581             formatInfoSingleton.callback(status, FLASH_JOURNAL_OPCODE_FORMAT);
00582         }
00583         return;
00584     }
00585 
00586     int32_t rc = flashJournalStrategySequential_format_progress(status, operation);
00587     if (rc != JOURNAL_STATUS_OK) {
00588         if (formatInfoSingleton.callback) {
00589             formatInfoSingleton.callback(rc, FLASH_JOURNAL_OPCODE_FORMAT);
00590         }
00591     }
00592 }
00593 
00594 void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
00595 {
00596     int32_t rc;
00597 
00598     if (status < ARM_DRIVER_OK) {
00599         /* Map integrity failures reported by the Storage driver appropriately. */
00600         if (status == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
00601             status = JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
00602         } else {
00603             status = JOURNAL_STATUS_STORAGE_IO_ERROR;
00604         }
00605 
00606         // printf("journal mtdHandler: received error status %ld\n", status);
00607         switch (activeJournal->state) {
00608             case SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED:
00609             case SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS:
00610                 if (activeJournal->callback) {
00611                     activeJournal->callback(status, FLASH_JOURNAL_OPCODE_INITIALIZE);
00612                 }
00613                 break;
00614 
00615             case SEQUENTIAL_JOURNAL_STATE_RESETING:
00616                 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00617                 if (activeJournal->callback) {
00618                     activeJournal->callback(status, FLASH_JOURNAL_OPCODE_RESET);
00619                 }
00620                 break;
00621 
00622             case SEQUENTIAL_JOURNAL_STATE_INITIALIZED:
00623             case SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE:
00624             case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD:
00625             case SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY:
00626             case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL:
00627                 /* reset journal state to allow further operation. */
00628                 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00629 
00630                 if (activeJournal->callback) {
00631                     activeJournal->callback(status, FLASH_JOURNAL_OPCODE_LOG_BLOB);
00632                 }
00633                 break;
00634             case SEQUENTIAL_JOURNAL_STATE_READING:
00635                 /* reset journal state to allow further operation. */
00636                 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00637 
00638                 if (activeJournal->callback) {
00639                     activeJournal->callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB);
00640                 }
00641                 break;
00642         }
00643 
00644         return;
00645     }
00646 
00647     switch (operation) {
00648         case ARM_STORAGE_OPERATION_INITIALIZE:
00649             if (activeJournal->callback) {
00650                 activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_INITIALIZE);
00651             }
00652             break;
00653 
00654         case ARM_STORAGE_OPERATION_ERASE_ALL:
00655             if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_RESETING) {
00656                 activeJournal->nextSequenceNumber       = 0;
00657                 activeJournal->currentBlobIndex         = (uint32_t)-1;
00658                 activeJournal->info.sizeofJournaledBlob = 0;
00659                 activeJournal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00660                 if (activeJournal->callback) {
00661                     activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_RESET);
00662                 }
00663             }
00664             break;
00665 
00666         case ARM_STORAGE_OPERATION_ERASE:
00667             if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) {
00668                 if (status <= ARM_DRIVER_OK) {
00669                     if (activeJournal->callback) {
00670                         activeJournal->callback(JOURNAL_STATUS_STORAGE_API_ERROR, FLASH_JOURNAL_OPCODE_LOG_BLOB);
00671                     }
00672                     return;
00673                 }
00674 
00675                 activeJournal->log.mtdEraseOffset += status;
00676 
00677                 if ((rc = flashJournalStrategySequential_log_progress()) != JOURNAL_STATUS_OK) {
00678                     activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00679                     if (activeJournal->callback) {
00680                         activeJournal->callback(rc, FLASH_JOURNAL_OPCODE_LOG_BLOB);
00681                     }
00682                     return;
00683                 }
00684             } else if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_RESETING) {
00685                 activeJournal->nextSequenceNumber       = 0;
00686                 activeJournal->currentBlobIndex         = (uint32_t)-1;
00687                 activeJournal->info.sizeofJournaledBlob = 0;
00688                 activeJournal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
00689                 if (activeJournal->callback) {
00690                     activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_RESET);
00691                 }
00692             }
00693             break;
00694 
00695         case ARM_STORAGE_OPERATION_PROGRAM_DATA:
00696             // printf("journal mtdHandler: PROGRAM_DATA: received status of %ld\n", status);
00697             rc = status;
00698             activeJournal->log.mtdOffset       += rc;
00699             activeJournal->log.amountLeftToLog -= rc;
00700             activeJournal->log.dataBeingLogged += rc;
00701             if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
00702                 activeJournal->log.tail.sizeofBlob += rc;
00703             }
00704 
00705             if ((rc = flashJournalStrategySequential_log_progress()) < JOURNAL_STATUS_OK) {
00706                 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
00707                 if (activeJournal->callback) {
00708                     activeJournal->callback(rc,
00709                                             (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL) ?
00710                                                 FLASH_JOURNAL_OPCODE_COMMIT : FLASH_JOURNAL_OPCODE_LOG_BLOB);
00711                 }
00712                 return;
00713             }
00714             if ((rc == JOURNAL_STATUS_OK) && (activeJournal->log.amountLeftToLog > 0)) {
00715                 return; /* we've got pending asynchronous activity */
00716             }
00717             if (activeJournal->callback) {
00718                 activeJournal->callback(rc, (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) ?
00719                                                 FLASH_JOURNAL_OPCODE_COMMIT : FLASH_JOURNAL_OPCODE_LOG_BLOB);
00720             }
00721             break;
00722 
00723         default:
00724             //printf("mtdHandler: unknown operation %u\n", operation);
00725             break;
00726     }
00727 }