source: umon/main/common/tfsclean1.c @ 87db514

Last change on this file since 87db514 was 87db514, checked in by Amar Takhar <amar@…>, on 04/16/15 at 19:26:21

Initial commit of the umon repository.

Prior to this three changes were made:

  • Remove umon_ prefix from parent directories.
  • Collapse main/target/ into main/
  • Remove ports/template/flashtest.scr.ucon script.
  • Property mode set to 100755
File size: 65.4 KB
Line 
1/**************************************************************************
2 *
3 * Copyright (c) 2013 Alcatel-Lucent
4 *
5 * Alcatel Lucent licenses this file to You under the Apache License,
6 * Version 2.0 (the "License"); you may not use this file except in
7 * compliance with the License.  A copy of the License is contained the
8 * file LICENSE at the top level of this repository.
9 * You may also obtain a copy of the License at:
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 **************************************************************************
20 *
21 * tfsclean1.c:
22 *
23 * This is one of several different versions of tfsclean().  This version
24 * is by far the most complex, but offers power-hit safety and minimal
25 * flash overhead.  It uses a "spare" sector to backup the
26 * "one-sector-at-a-time" defragmentation process.
27 *
28 * Original author:     Ed Sutter (ed.sutter@alcatel-lucent.com)
29 *
30 */
31#include "config.h"
32#include "cpu.h"
33#include "stddefs.h"
34#include "genlib.h"
35#include "tfs.h"
36#include "tfsprivate.h"
37#include "flash.h"
38#include "monflags.h"
39#include "warmstart.h"
40
41#if INCLUDE_TFS
42
43#if !INCLUDE_FLASH
44#error: If flash is not included, then use tfsclean2.c
45#endif
46
47#if DEFRAG_TEST_ENABLED
48void
49defragExitTestPoint(int val)
50{
51        if ((DefragTestType == DEFRAG_TEST_EXIT) && (DefragTestPoint == val)) {
52                printf("\n+++++++++ EXIT @ TEST POINT(%d)\n",val);
53                CommandLoop();
54        }
55}
56#else
57#define defragExitTestPoint(val)
58#endif
59
60/* Variables for testing tfsclean():
61 * They are set up through arguments to "tfs clean" in tfscli.c.
62 */
63int DefragTestType;
64int DefragTestPoint;
65int DefragTestSector;
66
67/* defragTick():
68 * Used to show progress, just to let the user know that we aren't
69 * dead in the water.
70 */
71static void
72defragTick(int verbose)
73{
74        static int tick;
75        static char     clockhand[] = { '|', '/', '-', '\\' };
76
77        if (!verbose && (!MFLAGS_NODEFRAGPRN())) {
78                if (tick > 3)
79                        tick = 0;
80                printf("%c\b",clockhand[tick++]);
81        }
82}
83
84/* defragCrcTable():
85 * Return a pointer to the crc table for the specified TFS device.
86 */
87struct sectorcrc *
88defragCrcTable(TDEV *tdp)
89{
90        return((struct sectorcrc *)(tdp->end+1) - tdp->sectorcount);
91}
92
93/* defragSerase():
94 * Common function to call from within tfsclean() to erase a sector
95 * and generate an error message if necessary.
96 *
97 * If DEFRAG_TEST_ENABLED is defined and the type/sector/point criteria
98 * is met, then instead of erasing the sector; just change the first non-zero
99 * byte to zero to corrupt it.  This essentially makes it a corrupted erase.
100 */
101static int
102defragSerase(int tag, int snum)
103{
104        int     ret = 0;
105
106#if DEFRAG_TEST_ENABLED
107        int     ssize;
108        uchar *sbase, *send, zero;
109
110        printf("     serase_%02d(%02d)\n",tag,snum);
111
112        if ((DefragTestType == DEFRAG_TEST_SERASE) &&
113                (DefragTestSector == snum) && (DefragTestPoint == tag)) {
114                        sectortoaddr(snum,&ssize,&sbase);
115                        send = sbase+ssize;
116                        zero = 0;
117                        while(sbase < send) {
118                                if (*sbase != 0) {
119                                        tfsflashwrite((ulong *)sbase,(ulong *)&zero,1);
120                                        break;
121                                }
122                                sbase++;
123                        }
124                        printf("DEFRAG_TEST_SERASE activated @ %d sector %d\n",tag,snum);
125                        CommandLoop();
126        }
127        else
128#endif
129        ret = tfsflasherase(snum);
130        if (ret <= 0) {
131                printf("tfsclean() serase erase failed: %d,%d,%d\n",snum,tag,ret);
132        }
133        return(ret);
134}
135
136/* defragFwrite():
137 * Common function to call from within tfsclean() to write to flash
138 * and generate an error message if necessary.
139 * If DEFRAG_TEST_ENABLED is defined and the test type is set to
140 * DEFRAG_TEST_FWRITE, then use APPRAMBASE as the source of the data
141 * so that the end result is an errored flash write.
142 */
143static int
144defragFwrite(int tag, uchar *dest,uchar *src,int size)
145{
146        int     ret = 0;
147
148#if DEFRAG_TEST_ENABLED
149        int     snum;
150
151        addrtosector((char *)dest,&snum,0,0);
152        printf("     fwrite_%02d(%d,0x%lx,0x%lx,%d)\n",
153                tag,snum,(ulong)dest,(ulong)src,size);
154
155        if ((DefragTestType == DEFRAG_TEST_FWRITE) &&
156                (DefragTestSector == snum) && (DefragTestPoint == tag)) {
157                        tfsflashwrite((ulong *)dest,(ulong *)getAppRamStart(),size/2);
158                        printf("DEFRAG_TEST_FWRITE activated @ %d sector %d\n",tag,snum);
159                        CommandLoop();
160        }
161        else
162#endif
163        ret = tfsflashwrite(dest,src,size);
164        if (ret != TFS_OKAY) {
165                printf("tfsclean() fwrite failed: 0x%lx,0x%lx,%d,%d\n",
166                        (ulong)dest,(ulong)src,size,tag);
167        }
168        return(ret);
169}
170
171/* defragGetSpantype():
172 * With the incoming sector base and end (s_base, s_end),
173 * determine the type of span that the incoming file (f_base, f_end)
174 * has across it.  There are six different ways the spanning can
175 * occur:
176 *   1. begin and end in previous active sector (bpep);
177 *   2. begin in previously active sector, end in this one (bpec);
178 *   3. begin in previously active sector, end in later one (bpel);
179 *   4. begin and end in this active sector (bcec);
180 *   5. begin in this active sector, end in later one (bcel);
181 *   6. begin and end in later active sector (blel);
182 */
183static int
184defragGetSpantype(char *s_base,char *s_end,char *f_base,char *f_end)
185{
186        int     spantype;
187
188        if (f_base < s_base) {
189                if ((f_end > s_base) && (f_end <= s_end))
190                        spantype = SPANTYPE_BPEC;
191                else if (f_end > s_end)
192                        spantype = SPANTYPE_BPEL;
193                else
194                        spantype = SPANTYPE_BPEP;
195        }
196        else {
197                if (f_base > s_end)
198                        spantype = SPANTYPE_BLEL;
199                else if (f_end <= s_end)
200                        spantype = SPANTYPE_BCEC;
201                else
202                        spantype = SPANTYPE_BCEL;
203        }
204        return(spantype);
205}
206
207/* defragGetSpantypeStr():
208 * Return a string that corresponds to the incoming state value.
209 */
210static char *
211defragGetSpantypeStr(int spantype)
212{
213        char *str;
214
215        switch(spantype) {
216        case SPANTYPE_BPEC:
217                str = "BPEC";
218                break;
219        case SPANTYPE_BLEL:
220                str = "BLEL";
221                break;
222        case SPANTYPE_BPEL:
223                str = "BPEL";
224                break;
225        case SPANTYPE_BPEP:
226                str = "BPEP";
227                break;
228        case SPANTYPE_BCEC:
229                str = "BCEC";
230                break;
231        case SPANTYPE_BCEL:
232                str = "BCEL";
233                break;
234        default:
235                str = "???";
236                break;
237        }
238        return(str);
239}
240
241/* defragEraseSpare():
242 * Erase the spare sector associated with the incoming TFS device.
243 * The underlying flash driver SHOULD have a check so that it only
244 * erases the sector if the sector is not already erased, so this
245 * extra check (call to flasherased()) may not be necessary in
246 * most cases.
247 */
248static int
249defragEraseSpare(TDEV *tdp)
250{
251        int     snum, ssize;
252        uchar *sbase;
253
254        if (addrtosector((unsigned char *)tdp->spare,&snum,&ssize,&sbase) < 0)
255                return(TFSERR_FLASHFAILURE);
256
257        if (!flasherased(sbase,sbase+(ssize-1))) {
258                if (defragSerase(1,snum) < 0) {
259                        return(TFSERR_FLASHFAILURE);
260                }
261        }
262        return(TFS_OKAY);
263}
264
265/* defragValidDSI():
266 * Test to see if we have a valid defrag state information (DSI)
267 * area.  The DSI area, working back from tdp->end, consists of a
268 * table of 32-bit crcs (one per sector), a table of defraghdr
269 * structures (one per active file) and a 32-bit crc of the DSI
270 * itself.  Knowing this format, we can easily step backwards into
271 * the DSI space to see if it all makes sense.
272 * If the table is 100% valid, then we will be able to step
273 * backwards through the DSI to find the 32-bit crc of the DSI area.
274 * If it matches, then we can be sure that the DSI is valid.
275 * Return total number of files in header if the defrag header
276 * table appears to be sane, else 0.
277 */
278static int
279defragValidDSI(TDEV *tdp, struct sectorcrc **scp)
280{
281        int             ftot, valid, lastssize;
282        uchar   *lastsbase;
283        struct  sectorcrc *crctbl;
284        ulong   hdrcrc, *crc;
285        struct  defraghdr       *dhp, dfhcpy;
286
287        ftot = valid = 0;
288        crctbl = defragCrcTable(tdp);
289        dhp = (struct defraghdr *)crctbl - 1;
290        /* next line was <dfhcpy = *dhp> ... */
291        memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr));
292        hdrcrc = dfhcpy.crc;
293        dfhcpy.crc = 0;
294        if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) {
295                ftot = dhp->idx + 1;
296                dhp = (struct defraghdr *)crctbl - ftot;
297                crc = (ulong *)dhp - 1;
298                if (crc32((uchar *)dhp,(uchar *)tdp->end-(uchar *)dhp) == *crc) {
299                        if (scp)
300                                *scp = crctbl;
301                        return(ftot);
302                }
303        }
304
305        /* It's possible that the DSI space has been relocated to the spare
306         * sector, so check for that here...
307         */
308        addrtosector((unsigned char *)tdp->end,0,&lastssize,&lastsbase);
309
310        crctbl = ((struct sectorcrc *)(tdp->spare+lastssize) - tdp->sectorcount);
311        dhp = (struct defraghdr *)crctbl - 1;
312        /* next line was <dfhcpy = *dhp> ... */
313        memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr));
314        hdrcrc = dfhcpy.crc;
315        dfhcpy.crc = 0;
316        if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) {
317                ftot = dhp->idx + 1;
318                dhp = (struct defraghdr *)crctbl - ftot;
319                crc = (ulong *)dhp - 1;
320                if (crc32((uchar *)dhp,
321                        (uchar *)(tdp->spare+lastssize-1) - (uchar *)dhp) == *crc) {
322#if DEFRAG_TEST_ENABLED
323                        printf("TFS: DSI in spare\n");
324#endif
325                        if (scp)
326                                *scp = crctbl;
327                        return(ftot);
328                }
329        }
330        return(0);
331}
332
333/* defragSectorInSpare():
334 * For each sector, run a CRC32 on the content of the spare
335 * using the size of the sector in question.  If the calculated
336 * crc matches that of the table, then we have located the sector
337 * that has been copied to the spare.
338 * This is a pain in the butt because we can't just run a CRC32 on
339 * the spare sector itself because the size of the spare may not match
340 * the size of the sector that was copied to it.  The source sector
341 * might have been smaller; hence when we calculate the CRC32, we need
342 * to use the size of the potential source sector.
343 */
344static int
345defragSectorInSpare(TDEV *tdp, struct sectorcrc *crctbl)
346{
347        uchar   *sbase;
348        struct  defraghdr *dhp;
349        int             i, ssize, snum, ftot;
350
351        sbase = (uchar *)tdp->start;
352        dhp = (struct defraghdr *)crctbl - 1;
353        ftot = dhp->idx + 1;
354
355        for(i=0;i<tdp->sectorcount;i++) {
356                addrtosector(sbase,&snum,&ssize,0);
357                if (i == tdp->sectorcount - 1) {
358                        ssize -=                                                        /* CRC table */
359                                (tdp->sectorcount * sizeof(struct sectorcrc));
360                        ssize -= (ftot * DEFRAGHDRSIZ);         /* DHT table */
361                        ssize -= 4;                                                     /* Crc of the tables */
362                }
363                if (crc32((uchar *)tdp->spare,ssize) == crctbl[i].precrc)
364                        return(snum);
365                sbase += ssize;
366        }
367        return(-1);
368}
369
370/* defragTouchedSectors():
371 * Step through the crc table and TFS flash space to find the first
372 * and last sectors that have been touched by defragmentation.
373 * This is used by defragGetState() to recover from an interrupted
374 * defragmentation, so a few verbose messages are useful to indicate
375 * status to the user.
376 */
377void
378defragTouchedSectors(TDEV *tdp,int *first, int *last)
379{
380        uchar   *sbase;
381        struct  defraghdr *dhp;
382        struct  sectorcrc       *crctbl;
383        int             i, ssize, snum, ftot;
384
385        *first = -1;
386        *last = -1;
387        sbase = (uchar *)tdp->start;
388        crctbl = defragCrcTable(tdp);
389        dhp = (struct defraghdr *)crctbl - 1;
390        ftot = dhp->idx + 1;
391
392        printf("TFS: calculating per-sector crcs... ");
393        for(i=0;i<tdp->sectorcount;i++) {
394                addrtosector(sbase,&snum,&ssize,0);
395                if (i == tdp->sectorcount - 1) {
396                        ssize -=                                                        /* CRC table */
397                                (tdp->sectorcount * sizeof(struct sectorcrc));
398                        ssize -= (ftot * DEFRAGHDRSIZ);         /* DHT table */
399                        ssize -= 4;                                                     /* Crc of the tables */
400                }
401                if (crc32(sbase,ssize) != crctbl[i].precrc) {
402                        if (*first == -1)
403                                *first = snum;
404                        *last = snum;
405                }
406                sbase += ssize;
407                defragTick(0);
408        }
409        printf("done\n");
410        return;
411}
412
413/* defragPostCrcCheck():
414 * Return 1 if the post-crc check of the incoming sector number passes;
415 * else 0.
416 */
417int
418defragPostCrcCheck(TDEV *tdp, int isnum)
419{
420        uchar   *sbase;
421        struct  defraghdr *dhp;
422        struct  sectorcrc *crctbl;
423        int     ftot, i, snum, ssize, lastsnum, lastssize;
424
425        sbase = (uchar *)tdp->start;
426        crctbl = defragCrcTable(tdp);
427        dhp = (struct defraghdr *)crctbl - 1;
428        ftot = dhp->idx + 1;
429
430        addrtosector((uchar *)tdp->end,&lastsnum,&lastssize,0);
431
432        for(i=0;i<tdp->sectorcount;i++) {
433                addrtosector(sbase,&snum,&ssize,0);
434                if (snum == isnum)
435                        break;
436                sbase += ssize;
437        }
438        if (isnum == lastsnum) {
439                ssize -= (tdp->sectorcount * sizeof(struct sectorcrc));
440                ssize -= (ftot * DEFRAGHDRSIZ);
441                ssize -= 4;
442        }
443        if (crctbl[i].postcrc == crc32(sbase,ssize))
444                return(1);
445        else
446                return(0);
447}
448
449/* defragGetStateStr():
450 * Return a string that corresponds to the incoming state value.
451 */
452static char *
453defragGetStateStr(int state)
454{
455        char *str;
456
457        switch(state) {
458        case SECTOR_DEFRAG_INACTIVE:
459                str = "SectorDefragInactive";
460                break;
461        case SECTOR_DEFRAG_ABORT_RESTART:
462                str = "DefragRestartAborted";
463                break;
464        case SCANNING_ACTIVE_SECTOR_1:
465                str = "ScanningActiveSector1";
466                break;
467        case SCANNING_ACTIVE_SECTOR_2:
468                str = "ScanningActiveSector2";
469                break;
470        case SCANNING_ACTIVE_SECTOR_3:
471                str = "ScanningActiveSector3";
472                break;
473        case SCANNING_ACTIVE_SECTOR_4:
474                str = "ScanningActiveSector4";
475                break;
476        case SCANNING_ACTIVE_SECTOR_5:
477                str = "ScanningActiveSector5";
478                break;
479        case SECTOR_DEFRAG_ALMOST_DONE:
480                str = "DefragAlmostDone";
481                break;
482        default:
483                str = "???";
484                break;
485        }
486        return(str);
487}
488
489/* defragRestart():
490 * Poll the console allowing the user to abort the auto-restart of
491 * the defragmentation.  If a character is received on the console,
492 * then return 0 indicating that the defrag should not be restarted;
493 * else return 1.
494 */
495int
496defragRestart(int state,int snum)
497{
498        printf("TFS defrag restart state: %s sector %d\n",
499                defragGetStateStr(state),snum);
500        if (pollConsole("Hit any key to abort..."))
501                return(0);
502        return(1);
503}
504
505/* defragGetState():
506 * Step through the files in the specified device and check for
507 * sanity.  Return SECTOR_DEFRAG_INACTIVE if it is determined that
508 * a defragmentation was not in progress; otherwise, return one of
509 * several different defrag state values depending on what is found
510 * in the TFS flash area.
511 *
512 * NOTE:
513 *   As of Jan 2008, the code wrapped within the ifdef/endif
514 *   ENABLE_FLASHERASED_CHECK_AT_STARTUP is not used by default
515 *   (the macro must be defined in config.h to pull it in).
516 *   This change has been determined to be safe and allows startup
517 *   to be much faster for systems that have a lot of empty TFS
518 *   space.  The code was used to verify that all flash space after
519 *   the last stored file in TFS was actually erased.  If not, then
520 *   it erases it. 
521 *   This turns out to not really be necessary because if tfsadd()
522 *   runs and finds that the area it needs isn't erased, it will
523 *   automatically fall into a tfsclean anyway.  As a result, to
524 *   make startup quicker, this code is not enabled by default.  If
525 *   it is needed, then just define the macro in config.h.
526 *
527 *       As of Mar 2011, thanks to input from Jamie Randall, I'm essentially
528 *       undoing the previous change by defining the
529 *       ENABLE_FLASHERASED_CHECK_AT_STARTUP right here.  Turns out that
530 *       while removal of this snippet of code does make bootup faster for
531 *       those cases where the flash has a large number of sectors, it does
532 *       cause powersafe defrag to fail in certain cases if a hit occurs.
533 *
534 */
535#define ENABLE_FLASHERASED_CHECK_AT_STARTUP             /* see note above */
536
537static int
538defragGetState(TDEV *tdp, int *activesnum)
539{
540        TFILE   *tfp;
541        struct  defraghdr       *dhp;
542        struct  sectorcrc *crctbl;
543        int             snum_in_spare, firstsnum;
544        int             first_touched_snum, last_touched_snum;
545        int             break_cause, break1_cause, spare_is_erased, ftot, ftot1, errstate;
546
547        /* Establish state of spare sector:
548         */
549        spare_is_erased = flasherased((uchar *)tdp->spare,
550                (uchar *)tdp->spare+tdp->sparesize-1);
551
552        ftot = 0;
553        break_cause = break1_cause = 0;
554        for(tfp=(TFILE *)tdp->start; tfp < (TFILE *)tdp->end; tfp=tfp->next) {
555                /* If we are legally at the end of file storage space, then we
556                 * will hit a header size that is ERASED16.  If we reach this
557                 * point and the remaining space dedicated to file storage is
558                 * erased and the spare is erased, it is safe to assume that we
559                 * were not in the middle of a defrag.
560                 */
561                if (tfp->hdrsize == ERASED16) {
562#ifdef ENABLE_FLASHERASED_CHECK_AT_STARTUP      /* (see note above) */
563                        /* Is space from last file to end of TFS space erased? */
564                        if (!flasherased((uchar *)tfp,(uchar *)tdp->end)) {
565                                break_cause = 1;
566                                break;
567                        }
568                        if (!spare_is_erased) {
569                                break_cause = 2;
570                                break;
571                        }
572#if DEFRAG_TEST_ENABLED
573                        printf("\ndefragGetState: inactive_1\n");
574#endif
575#endif
576                        return(SECTOR_DEFRAG_INACTIVE);
577                }
578
579                /* If the crc32 of the header is corrupt, or if the next pointer
580                 * doesn't make any sense, then we must assume that a defrag
581                 * was in progress...
582                 */
583                if (tfshdrcrc(tfp) != tfp->hdrcrc) {
584                        break;
585                }
586
587                if (!(tfp->next) || (tfp->next <= (TFILE *)tdp->start) ||
588                         (tfp->next >= (TFILE *)tdp->end)) {
589                        break;
590                }
591                if (TFS_FILEEXISTS(tfp))
592                        ftot++;
593        }
594        /* If we are here, then something is not "perfect" with the flash
595         * space used by TFS.  If break_cause is non-zero, there is a chance
596         * that the only problem is that a file-write was interrupted and
597         * we did not actually interrupt an in-progress-defrag.  An interrupted
598         * file write would place some incomplete data after the last file.
599         */
600        ftot1 = defragValidDSI(tdp,&crctbl);
601
602        /* If we don't have valid defrag state info (DSI), then we can assume
603         * that the files in TFS have not yet been touched (since if we had
604         * touched them, we would have already successfully created the DSI).
605         * This being the case, then we will not continue with any defrag,
606         * let TFS clean things up when the space is needed.
607         */
608        if (!ftot1) {
609                if (break_cause) {
610                        /* Hmmm... Should something be done here? */
611                }
612#if DEFRAG_TEST_ENABLED
613                printf("\ndefragGetState: inactive_2\n");
614#endif
615                return(SECTOR_DEFRAG_INACTIVE);
616        }
617
618        /* If we get here, then we have a valid defrag header table, so we
619         * can use it and the state of each of the sectors to figure out
620         * where we are in the defragmentation process.  We need to determine
621         * which sector was being worked on at the point in time when the
622         * defragmentation was interrupted.  A sector is in the "touched"
623         * state if a crc32 on its content does not match the crc32 stored
624         * in the crc table above the defrag header table.
625         *
626         * Here we step through the defrag header table and see if each file
627         * in the header table exists in TFS.  If all files exist, then we
628         * must have been very close to completion of the defrag process.
629         */
630        printf("TFS: scanning DSI space... ");
631        dhp = (struct defraghdr *)crctbl - ftot1;
632        while(dhp < (struct defraghdr *)crctbl) {
633                tfp = (TFILE *)dhp->nda;
634                if (tfp->hdrcrc != dhp->ohdrcrc)
635                        break;
636               
637                if (tfshdrcrc(tfp) != tfp->hdrcrc) {
638                        break1_cause = 1;
639                        break;
640                }
641                if (crc32((uchar *)(tfp+1),tfp->filsize) != tfp->filcrc) {
642                        break1_cause = 2;
643                        break;
644                }
645                dhp++;
646                defragTick(0);
647        }
648        printf("done\n");
649
650        /* If we stepped through the entire table, then we've completed the
651         * file relocation process, but we still have to clean up...
652         */
653        if (dhp >= (struct defraghdr *)crctbl) {
654                if (defragRestart(SECTOR_DEFRAG_ALMOST_DONE,0)) {
655                        return(SECTOR_DEFRAG_ALMOST_DONE);
656                }
657                else {
658                        return(SECTOR_DEFRAG_ABORT_RESTART);
659                }
660        }
661       
662        if (addrtosector((unsigned char *)tdp->start,&firstsnum,0,0) < 0) {
663                errstate = 50;
664                goto state_error;
665        }
666        defragTouchedSectors(tdp,&first_touched_snum,&last_touched_snum);
667
668        /* If there are no touched sectors, then we will not continue with
669         * the defrag because we didn't start relocation of any of the files
670         * yet.
671         */
672        if (first_touched_snum == -1) {
673#if DEFRAG_TEST_ENABLED
674                printf("\ndefragGetState: inactive_3\n");
675#endif
676                return(SECTOR_DEFRAG_INACTIVE);
677        }
678
679        if (spare_is_erased)
680                snum_in_spare = -1;
681        else
682                snum_in_spare = defragSectorInSpare(tdp,crctbl);
683
684#if DEFRAG_TEST_ENABLED
685        printf("\ndefragGetState info: %d %d %d\n",
686                first_touched_snum, last_touched_snum, snum_in_spare);
687#endif
688
689        /* At this point we know what sector was the last to be touched.
690         * What we don't know is whether or not the "touch" was completed.
691         * So we don't know if the active sector is last_touched_snum or
692         * last_touched_snum+1.
693         * The only useful piece of data we 'might' have is the fact that
694         * the spare may contain the content of the last touched sector.
695         */
696
697        /* If the spare is erased, it may be because defrag was just getting
698         * ready to start working on the next sector (meaning that the active
699         * sector is last_touched_snum+1) or the sector was in the process of
700         * being modified.  We use the post-crc in the DHT to determine what
701         * the active sector is...
702         */
703        if (spare_is_erased) {
704                if (last_touched_snum >= 0) {
705                        if (defragPostCrcCheck(tdp,last_touched_snum)) {
706                                *activesnum = last_touched_snum + 1;
707
708                                if (defragRestart(SCANNING_ACTIVE_SECTOR_1,*activesnum))
709                                        return(SCANNING_ACTIVE_SECTOR_1);
710                                else
711                                        return(SECTOR_DEFRAG_ABORT_RESTART);
712                        }
713                        else {
714                                if (defragSerase(2,last_touched_snum) < 0) {
715                                        errstate = 51;
716                                        goto state_error;
717                                }
718                                *activesnum = last_touched_snum;
719
720                                if (defragRestart(SCANNING_ACTIVE_SECTOR_2,*activesnum))
721                                        return(SCANNING_ACTIVE_SECTOR_2);
722                                else
723                                        return(SECTOR_DEFRAG_ABORT_RESTART);
724                        }
725
726                }
727                else {
728                        errstate = 52;
729                        goto state_error;
730                }
731        }
732
733        /* If the sector copied to spare is one greater than the last touched
734         * sector, then the active sector is last_touched_snum+1 and it was
735         * just copied to the spare.  In this case we erase the spare and
736         * return indicating the active sector.
737         */
738        if (snum_in_spare == last_touched_snum+1) {
739                if (defragEraseSpare(tdp) < 0) {
740                        errstate = 53;
741                        goto state_error;
742                }
743                *activesnum = snum_in_spare;
744
745                if (defragRestart(SCANNING_ACTIVE_SECTOR_3,*activesnum))
746                        return(SCANNING_ACTIVE_SECTOR_3);
747                else
748                        return(SECTOR_DEFRAG_ABORT_RESTART);
749        }
750
751        /* If the spare is not erased, but it does not match any of the
752         * sector CRCs, then we must have been in the process of copying
753         * the active sector to the spare, so we can erase it and return
754         * to the SCANNING_ACTIVE_SECTOR state.
755         */
756        if (snum_in_spare == -1) {
757                if (last_touched_snum >= 0) {
758                        *activesnum = last_touched_snum + 1;
759
760                        if (!defragRestart(SCANNING_ACTIVE_SECTOR_4,*activesnum))
761                                return(SECTOR_DEFRAG_ABORT_RESTART);
762
763                        if (defragEraseSpare(tdp) < 0) {
764                                errstate = 54;
765                                goto state_error;
766                        }
767                        return(SCANNING_ACTIVE_SECTOR_4);
768                }
769                else {
770                        errstate = 55;
771                        goto state_error;
772                }
773        }
774
775        /* If the sector copied to spare is the number of the last touched
776         * sector, then we were in the middle of modifying the sector, so
777         * we have to erase that sector, copy the spare to it and return
778         * to the scanning state.
779         */
780        if (snum_in_spare == last_touched_snum) {
781                int     ssize;
782                uchar *sbase;
783
784                *activesnum = snum_in_spare;
785
786                if (!defragRestart(SCANNING_ACTIVE_SECTOR_5,*activesnum))
787                        return(SECTOR_DEFRAG_ABORT_RESTART);
788
789                if (defragSerase(3,snum_in_spare) < 0) {
790                        errstate = 56;
791                        goto state_error;
792                }
793                if (sectortoaddr(snum_in_spare,&ssize,&sbase) < 0) {
794                        errstate = 57;
795                        goto state_error;
796                }
797                if (defragFwrite(1,sbase,(uchar *)tdp->spare,ssize) < 0) {
798                        errstate = 58;
799                        goto state_error;
800                }
801                if (defragEraseSpare(tdp) < 0) {
802                        errstate = 59;
803                        goto state_error;
804                }
805                return(SCANNING_ACTIVE_SECTOR_5);
806        }
807
808        /* If we got here, then we are confused, so don't do any defrag
809         * continuation...
810         */
811        errstate = 90;
812
813state_error:
814        printf("DEFRAG_STATE_ERROR: #%d.\n",errstate);
815        return(SECTOR_DEFRAG_INACTIVE);
816}
817
818/* inSector():
819 * We are trying to figure out if the address space that we want to copy
820 * from is within the active sector.  If it is, then we need to adjust
821 * our pointers so that we retrieve the at least some of data from the
822 * spare.
823 * If the range specified by 'i_base' and 'i_size' overlays (in any way)
824 * the address space used by the sector specified by 'snum',
825 * then return the address in the spare and the size of the overlay.
826 */
827static int
828inSector(TDEV *tdp,int snum,uchar *i_base,int i_size,uchar **saddr,int *ovlysz)
829{
830        int             s_size;
831        uchar   *s_base, *s_end, *i_end;
832
833        /* Retrieve information about the sector: */
834        if (sectortoaddr(snum,&s_size,&s_base) == -1)
835                return(TFSERR_MEMFAIL);
836
837        i_end = i_base + i_size;
838        s_end = s_base + s_size;
839
840        if ((i_end < s_base) || (i_base > s_end)) {
841                *ovlysz = 0;
842                return(0);
843        }
844
845        if (i_base < s_base) {
846                if (i_end > s_end) {
847                        *ovlysz = s_size;
848                }
849                else {
850                        *ovlysz = (i_size - (s_base - i_base));
851                }
852                *saddr = (uchar *)tdp->spare;
853        }
854        else {
855                if (i_end > s_end) {
856                        *ovlysz = (i_size - (i_end - s_end));
857                }
858                else {
859                        *ovlysz = i_size;
860                }
861                *saddr = (uchar *)tdp->spare + (i_base - s_base);
862        }
863        return(0);
864}
865
866/* struct fillinfo & FILLMODE definitions:
867 * Structure used by the "Fill" functions below.
868 */
869#define FILLMODE_FWRITE                 1       /* Do the flash write */
870#define FILLMODE_SPAREOVERLAP   2       /* Determine if there is SPARE overlap */
871#define FILLMODE_CRCONLY                3       /* Calculate a 32-bit crc on the data */
872
873struct fillinfo {
874        struct defraghdr *dhp;  /* pointer to defrag header table */
875        TDEV    *tdp;                   /* pointer to TFS device */
876        ulong   crc;                    /* used in FILLMODE_CRCONLY mode */
877        int             crcsz;                  /* size of crc calculation */
878        int             fhdr;                   /* set if we're working on a file header */
879        int             asnum;                  /* the active sector */
880        int             mode;                   /* see FILLMODE_xxx definitions */
881};
882
883/* defragFillFlash():
884 * This function is called by the defragFillActiveSector() function
885 * below.  It covers the four different cases of a file spanning over
886 * the active sector, plus it deals with the possibility that the source
887 * of the file data may be the same sector as the active one (meaning that
888 * the source is taken from the spare).  It is within this function that
889 * the active sector is actually modified and it assumes that the portion
890 * of the active sector to be written to is already erased.
891 *
892 *
893 * SPANTYPE_BCEC:
894 * In this case, the file starts in the active sector and ends in
895 * the active sector...
896 * -----------|----------|----------|----------|---------|---------|----------
897 * |          |          |          |          |         |         |         |
898 * |          |          |<-active->|          |         |         |  SPARE  |
899 * |          |          |  sector  |          |         |         |  SECTOR |
900 * |          |          |          |          |         |         |         |
901 * |          |          | newfile  |          |         |         |         |
902 * |          |          | |<-->|   |          |         |         |         |
903 * -----------|----------|----------|----------|---------|---------|----------
904 *
905 *
906 * SPANTYPE_BPEC:
907 * In this case, the file starts in a sector prior to the currently active
908 * sector and ends in the active sector...
909 * -----------|----------|----------|----------|---------|---------|----------
910 * |          |          |          |          |         |         |         |
911 * |          |          |          |<-active->|         |         |  SPARE  |
912 * |          |          |          |  sector  |         |         |  SECTOR |
913 * |          |          |          |          |         |         |         |
914 * |          |      |<----newfile----->|      |         |         |         |
915 * |          |          |          |          |         |         |         |
916 * -----------|----------|----------|----------|---------|---------|----------
917 *
918 *
919 * SPANTYPE_BPEL:
920 * In this case, the file starts in some sector prior to the currently
921 * active sector and ends in some sector after the currently active
922 * sector...
923 * -----------|----------|----------|----------|---------|---------|----------
924 * |          |          |          |          |         |         |         |
925 * |          |          |<-active->|          |         |         |  SPARE  |
926 * |          |          |  sector  |          |         |         |  SECTOR |
927 * |          |          |          |          |         |         |         |
928 * |       |<---------- newfile------------------->|     |         |         |
929 * |          |          |          |          |         |         |         |
930 * -----------|----------|----------|----------|---------|---------|----------
931 *
932 *
933 * SPANTYPE_BCEL:
934 * In this case, the file starts in the active sector and ends in
935 * a later sector.
936 * -----------|----------|----------|----------|---------|---------|----------
937 * |          |          |          |          |         |         |         |
938 * |          |<-active->|          |          |         |         |  SPARE  |
939 * |          |  sector  |          |          |         |         |  SECTOR |
940 * |          |          |          |          |         |         |         |
941 * |          |      |<----newfile----->|      |         |         |         |
942 * |          |      ****|          |          |         |         |         |
943 * -----------|----------|----------|----------|---------|---------|----------
944 */
945static int
946defragFillFlash(struct fillinfo *fip,int spantype,char **activeaddr,int verbose)
947{
948        char    *hp;
949        TFILE   nfhdr;
950        struct  defraghdr *dhp;
951        int             ohdroffset, nhdroffset;
952        uchar   *ovly, *src, *activesbase;
953        int             ovlysz, srcsz, activessize;
954
955        src = 0;
956        ovly = 0;
957        srcsz = 0;
958        nhdroffset = ohdroffset = 0;
959        dhp = fip->dhp;
960
961        if (verbose >= 2) {
962                printf("   defragFillFlash %s %s (%s %d)\n",fip->fhdr ? "hdr" : "dat",
963                        defragGetSpantypeStr(spantype), dhp->fname,fip->asnum);
964        }
965
966        if (spantype == SPANTYPE_BCEC) {
967                if (fip->fhdr) {
968                        src = (uchar *)dhp->ohdr;
969                        srcsz = TFSHDRSIZ;
970                }
971                else {
972                        src = (uchar *)dhp->ohdr+TFSHDRSIZ;
973                        srcsz = dhp->filsize;
974                }
975        }
976        else if (spantype == SPANTYPE_BPEC) {
977                if (fip->fhdr) {
978                        /* Calculate the offset into the header at which point a
979                         * sector boundary occurs.  Do this for both the old (before
980                         * defrag relocation) and new (after defrag relocation)
981                         * location of the header.
982                         */
983                        /* Changed as of Dec 2010, based on error found by Leon...
984                         * We need to figure out how the header overlaps the sector
985                         * boundary.  Prior to 12/2010, this code did not account for
986                         * the case where the file size spans beyond the currently
987                         * active sector.
988                         */
989                        if ((dhp->neso > dhp->filsize) && (dhp->oeso > dhp->filsize)) {
990                                nhdroffset = TFSHDRSIZ - (dhp->neso - dhp->filsize);
991                                ohdroffset = TFSHDRSIZ - (dhp->oeso - dhp->filsize);
992                                srcsz = (dhp->oeso - dhp->filsize) + (ohdroffset - nhdroffset);
993                                src = (uchar *)dhp->ohdr + nhdroffset;
994                        }
995                        else {
996                                int ssz;
997                                int sno = dhp->nesn;
998                                int fsz = dhp->filsize;
999                                while(sno > fip->asnum) {
1000                                        if (sectortoaddr(sno,&ssz,0) < 0)
1001                                                return(TFSERR_MEMFAIL);
1002                                        if (fsz == dhp->filsize)
1003                                                fsz -= dhp->neso;
1004                                        else
1005                                                fsz -= ssz;
1006                                        sno--;
1007                                }
1008                                if (sectortoaddr(fip->asnum,&ssz,0) < 0)
1009                                        return(TFSERR_MEMFAIL);
1010                                srcsz = ssz - fsz;
1011                                src = (uchar *)dhp->ohdr;
1012                                src += (TFSHDRSIZ-srcsz);
1013                                nhdroffset = (TFSHDRSIZ-srcsz);
1014                        }
1015                }
1016                else {
1017                        src = (uchar *)dhp->ohdr + TFSHDRSIZ + (dhp->filsize - dhp->neso);
1018                        srcsz = dhp->neso;
1019                }
1020        }
1021        else if (spantype == SPANTYPE_BCEL) {
1022                if (sectortoaddr(fip->asnum,&activessize,&activesbase) == -1)
1023                        return(TFSERR_MEMFAIL);
1024
1025                if (fip->fhdr) {
1026                        src = (uchar *)dhp->ohdr;
1027                }
1028                else {
1029                        src = (uchar *)dhp->ohdr+TFSHDRSIZ;
1030                }
1031                srcsz = (activesbase + activessize) - (uchar *)*activeaddr;
1032        }
1033        else if (spantype == SPANTYPE_BPEL) {
1034                if (sectortoaddr(fip->asnum,&activessize,0) == -1)
1035                        return(TFSERR_MEMFAIL);
1036
1037                if (fip->fhdr) {
1038                        src = (uchar *)dhp->ohdr;
1039                }
1040                else {
1041                        src = (uchar *)dhp->ohdr+TFSHDRSIZ;
1042                }
1043
1044                src += ((*activeaddr - dhp->nda) - TFSHDRSIZ);
1045                srcsz = activessize;
1046        }
1047        else {
1048                return(0);
1049        }
1050
1051        /* Do some error checking on the computed size:
1052         */
1053        if (srcsz < 0) {
1054                printf("defragFillFlash: srcsz < 0\n");
1055                return(TFSERR_MEMFAIL);
1056        }
1057
1058        if (fip->fhdr) {
1059                if (srcsz > TFSHDRSIZ) {
1060                        printf("defragFillFlash: srcsz > TFSHDRSIZ\n");
1061                        return(TFSERR_MEMFAIL);
1062                }
1063        }
1064        else {
1065                if (srcsz > dhp->filsize) {
1066                        printf("defragFillFlash: srcsz > filsize\n");
1067                        return(TFSERR_MEMFAIL);
1068                }
1069        }
1070
1071        /* Determine if any portion of the source was part of the sector that
1072         * is now the active sector..  If yes (ovlysz > 0), then we must
1073         * deal with the fact that some (or all) of the fill source is in the
1074         * spare sector...
1075         */
1076        if (inSector(fip->tdp,fip->asnum,src,srcsz,&ovly,&ovlysz) < 0)
1077                return(TFSERR_MEMFAIL);
1078
1079        /* If the mode is not FILLMODE_FWRITE, then we don't do any of the
1080         * flash operations.  We are in this function only to determine
1081         * if we need to copy the active sector to the spare prior to
1082         * starting the modification of the active sector.
1083         */
1084        if (fip->mode == FILLMODE_FWRITE) {
1085                if (fip->fhdr) {
1086                        hp = (char *)&nfhdr;
1087                        if (ovlysz) {
1088                                memcpy((char *)hp+nhdroffset,(char *)ovly,ovlysz);
1089                                if (ovlysz != srcsz) {
1090                                        memcpy(hp+nhdroffset+ovlysz,(char *)src+ovlysz,
1091                                                srcsz-ovlysz);
1092                                }
1093                        }
1094                        else {
1095                                /* next line was <nfhdr = *dhp->ohdr> ... */
1096                                memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE));
1097                        }
1098                        nfhdr.next = dhp->nextfile;
1099                        if (defragFwrite(2,(uchar *)*activeaddr,(uchar *)hp+nhdroffset,srcsz) == -1)
1100                                return(TFSERR_FLASHFAILURE);
1101                }
1102                else {
1103                        if (ovlysz) {
1104                                if (defragFwrite(3,(uchar *)*activeaddr,(uchar *)ovly,ovlysz) == -1)
1105                                        return(TFSERR_FLASHFAILURE);
1106                                if (ovlysz != srcsz) {
1107                                        if (defragFwrite(4,(uchar *)*activeaddr+ovlysz,(uchar *)src+ovlysz,
1108                                                srcsz-ovlysz) == -1)
1109                                                return(TFSERR_FLASHFAILURE);
1110                                }
1111                        }
1112                        else {
1113                                if (defragFwrite(5,(uchar *)*activeaddr,(uchar *)src,srcsz) == -1)
1114                                        return(TFSERR_FLASHFAILURE);
1115                        }
1116                }
1117        }
1118        else if (fip->mode == FILLMODE_CRCONLY) {
1119                register uchar  *bp;
1120                int             sz, temp;
1121
1122                if (fip->fhdr) {
1123                        hp = (char *)&nfhdr;
1124                        /* next line was <nfhdr = *dhp->ohdr> ... */
1125                        memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE));
1126                        nfhdr.next = dhp->nextfile;
1127                        bp = (uchar *)hp + nhdroffset;
1128                }
1129                else {
1130                        bp = (uchar *)src;
1131                }
1132                sz = srcsz;
1133                fip->crcsz += sz;
1134                while(sz) {
1135                        temp = (fip->crc ^ *bp++) & 0x000000FFL;
1136                        fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp];
1137                        sz--;
1138                }
1139        }
1140        *activeaddr += srcsz;
1141
1142        if ((spantype == SPANTYPE_BCEC || spantype == SPANTYPE_BPEC) &&
1143                (!fip->fhdr) && ((ulong)*activeaddr & 0xf)) {
1144                int             sz, temp, modfixsize;
1145
1146                modfixsize = (TFS_FSIZEMOD - ((ulong)*activeaddr & (TFS_FSIZEMOD-1)));
1147                *activeaddr += modfixsize;
1148                if (fip->mode == FILLMODE_CRCONLY) {
1149                        sz = modfixsize;
1150                        fip->crcsz += sz;
1151                        while(sz) {
1152                                temp = (fip->crc ^ 0xff) & 0x000000FFL;
1153                                fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp];
1154                                sz--;
1155                        }
1156                }
1157        }
1158
1159        /* Return ovlysz so that the caller will know if this function
1160         * needed the spare sector.  This is used in the "mode = SPARE_OVERLAP"
1161         * pass of defragFillActiveSector().
1162         */
1163        return(ovlysz);
1164}
1165
1166/* defragFillActiveSector():
1167 * This and defragFillFlash() are the workhorses of the tfsclean() function.
1168 * The bulk of this function is used to determine if we need to do anything
1169 * to the active sector and if so, do we need to copy the active sector to
1170 * the spare prior to erasing it.
1171 * The first loop in this function determines whether we need to do anything
1172 * at all with this sector (it may not be touched by the defragmentation).
1173 * The second loop determines if we have to copy the active sector to the
1174 * spare prior to erasing the active sector.
1175 * The final loop in this function does the call to defragFillFlash()
1176 * to do the actual flash writes.
1177 */
1178static int
1179defragFillActiveSector(TDEV *tdp, int ftot, int snum, int verbose)
1180{
1181        int             firstsnum;              /* number of first TFS sector */
1182        int             activesnum;             /* number of sector currently being written to */
1183        int             activessize;    /* size of active sector */
1184        char    *activeaddr;    /* offset being written to in the active sector */
1185        uchar   *activesbase;   /* base address of active sector */
1186        char    *activesend;    /* end address of active sector */
1187        struct  defraghdr *sdhp;/* pointer into defrag hdr table in spare */
1188        struct  defraghdr *dhp; /* pointer into defrag header table */
1189        int             fullsize;               /* size of file and header */
1190        char    *new_dend;              /* new end of data */
1191        char    *new_dbase;             /* new base of data */
1192        char    *new_hend;              /* new end of header */
1193        char    *new_hbase;             /* new base of header */
1194        char    *new_fend;              /* new end of file */
1195        char    *new_fbase;             /* new base of file */
1196        int             new_fspan;              /* span type for new file */
1197        int             new_hspan;              /* span type for new header */
1198        int             new_dspan;              /* span type for new data */
1199        int             fillstat;               /* result of defragFillFlash() function call */
1200        int             noreloctot;             /* number of files spanning the active sector */
1201                                                        /* that do not have to be relocated */
1202        int             tmptot;                 /* temps used for the "SPARE_OVERLAP" mode */
1203        char    *tmpactiveaddr;
1204        struct  defraghdr *tmpdhp;
1205        struct  fillinfo finfo;
1206        struct  sectorcrc       *crctbl;
1207        int             lastsnum, tot;
1208        int             copytospare;
1209        int             lastfileisnotrelocated;
1210
1211        /* Retrieve number of first TFS sector: */
1212        if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0)
1213                return(TFSERR_MEMFAIL);
1214
1215        activesnum = snum + firstsnum;
1216        crctbl = defragCrcTable(tdp);
1217
1218        /* Retrieve information about active sector: */
1219        if (sectortoaddr(activesnum,&activessize,&activesbase) == -1)
1220                return(TFSERR_MEMFAIL);
1221
1222        if (verbose)
1223                printf(" Active sector: %3d @ 0x%lx\n",activesnum,(ulong)activesbase);
1224
1225        if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0)
1226                return(TFSERR_MEMFAIL);
1227
1228        /* Establish a pointer to the defrag header table.
1229         * For the case when the active sector is the last sector, the defrag
1230         * header table will be in the spare, so we also establish a pointer
1231         * to that space...
1232         */
1233        dhp = (struct defraghdr *)crctbl;
1234        dhp -= ftot;
1235        sdhp = (struct defraghdr *)(tdp->spare+activessize -
1236                        (tdp->sectorcount * sizeof(struct sectorcrc)));
1237        sdhp -= ftot;
1238
1239        activeaddr = (char *)activesbase;
1240        tmpactiveaddr = (char *)activesbase;
1241        activesend = (char *)activesbase + activessize - 1;
1242
1243        /* FIRST LOOP:
1244         * See if we need to do anything...
1245         * In this state, we are simply checking to see if anything is going
1246         * to cause the currently active sector to be written to.
1247         * If yes, then we need to copy it to the spare and start the
1248         * modification process; else, we just return and do nothing
1249         * to this sector.
1250         * For each file in the defrag header table that is destined for
1251         * the address space occupied by the currently active sector, copy
1252         * that file (header and data) to the active sector...
1253         * Note that it may only be a partial copy, depending on the size
1254         * of the file and the amount of space left in the active sector.
1255         */
1256
1257        noreloctot = 0;
1258        new_fspan = SPANTYPE_UNDEF;
1259        lastfileisnotrelocated = 0;
1260        for(tot=0;tot<ftot;tot++,dhp++,sdhp++) {
1261                fullsize = TFSHDRSIZ + dhp->filsize;
1262                new_fbase = dhp->nda;
1263                new_fend = (new_fbase + fullsize);
1264
1265                /* We must figure out how the new version of the file will
1266                 * span across the active sector.
1267                 * See defragGetSpantype() for details.
1268                 */
1269                new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1270                        (char *)new_fbase,(char *)new_fend);
1271
1272                /* If the file we are looking at entirely spans a sector that is
1273                 * prior to the currently active sector, then we just continue
1274                 * through the list.
1275                 * If the file entirely spans a sector that is after the
1276                 * currently active sector, then we are done with this active sector. 
1277                 * If the file falls within the active sector in any way, and its
1278                 * new location does not match its old location, then we
1279                 * break out of this loop and begin the modification of this
1280                 * active sector...
1281                 */
1282                if (new_fspan == SPANTYPE_BLEL)
1283                        return(0);
1284               
1285                if (new_fspan != SPANTYPE_BPEP) {
1286                        if (dhp->nda == (char *)dhp->ohdr) {
1287                                noreloctot++;
1288                                if (tot == ftot-1) {
1289                                        lastfileisnotrelocated = 1;
1290                                        if (verbose > 1)
1291                                                printf("  last file not relocated\n");
1292                                }
1293                        }
1294                        else
1295                                break;
1296                }
1297        }
1298
1299        /* If tot == ftot, then we got through the entire loop above without
1300         * finding a file that needs to be relocated into this active sector.
1301         * This means one of two things: either all the files fall into a
1302         * sector prior to this active sector, or the files in this active
1303         * sector do not need to be relocated.  In either case, we simply
1304         * return without touching this sector.
1305         * Note that we also keep track of the possibility that the last file
1306         * may not be relocated.  If this ends up to be the case, then we are
1307         * simply cleaning up one or more dead files after a full set of active
1308         * files, so we should clean up the sector.
1309         */
1310        if ((tot == ftot) && (lastfileisnotrelocated == 0))
1311                return(0);
1312
1313        /* If tot != ftot, then we must subtract noreloctot from tot so that
1314         * we establish 'tot' as the index into the first file that must be
1315         * copied to the active sector...
1316         */
1317        if (noreloctot) {
1318                tot -= noreloctot;
1319                dhp -= noreloctot;
1320                sdhp -= noreloctot;
1321        }
1322
1323        /* Exit immediately before cleaning up the spare... */
1324        defragExitTestPoint(10000+activesnum);
1325
1326        /* Since we got here, we know that we have to do some work on the
1327         * currently active sector.  We may not have to copy it to the spare,
1328         * but we will erase the spare anyway because the sector erase is
1329         * supposed to be smart enough to avoid the erase if it is already
1330         * erased.  This should be handled by the flash driver because in
1331         * ALL cases the erase should be avoided if possible.
1332         */
1333        if (defragEraseSpare(tdp) < 0)
1334                return(TFSERR_FLASHFAILURE);
1335
1336        /* Exit immediately after cleaning up the spare... */
1337        defragExitTestPoint(10001+activesnum);
1338
1339        /* If the active sector is the last sector (which would contain the
1340         * defrag header table), then we reference the copy of the table that
1341         * is in the spare...
1342         * Also, if this is the last sector, then we HAVE to copy it to
1343         * spare, so we can skip the 2nd loop that attempts to determine
1344         * if we need to do it.
1345         */
1346        if (activesnum == lastsnum) {
1347                dhp = sdhp;
1348                copytospare = 1;
1349        }
1350        else {
1351                /* SECOND LOOP:
1352                 * See if we need to copy the active sector to the spare...
1353                 * We do this by continuing the loop we started above.  Notice that
1354                 * we do an almost identical loop again below this.
1355                 * On this pass through the loop we are only checking to see if it is
1356                 * necessary to copy this active sector to the spare.
1357                 */
1358                tmptot = tot;
1359                tmpdhp = dhp;
1360                copytospare = 0;
1361                finfo.mode = FILLMODE_SPAREOVERLAP;
1362                for(;tmptot<ftot;tmptot++,tmpdhp++) {
1363                        finfo.tdp = tdp;
1364                        finfo.dhp = tmpdhp;
1365                        finfo.asnum = activesnum;
1366       
1367                        fullsize = TFSHDRSIZ + tmpdhp->filsize;
1368                        new_fbase = tmpdhp->nda;
1369                        new_fend = (new_fbase + fullsize);
1370       
1371                        new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1372                                (char *)new_fbase,(char *)new_fend);
1373       
1374                        if (new_fspan == SPANTYPE_BPEP)
1375                                continue;
1376                        else if (new_fspan == SPANTYPE_BLEL)
1377                                break;
1378       
1379                        /* Now retrieve span information about header and data
1380                         * portions of the file (new and orig)...
1381                         */
1382                        new_hbase = new_fbase;
1383                        new_hend = new_hbase + TFSHDRSIZ;
1384                        new_dbase = new_hbase + TFSHDRSIZ;
1385                        new_dend = new_fend;
1386       
1387                        new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1388                                (char *)new_hbase,(char *)new_hend);
1389                        new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1390                                (char *)new_dbase,(char *)new_dend);
1391       
1392                        /* If defragFillFlash() returns positive (with mode ==
1393                         * FILLMODE_SPAREOVERLAP set above), then we know that the
1394                         * spare sector must be loaded with a copy of this active
1395                         * sector, so we can break out of this loop at that point...
1396                         */
1397                        finfo.fhdr = 1;
1398                        fillstat = defragFillFlash(&finfo,new_hspan,&tmpactiveaddr,verbose);
1399                        if (fillstat < 0)
1400                                return(fillstat);       
1401                        if (fillstat > 0) {
1402                                copytospare = 1;
1403                                break;
1404                        }
1405                        if (new_hspan == SPANTYPE_BCEL)
1406                                break;
1407       
1408                        finfo.fhdr = 0;
1409                        fillstat = defragFillFlash(&finfo,new_dspan,&tmpactiveaddr,verbose);
1410                        if (fillstat < 0)
1411                                return(fillstat);       
1412                        if (fillstat > 0) {
1413                                copytospare = 1;
1414                                break;
1415                        }
1416                        if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL)
1417                                break;
1418                }
1419        }
1420
1421        finfo.mode = FILLMODE_FWRITE;
1422
1423        defragExitTestPoint(10002+activesnum);
1424
1425        if (copytospare) {
1426                defragTick(verbose);
1427#if DEFRAG_TEST_ENABLED
1428                printf("     copying sector %d to spare\n",activesnum);
1429#endif
1430                if (defragFwrite(6,(uchar *)tdp->spare,activesbase,activessize) == -1) {
1431                        printf("Failed to copy active %d to spare\n",activesnum);
1432                        return(TFSERR_FLASHFAILURE);
1433                }
1434        }
1435#if DEFRAG_TEST_ENABLED
1436        else {
1437                printf("     copy saved\n");
1438        }
1439#endif
1440
1441        defragTick(verbose);
1442
1443        /* We can now begin actual modification of the active sector,
1444         * so start off by eraseing it...
1445         */
1446        defragExitTestPoint(10003+activesnum);
1447
1448        if (defragSerase(4,activesnum) < 0)
1449                return(TFSERR_FLASHFAILURE);
1450
1451        defragExitTestPoint(10004+activesnum);
1452
1453        /* THIRD LOOP:
1454         * Now we pass through the loop to do the real flash modifications...
1455         */
1456        for(;tot<ftot;tot++,dhp++) {
1457                finfo.tdp = tdp;
1458                finfo.dhp = dhp;
1459                finfo.asnum = activesnum;
1460
1461                fullsize = TFSHDRSIZ + dhp->filsize;
1462                new_fbase = dhp->nda;
1463                new_fend = (new_fbase + fullsize);
1464
1465                new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1466                        (char *)new_fbase,(char *)new_fend);
1467
1468                if (new_fspan == SPANTYPE_BPEP)
1469                        continue;
1470                else if (new_fspan == SPANTYPE_BLEL)
1471                        break;
1472
1473                if (verbose)
1474                        printf("  File: %s\n",dhp->fname);
1475
1476                /* Now retrieve span information about header and data
1477                 * portions of the file (new and orig)...
1478                 */
1479                new_hbase = new_fbase;
1480                new_hend = new_hbase + TFSHDRSIZ;
1481                new_dbase = new_hbase + TFSHDRSIZ;
1482                new_dend = new_fend;
1483
1484                new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1485                        (char *)new_hbase,(char *)new_hend);
1486                new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1487                        (char *)new_dbase,(char *)new_dend);
1488
1489                /* At this point we have all the information we need to copy
1490                 * the appropriate amount of the file from orignal space
1491                 * to new space.
1492                 * We have to break the write up into two parts, the header
1493                 * (new_hspan) and the data (new_dspan) so we have to look
1494                 * at the spantype for each to determine what part of the
1495                 * header and/or data we are going to copy.
1496                 *
1497                 * Also, we must consider the possibility that the source
1498                 * data may be in the spare sector.  This would be the case
1499                 * if the active sector is the same sector that the original
1500                 * data was in.  If the source data is in the spare sector,
1501                 * then an added complication is the fact that it may not
1502                 * all be there, we may have to copy some from the spare,
1503                 * then some from the original space.
1504                 */
1505                finfo.fhdr = 1;
1506                fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose);
1507                if (fillstat < 0)
1508                        return(fillstat);       
1509                if (new_hspan == SPANTYPE_BCEL)
1510                        break;
1511
1512                finfo.fhdr = 0;
1513                fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose);
1514                if (fillstat < 0)
1515                        return(fillstat);       
1516                if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL)
1517                        break;
1518                defragTick(verbose);
1519        }
1520        return(0);
1521}
1522
1523static int
1524defragNewSectorCrc(TDEV *tdp, struct defraghdr *dht, int snum,
1525        ulong *newcrc, int verbose)
1526{
1527        int             firstsnum;              /* number of first TFS sector */
1528        int             activesnum;             /* number of sector currently being written to */
1529        int             activessize;    /* size of active sector */
1530        char    *activeaddr;    /* offset being written to in the active sector */
1531        uchar   *activesbase;   /* base address of active sector */
1532        char    *activesend;    /* end address of active sector */
1533        struct  defraghdr *dhp; /* pointer into defrag header table */
1534        int             fullsize;               /* size of file and header */
1535        char    *new_dend;              /* new end of data */
1536        char    *new_dbase;             /* new base of data */
1537        char    *new_hend;              /* new end of header */
1538        char    *new_hbase;             /* new base of header */
1539        char    *new_fend;              /* new end of file */
1540        char    *new_fbase;             /* new base of file */
1541        int             new_fspan;              /* span type for new file */
1542        int             new_hspan;              /* span type for new header */
1543        int             new_dspan;              /* span type for new data */
1544        int             fillstat;               /* result of defragFillFlash() function call */
1545        int             ftot;
1546        struct  fillinfo finfo;
1547        struct  sectorcrc       *crctbl;
1548        int             lastsnum, tot, sz, temp;
1549
1550        /* Retrieve number of first TFS sector: */
1551        if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0)
1552                return(TFSERR_MEMFAIL);
1553
1554        activesnum = snum + firstsnum;
1555        crctbl = defragCrcTable(tdp);
1556
1557        /* Retrieve information about active sector: */
1558        if (sectortoaddr(activesnum,&activessize,&activesbase) == -1)
1559                return(TFSERR_MEMFAIL);
1560
1561        if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0)
1562                return(TFSERR_MEMFAIL);
1563
1564        dhp = (struct defraghdr *)crctbl - 1;
1565        ftot = dhp->idx + 1;
1566        dhp = dht;
1567        activeaddr = (char *)activesbase;
1568        activesend = (char *)activesbase + activessize - 1;
1569
1570        finfo.tdp = tdp;
1571        finfo.crcsz = 0;
1572        finfo.crc = 0xffffffff;
1573        finfo.asnum = activesnum;
1574        finfo.mode = FILLMODE_CRCONLY;
1575
1576        for(tot=0;tot<ftot;tot++,dhp++) {
1577                finfo.dhp = dhp;
1578
1579                fullsize = TFSHDRSIZ + dhp->filsize;
1580                new_fbase = dhp->nda;
1581                new_fend = (new_fbase + fullsize);
1582
1583                new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1584                        (char *)new_fbase,(char *)new_fend);
1585
1586                if (new_fspan == SPANTYPE_BPEP)
1587                        continue;
1588                else if (new_fspan == SPANTYPE_BLEL)
1589                        break;
1590
1591                /* Now retrieve span information about header and data
1592                 * portions of the file (new and orig)...
1593                 */
1594                new_hbase = new_fbase;
1595                new_hend = new_hbase + TFSHDRSIZ;
1596                new_dbase = new_hbase + TFSHDRSIZ;
1597                new_dend = new_fend;
1598
1599                new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1600                        (char *)new_hbase,(char *)new_hend);
1601                new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend,
1602                        (char *)new_dbase,(char *)new_dend);
1603
1604                finfo.fhdr = 1;
1605                fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose);
1606                if (fillstat < 0)
1607                        return(fillstat);       
1608                if (new_hspan == SPANTYPE_BCEL)
1609                        break;
1610
1611                finfo.fhdr = 0;
1612                fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose);
1613                if (fillstat < 0)
1614                        return(fillstat);       
1615                if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL)
1616                        break;
1617        }
1618        sz = activessize - finfo.crcsz;
1619
1620        /* If this is the last sector, then we must not include the space used
1621         * for defrag state storage in the crc calculation.
1622         * We deduct size of CRC table, DHT table and the crc of the DSI space...
1623         */
1624        if (activesnum == lastsnum) {
1625                sz -= (tdp->sectorcount * sizeof(struct sectorcrc));   
1626                sz -= (ftot * DEFRAGHDRSIZ);
1627                sz -= 4;
1628        }
1629        while(sz) {
1630                temp = (finfo.crc ^ 0xff) & 0x000000FFL;
1631                finfo.crc = ((finfo.crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp];
1632                sz--;
1633        }
1634        *newcrc = ~finfo.crc;
1635        return(0);
1636}
1637
1638/* defragBuildCrcTable():
1639 * Build the table of sector crcs.
1640 * This consists of a set of CRCs representing each sector
1641 * before defrag starts and after defrag has completed. 
1642 * One set for each sector.  This table is then used if the
1643 * defrag process is interrupted to determine the state of
1644 * the interrupted defragmentation process.
1645 */
1646int
1647defragBuildCrcTable(TDEV *tdp, struct defraghdr *dht, int verbose)
1648{
1649        ulong   crc;
1650        uchar   *sbase;
1651        int             i, ssize, dhstsize;
1652        struct  sectorcrc *crctbl;
1653
1654        dhstsize = (ulong)(tdp->end+1) - (ulong)dht + 4;
1655        crctbl = defragCrcTable(tdp);
1656
1657        /* The pre-defrag crc table...
1658         * This one's easy because it is simply a crc for each of the current
1659         * sectors.
1660         */
1661        sbase = (uchar *)tdp->start;
1662        for(i=0;i<tdp->sectorcount;i++) {
1663                if (addrtosector(sbase,0,&ssize,0) < 0)
1664                        return(-1);
1665
1666                if (i == tdp->sectorcount-1)
1667                        ssize -= dhstsize;
1668               
1669                /* The pre-defrag crc: */
1670                crc = crc32(sbase,ssize);
1671                if (defragFwrite(7,(uchar *)&crctbl[i].precrc,
1672                        (uchar *)&crc,4) == -1) {
1673                        return(-1);
1674                }
1675
1676                /* The post-defrag crc: */
1677                if (defragNewSectorCrc(tdp,dht,i,&crc,verbose) < 0)
1678                        return(-1);
1679
1680                if (defragFwrite(8,(uchar *)&crctbl[i].postcrc,
1681                        (uchar *)&crc,4) == -1) {
1682                        return(-1);
1683                }
1684
1685                sbase += ssize;
1686
1687                defragTick(0);
1688        }
1689        return(0);
1690}
1691
1692/* _tfsclean():
1693 * This is the front-end of the defragmentation process, following are the
1694 * basic steps of defragmentation...
1695 *
1696 * Build the Defrag State Information (DSI) area:
1697 * 1. Create a table of 32-bit CRCs, two for each sector.  One is the CRC
1698 *        of the sector prior to beginning defragmentation and the other is
1699 *        what will be the CRC of the sector after defragmentation has completed.
1700 *        These CRCs are used to help recover from an interrupted defragmentation.
1701 * 2. Create a table of struct defraghdr structures, one for each file in
1702 *        TFS that is currently active (not dead).
1703 * 3. Create a CRC of the tables created in steps 1 & 2.
1704 *
1705 * The data created in steps 1-3 is stored at the end of the last sector
1706 * used by TFS for file storage.  After this is created, the actual flash
1707 * defragmentation process starts.
1708 *
1709 * File relocation:
1710 * 4. Step through each sector in TFS flash space, process each file whose
1711 *        relocated space overlaps with that sector.  As each sector is being
1712 *        re-built, the original version of that sector is stored in the spare.
1713 *
1714 * End of flash cleanup:
1715 * 5. Run through the remaining, now unsused, space in TFS flash and make
1716 *        sure it is erased.
1717 *
1718 * File check:
1719 * 6. Run a check of all of the relocated files to make sure everything is
1720 *        still sane.
1721 *
1722 * Defragmentation success depends on some coordination with tfsadd()...
1723 * Whenever a file is added to TFS, tfsadd() must verify that the space
1724 * needed for defrag overhead (defrag state & header tables) will be
1725 * available.  Also, tfsadd() must make sure that the defrag overhead will
1726 * always fit into one sector (the sector just prior to the spare).
1727 */
1728
1729int
1730_tfsclean(TDEV *tdp, int restart, int verbose)
1731{
1732        int             dhstsize;               /* Size of state table overhead */
1733        int             firstsnum;              /* Number of first sector in TFS device. */
1734        int             lastsnum;               /* Number of last sector in TFS device. */
1735        int             lastssize;              /* Size of last sector in TFS device. */
1736        uchar   *lastsbase;             /* Base address of last sector in TFS device. */
1737        int             sectorcheck;    /* Used to verify proper TFS configuration. */
1738        struct  defraghdr *dht; /* Pointer to defrag header table. */
1739        int             chkstat;                /* Result of tfscheck() after defrag is done. */
1740        int             ftot;                   /* Total number of active files in TFS. */
1741        int             dtot;                   /* Total number of deleted files in TFS. */
1742        int             fcnt;                   /* Running file total, used in hdrtbl build. */
1743        TFILE   *tfp;                   /* Misc file pointer */
1744        char    *newaddress;    /* Used to calculate "new" location of file. */
1745        struct  defraghdr       dfhdr;  /* Used to build defrag header table. */
1746        int             activesnum;             /* Sector being worked on restarted defrag. */
1747        struct  sectorcrc       *crctbl;        /* Pointer to table of per-sector crcs. */
1748        int             defrag_state;
1749        int             sidx, snum;
1750        char    *end;
1751       
1752        if (TfsCleanEnable < 0)
1753                return(TFSERR_CLEANOFF);
1754
1755        /* If incoming TFS device pointer is NULL, return error
1756         */
1757        if (!tdp)
1758                return(TFSERR_BADARG);
1759
1760        activesnum = 0;
1761
1762        /* If the 'restart' flag is set, then we only want to do a defrag if
1763         * we determine that one is already in progress; so we have to look at
1764         * the current state of the defrag state table to figure out if a defrag
1765         * was active.  If not, just return.
1766         */
1767        if (restart) {
1768                defrag_state = defragGetState(tdp,&activesnum);
1769                switch(defrag_state) {
1770                        case SECTOR_DEFRAG_INACTIVE:
1771                        case SECTOR_DEFRAG_ABORT_RESTART:
1772                                return(TFS_OKAY);
1773                        case SCANNING_ACTIVE_SECTOR_1:
1774                        case SCANNING_ACTIVE_SECTOR_2:
1775                        case SCANNING_ACTIVE_SECTOR_3:
1776                        case SCANNING_ACTIVE_SECTOR_4:
1777                        case SCANNING_ACTIVE_SECTOR_5:
1778                                defrag_state = SCANNING_ACTIVE_SECTOR;
1779                                break;
1780                }
1781        }
1782        else {
1783                defrag_state = SECTOR_DEFRAG_INACTIVE;
1784        }
1785
1786        if (verbose || restart || (!MFLAGS_NODEFRAGPRN())) {
1787                printf("TFS device '%s' powersafe defragmentation\n",tdp->prefix);
1788                if ((restart) && pollConsole("ok?")) {
1789                        printf("aborted\n");
1790                        return(TFS_OKAY);
1791                }
1792        }
1793
1794        if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0)
1795                return(TFSERR_MEMFAIL);
1796        lastsnum = firstsnum + tdp->sectorcount - 1;
1797        if (addrtosector((uchar *)tdp->end,&sectorcheck,0,0) < 0)
1798                return(TFSERR_MEMFAIL);
1799        if (lastsnum != sectorcheck) {
1800                /* If this error occurs, it is an indication that TFS was not
1801                 * properly configured in config.h, this error should not occur
1802                 * if TFS is properly configured.
1803                 */
1804                printf("%s: SECTORCOUNT != TFSSTART <-> TFSEND\n", tdp->prefix);
1805                printf("First TFS sector = %d, last = %d\n",firstsnum,sectorcheck);
1806                return(TFSERR_MEMFAIL);
1807        }
1808
1809        if (defrag_state == SECTOR_DEFRAG_INACTIVE) {
1810                activesnum = firstsnum;
1811        }
1812
1813        /* Retrieve information about last sector:
1814         */
1815        if (sectortoaddr(lastsnum,&lastssize,&lastsbase) == -1)
1816                return(TFSERR_MEMFAIL);
1817
1818        /* Establish a pointer to a table of CRCs that will contain
1819         * one 32-bit CRC for each sector (prior to starting the defrag).
1820         */
1821        crctbl = defragCrcTable(tdp);
1822
1823        /* Retrieve the number of "dead" and "living" files:
1824         * If there are no dead files, then there is no need to defrag.
1825         * If there are no "living" files, then we can just init the flash.
1826         */
1827        ftot = dtot = 0;
1828        if (restart && defragValidDSI(tdp,0)) {
1829                dht = (struct defraghdr *)crctbl - 1;
1830                ftot = dht->idx + 1;
1831        }
1832        else {
1833                tfp = (TFILE *)tdp->start;
1834                while(validtfshdr(tfp)) {
1835                        if (TFS_FILEEXISTS(tfp))
1836                                ftot++;
1837                        else
1838                                dtot++;
1839                        tfp = nextfp(tfp,tdp);
1840                }
1841                if (dtot == 0) {
1842                        if (verbose)
1843                                printf("No dead files in %s.\n",tdp->prefix);
1844                        if (tfsflasherased(tdp,verbose))
1845                                return(0);
1846                        if (verbose)
1847                                printf("Cleaning up end of flash...\n");
1848                }
1849        }
1850        if (ftot == 0) {
1851                if (verbose)
1852                        printf("No active files detected, erasing all %s flash...\n",
1853                                tdp->prefix);
1854                _tfsinit(tdp);
1855                return(0);
1856        }
1857
1858        /* Now that we know how many files are in TFS, we can establish
1859         * a pointer to the defrag header table, and the size of the table...
1860         */
1861        dht = (struct defraghdr *)crctbl - ftot;
1862        dhstsize = (ulong)(tdp->end+1) - (ulong)dht;
1863        dhstsize += 4; /* Account for the CRC of the state tables. */
1864
1865        if (defrag_state == SECTOR_DEFRAG_INACTIVE) {
1866                ulong   crc;
1867
1868                if (verbose) {
1869                        printf("TFS defrag: building DSI space...\n");
1870                }
1871
1872                /* We start by making sure that the space needed by the
1873                 * defrag header and state table at the end of the last
1874                 * sector is clear...
1875                 */
1876                if (!flasherased((uchar *)dht, (uchar *)(tdp->end))) {
1877                        if (defragEraseSpare(tdp) < 0)
1878                                return(TFSERR_FLASHFAILURE);
1879
1880                        if (defragFwrite(9,(uchar *)(tdp->spare),lastsbase,
1881                                lastssize-dhstsize) == -1) {
1882                                return(TFSERR_FLASHFAILURE);
1883                        }
1884                        if (defragSerase(5,lastsnum) < 0) {
1885                                return(TFSERR_FLASHFAILURE);
1886                        }
1887                        if (defragFwrite(10,lastsbase,(uchar *)(tdp->spare),
1888                                lastssize) == -1) {
1889                                return(TFSERR_FLASHFAILURE);
1890                        }
1891                }
1892
1893                /* Erase the spare then copy the portion of the last TFS
1894                 * sector that does not overlap with the defrag header and
1895                 * state table area to the spare.  We do this so that the spare
1896                 * sector contains a defrag header and state table area that
1897                 * is erased.
1898                 */
1899                if (defragEraseSpare(tdp) < 0)
1900                        return(TFSERR_FLASHFAILURE);
1901       
1902                if (defragFwrite(11,(uchar *)tdp->spare,
1903                        lastsbase,lastssize-dhstsize) == -1) {
1904                        return(TFSERR_FLASHFAILURE);
1905                }
1906
1907                /* At this point we have a valid copy of the last sector in
1908                 * the spare.  If any portion of the last sector is not identical
1909                 * to what is in the spare, then we need to erase the last sector
1910                 * and re-copy what is in the spare to the last sector.  This is
1911                 * necessary because an interrupt may have occurred while writing
1912                 * to the last sector, and it may have corrupted something.
1913                 */
1914
1915                if ((memcmp((char *)lastsbase,(char *)(tdp->spare),lastssize-dhstsize)) ||
1916                        (!flasherased((uchar *)dht,(uchar *)tdp->end))) {
1917                        if (defragSerase(6,lastsnum) < 0) {
1918                                return(TFSERR_FLASHFAILURE);
1919                        }
1920                        if (defragFwrite(12,lastsbase,(uchar *)(tdp->spare),
1921                                lastssize) == -1) {
1922                                return(TFSERR_FLASHFAILURE);
1923                        }
1924                }
1925                /* Build the header table:
1926                 */
1927                fcnt = 0;
1928                tfp = (TFILE *)tdp->start;
1929                newaddress = (char *)tdp->start;
1930
1931                if (verbose > 2) {
1932                        printf("\nDEFRAG HEADER DATA (dht=0x%lx, ftot=%d):\n",
1933                                (ulong)dht,ftot);
1934                }
1935       
1936                while(validtfshdr(tfp)) {
1937                        if (TFS_FILEEXISTS(tfp)) {
1938                                uchar   *base, *eof, *neof, *nbase;
1939                                int             size, slot;
1940                                struct  tfsdat *slotptr;
1941       
1942                                strcpy(dfhdr.fname,TFS_NAME(tfp));
1943                                dfhdr.ohdr = tfp;
1944                                dfhdr.ohdrcrc = tfp->hdrcrc;
1945                                dfhdr.filsize = TFS_SIZE(tfp);
1946                                if (addrtosector((uchar *)tfp,0,0,&base) < 0)
1947                                        return(TFSERR_MEMFAIL);
1948
1949                                eof = (uchar *)(tfp+1)+TFS_SIZE(tfp)-1;
1950                                if (addrtosector((uchar *)eof,0,0,&base) < 0)
1951                                        return(TFSERR_MEMFAIL);
1952                                dfhdr.oeso = eof - base + 1;
1953
1954                                neof = (uchar *)newaddress+TFSHDRSIZ+TFS_SIZE(tfp)-1;
1955                                if (addrtosector((uchar *)neof,&dfhdr.nesn,0,&nbase) < 0)
1956                                        return(TFSERR_MEMFAIL);
1957                                dfhdr.neso = neof - nbase + 1;
1958
1959                                dfhdr.crc = 0;
1960                                dfhdr.idx = fcnt;
1961                                dfhdr.nda = newaddress;
1962       
1963                                /* If the file is currently opened, adjust the base address. */
1964                                slotptr = tfsSlots;
1965                                for (slot=0;slot<TFS_MAXOPEN;slot++,slotptr++) {
1966                                        if (slotptr->offset != -1) {
1967                                                if (slotptr->base == (uchar *)(TFS_BASE(tfp))) {
1968                                                        slotptr->base = (uchar *)(newaddress+TFSHDRSIZ);
1969                                                }
1970                                        }
1971                                }
1972                                size = TFS_SIZE(tfp) + TFSHDRSIZ;
1973                                if (size & 0xf) {
1974                                        size += TFS_FSIZEMOD;
1975                                        size &= ~(TFS_FSIZEMOD-1);
1976                                }
1977                                newaddress += size;
1978                                dfhdr.nextfile = (TFILE *)newaddress;
1979                                dfhdr.crc = crc32((uchar *)&dfhdr,DEFRAGHDRSIZ);
1980                                if (verbose > 2) {
1981                                        printf(" File %s (sz=%d):\n",TFS_NAME(tfp),TFS_SIZE(tfp));
1982                                        printf("     nda=  0x%08lx, ohdr= 0x%08lx, nxt=  0x%08lx\n",
1983                                                (ulong)(dfhdr.nda),(ulong)(dfhdr.ohdr),
1984                                                (ulong)(dfhdr.nextfile));
1985                                        printf("     oeso= 0x%08lx, nesn= 0x%08lx, neso= 0x%08lx\n",
1986                                                (ulong)(dfhdr.oeso),(ulong)(dfhdr.nesn),
1987                                                (ulong)(dfhdr.neso));
1988                                }
1989                                if (defragFwrite(13,(uchar *)(&dht[fcnt]),
1990                                        (uchar *)(&dfhdr),DEFRAGHDRSIZ) == -1) {
1991                                        return(TFSERR_FLASHFAILURE);
1992                                }
1993                                fcnt++;
1994                                defragTick(0);
1995                        }
1996                        tfp = nextfp(tfp,tdp);
1997                }
1998
1999                if (defragBuildCrcTable(tdp,dht,verbose) < 0)
2000                        return(TFSERR_FLASHFAILURE);
2001
2002                /* Now, the last part of the state table build is to store a
2003                 * 32-bit crc of the data we just wrote...
2004                 */
2005                crc = crc32((uchar *)dht,(uchar *)tdp->end - (uchar *)dht);
2006                if (defragFwrite(14,(uchar *)((ulong *)dht-1),(uchar *)&crc,4) == -1) {
2007                        return(TFSERR_FLASHFAILURE);
2008                }
2009
2010                defrag_state = SCANNING_ACTIVE_SECTOR;
2011        }
2012
2013        /* Exit here to have a complete defrag header installed. */
2014        defragExitTestPoint(1000);
2015
2016        if (defrag_state == SCANNING_ACTIVE_SECTOR) {
2017
2018                if (verbose) {
2019                        printf("TFS: updating sectors %d-%d...\n",
2020                                activesnum,lastsnum);
2021                }
2022
2023                /* Now we begin the actual defragmentation.  We have built enough
2024                 * state information (defrag header and state table) into the last
2025                 * TFS sector, so now we can start the cleanup.
2026                 */
2027                for(sidx = activesnum - firstsnum; sidx < tdp->sectorcount; sidx++) {
2028                        if (defragFillActiveSector(tdp,ftot,sidx,verbose) < 0)
2029                                return(TFSERR_FLASHFAILURE);
2030                }
2031
2032                defrag_state = SECTOR_DEFRAG_ALMOST_DONE;
2033        }
2034
2035        /* Exit here to test "almost-done" state detection. */
2036        defragExitTestPoint(1001);
2037
2038        if (defrag_state == SECTOR_DEFRAG_ALMOST_DONE) {
2039
2040                /* We've completed the relocation of all files into a defragmented
2041                 * area of TFS flash space.  Now we have to erase all sectors after
2042                 * the sector used by the last file in TFS (including the spare)...
2043                 * If the last file in TFS uses the last sector, then the defrag
2044                 * header table will be erased and there is nothing left to do
2045                 * except erase the spare.
2046                 */
2047                if (verbose) {
2048                        printf("TFS: clearing available space...\n");
2049                }
2050                if (dht[ftot-1].crc != ERASED32) {
2051                        end = (dht[ftot-1].nda + dht[ftot-1].filsize + TFSHDRSIZ) - 1;
2052                        if (addrtosector((uchar *)end,&snum,0,0) < 0)
2053                                return(TFSERR_FLASHFAILURE);
2054                        snum++;
2055                        while(snum <= lastsnum) {
2056                                if (defragSerase(7,snum) < 0)
2057                                        return(TFSERR_FLASHFAILURE);
2058                                snum++;
2059                                defragTick(0);
2060                        }
2061                }
2062                if (defragEraseSpare(tdp) < 0)
2063                        return(TFSERR_FLASHFAILURE);
2064
2065                /* All defragmentation is done, so verify sanity of files... */
2066                chkstat = tfscheck(tdp,verbose);
2067        }
2068        else {
2069                chkstat = TFS_OKAY;
2070        }
2071
2072        if ((verbose) || (!MFLAGS_NODEFRAGPRN()))
2073                printf("Defragmentation complete\n");
2074
2075        return(chkstat);
2076}
2077
2078/* tfsfixup():
2079 *      Called at system startup to finish up a TFS defragmentation if one
2080 *      was in progress.
2081 */
2082int
2083tfsfixup(int verbose, int dontquery)
2084{
2085        TDEV    *tdp;
2086
2087        /* Clear test data... */
2088        DefragTestType = 0;
2089        DefragTestPoint = 0;
2090        DefragTestSector = 0;
2091
2092#if !DEFRAG_TEST_ENABLED
2093        tfsTrace = 99;
2094#endif
2095
2096        /* For each TFS device, run defrag with "fixup" flag set to let
2097         * the defragger know that it should only defrag if a defrag was
2098         * in progress.
2099         */
2100        for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
2101                /* Call tfsclean() with fixup flag set... */
2102#if TFS_VERBOSE_STARTUP
2103                if (StateOfMonitor == INITIALIZE)
2104                        printf("TFS Scanning %s...\n",tdp->prefix);
2105#endif
2106                _tfsclean(tdp,1,99);
2107        }
2108
2109#if !DEFRAG_TEST_ENABLED
2110        tfsTrace = 0;
2111#endif
2112        return(0);
2113}
2114
2115#if DEFRAG_TEST_ENABLED
2116int
2117dumpDhdr(DEFRAGHDR *dhp)
2118{
2119        printf("ohdr: 0x%08lx\n",(ulong)dhp->ohdr);
2120        printf("nextfile: 0x%08lx\n",(ulong)dhp->nextfile);
2121        printf("filsize: 0x%08lx\n",(ulong)dhp->filsize);
2122        printf("crc: 0x%08lx\n",(ulong)dhp->crc);
2123        printf("idx: 0x%08lx\n",(ulong)dhp->idx);
2124        printf("nesn: 0x%08lx\n",(ulong)dhp->nesn);
2125        printf("neso: 0x%08lx\n",(ulong)dhp->neso);
2126        printf("nda: 0x%08lx\n",(ulong)dhp->nda);
2127        printf("fname: %s\n",dhp->fname);
2128        return(TFS_OKAY);
2129}
2130
2131int
2132dumpDhdrTbl(DEFRAGHDR *dhp, int ftot)
2133{
2134        TDEV    *tdp;
2135        uchar   *sbase;
2136        ulong   *crc, calccrc;
2137        int             i, ssize, snum;
2138        struct  sectorcrc *crctbl;
2139
2140        for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
2141
2142                if (!dhp) {
2143                        crctbl = defragCrcTable(tdp);
2144                        printf("Device %s...\n",tdp->prefix);
2145                        dhp = (struct defraghdr *)crctbl - 1;
2146                        ftot = dhp->idx + 1;
2147                        printf("(%d files):\n",ftot);
2148                        dhp = (struct defraghdr *)crctbl - ftot;
2149                        crc = (ulong *)dhp-1;
2150                        if (*crc != crc32((uchar *)dhp,(uchar *)tdp->end - (uchar *)dhp)) {
2151                                printf("Table CRC failure\n");
2152                                return(TFS_OKAY);
2153                        }
2154                }
2155                else
2156                        crctbl = (struct sectorcrc *)(dhp + ftot);
2157
2158                printf("dhp=0x%lx, ftot=%d\n",(ulong)dhp,ftot);
2159               
2160                while(dhp < (struct defraghdr *)crctbl) {
2161                        printf(" %s (dhp=0x%lx, idx=%ld):\n",
2162                                dhp->fname,(ulong)dhp,dhp->idx);
2163                        printf("   nda: 0x%08lx, ohdr: 0x%08lx\n",
2164                                (ulong)dhp->nda,(ulong)dhp->ohdr);
2165                        dhp++;
2166                }
2167
2168                sbase = (uchar *)tdp->start;
2169                printf("crctbl at 0x%lx\n",(ulong)crctbl);
2170                for(i=0;i<tdp->sectorcount;i++) {
2171                        if (addrtosector(sbase,&snum,&ssize,0) < 0)
2172                                return(0);
2173                        if (i == tdp->sectorcount-1) {
2174                                ssize -=                                                        /* CRC table */
2175                                        (tdp->sectorcount * sizeof(struct sectorcrc)); 
2176                                ssize -= (ftot * DEFRAGHDRSIZ);         /* DHT table */
2177                                ssize -= 4;                                                     /* Crc of the tables */
2178                        }
2179                        calccrc = crc32(sbase,ssize);
2180                        if (calccrc == crctbl[i].precrc)
2181                                printf("crctbl[%d] (snum=%d) pre-pass\n",i,snum);
2182                        else if (calccrc == crctbl[i].postcrc)
2183                                printf("crctbl[%d] (snum=%d) post-pass\n",i,snum);
2184                        else {
2185                                printf("crctbl[%d] (snum=%d) test failed\n",i,snum);
2186                                printf("pre: 0x%lx, post: 0x%lx,calc: 0x%lx\n",
2187                                        crctbl[i].precrc,crctbl[i].postcrc,calccrc);
2188                        }
2189                        sbase += ssize;
2190                }
2191        }
2192        return(TFS_OKAY);
2193}
2194#endif  /* DEFRAG_TEST_ENABLED */
2195#endif  /* INCLUDE_TFS */
Note: See TracBrowser for help on using the repository browser.