ftllite.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:72k
源码类别:

VxWorks

开发平台:

C/C++

  1. /*
  2.  * $Log:   V:/ftllite.c_v  $
  3.  *
  4.  *    Rev 1.36   01 Mar 1998 12:59:36   amirban
  5.  * Add parameter to mapSector
  6.  *
  7.  *    Rev 1.35   23 Feb 1998 17:08:32   Yair
  8.  * Added casts
  9.  *
  10.  *    Rev 1.34   19 Feb 1998 19:05:46   amirban
  11.  * Shortened FORMAT_PATTERN, and changed repl. page handling
  12.  *
  13.  *    Rev 1.33   23 Nov 1997 17:19:36   Yair
  14.  * Get rid of warnings (With Danny)
  15.  *
  16.  *    Rev 1.32   11 Nov 1997 15:26:46   ANDRY
  17.  * () in complex expressions to get rid of compiler warnings
  18.  *
  19.  *    Rev 1.31   06 Oct 1997 18:37:24   ANDRY
  20.  * no COBUX
  21.  *
  22.  *    Rev 1.30   05 Oct 1997 15:31:40   ANDRY
  23.  * for COBUX: checkForWriteInPlace() always skips even number of bytes
  24. ` *
  25.  *    Rev 1.29   28 Sep 1997 18:22:08   danig
  26.  * Free socket buffer in flsocket.c
  27.  *
  28.  *    Rev 1.28   23 Sep 1997 18:09:44   danig
  29.  * Initialize buffer.sectorNo in initTables
  30.  *
  31.  *    Rev 1.27   10 Sep 1997 16:17:16   danig
  32.  * Got rid of generic names
  33.  *
  34.  *    Rev 1.26   31 Aug 1997 14:28:30   danig
  35.  * Registration routine return status
  36.  *
  37.  *    Rev 1.25   28 Aug 1997 19:01:28   danig
  38.  * buffer per socket
  39.  *
  40.  *    Rev 1.24   28 Jul 1997 14:52:30   danig
  41.  * volForCallback
  42.  *
  43.  *    Rev 1.23   24 Jul 1997 18:02:44   amirban
  44.  * FAR to FAR0
  45.  *
  46.  *    Rev 1.22   21 Jul 1997 19:18:36   danig
  47.  * Compile with SINGLE_BUFFER
  48.  *
  49.  *    Rev 1.21   20 Jul 1997 17:17:12   amirban
  50.  * Get rid of warnings
  51.  *
  52.  *    Rev 1.20   07 Jul 1997 15:22:00   amirban
  53.  * Ver 2.0
  54.  *
  55.  *    Rev 1.19   03 Jun 1997 17:08:10   amirban
  56.  * setBusy change
  57.  *
  58.  *    Rev 1.18   18 May 1997 17:56:04   amirban
  59.  * Add flash read/write flag parameter
  60.  *
  61.  *    Rev 1.17   01 May 1997 12:15:52   amirban
  62.  * Initialize vol.garbageCollectStatus
  63.  *
  64.  *    Rev 1.16   02 Apr 1997 16:56:06   amirban
  65.  * More Big-Endian: Virtual map
  66.  *
  67.  *    Rev 1.15   18 Mar 1997 15:04:06   danig
  68.  * More Big-Endian corrections for BAM
  69.  *
  70.  *    Rev 1.14   10 Mar 1997 18:52:38   amirban
  71.  * Big-Endian corrections for BAM
  72.  *
  73.  *    Rev 1.13   21 Oct 1996 18:03:18   amirban
  74.  * Defragment i/f change
  75.  *
  76.  *    Rev 1.12   09 Oct 1996 11:55:30   amirban
  77.  * Assign Big-Endian unit numbers
  78.  *
  79.  *    Rev 1.11   08 Oct 1996 12:17:46   amirban
  80.  * Use remapped
  81.  *
  82.  *    Rev 1.10   03 Oct 1996 11:56:42   amirban
  83.  * New Big-Endian
  84.  *
  85.  *    Rev 1.9   09 Sep 1996 11:39:12   amirban
  86.  * Background and mapSector bugs
  87.  *
  88.  *    Rev 1.8   29 Aug 1996 14:19:04   amirban
  89.  * Fix boot-image bug, warnings
  90.  *
  91.  *    Rev 1.7   15 Aug 1996 14:04:38   amirban
  92.  *
  93.  *    Rev 1.6   12 Aug 1996 15:49:54   amirban
  94.  * Advanced background transfer, and defined setBusy
  95.  *
  96.  *    Rev 1.5   31 Jul 1996 14:30:28   amirban
  97.  * Background stuff
  98.  *
  99.  *    Rev 1.3   08 Jul 1996 17:21:16   amirban
  100.  * Better page scan in mount unit
  101.  *
  102.  *    Rev 1.2   16 Jun 1996 14:03:42   amirban
  103.  * Added badFormat return code for mount
  104.  *
  105.  *    Rev 1.1   09 Jun 1996 18:16:02   amirban
  106.  * Corrected definition of LogicalAddress
  107.  *
  108.  *    Rev 1.0   20 Mar 1996 13:33:06   amirban
  109.  * Initial revision.
  110.  */
  111. /************************************************************************/
  112. /*                                                                      */
  113. /* FAT-FTL Lite Software Development Kit */
  114. /* Copyright (C) M-Systems Ltd. 1995-1996 */
  115. /* */
  116. /************************************************************************/
  117. #include "backgrnd.h"
  118. #include "flflash.h"
  119. #include "flbuffer.h"
  120. #include "fltl.h"
  121. /*  Implementation constants and type definitions */
  122. #define SECTOR_OFFSET_MASK (SECTOR_SIZE - 1)
  123. typedef long int LogicalAddress; /* Byte address of media in logical
  124.    unit no. order. */
  125. typedef long int VirtualAddress; /* Byte address of media as specified
  126.    by Virtual Map. */
  127. typedef SectorNo LogicalSectorNo; /* A logical sector no. is given
  128.    by dividing its logical address by
  129.    the sector size */
  130. typedef SectorNo VirtualSectorNo; /* A virtual sector no. is such that
  131.    the first page is no. 0, the 2nd
  132.    is 1 etc.
  133.    The virtual sector no. is given
  134.    by dividing its virtual address by
  135.    the sector size and adding the
  136.    number of pages (result always
  137.    positive). */
  138. typedef unsigned short UnitNo;
  139. #define ADDRESSES_PER_SECTOR (SECTOR_SIZE / sizeof(LogicalAddress))
  140. #define UNASSIGNED_ADDRESS 0xffffffffl
  141. #define DELETED_ADDRESS 0
  142. #define DELETED_SECTOR 0
  143. #define PAGE_SIZE_BITS (SECTOR_SIZE_BITS + (SECTOR_SIZE_BITS - 2))
  144. #define PAGE_SIZE (1L << PAGE_SIZE_BITS)
  145. /* Unit descriptor record */
  146. #define UNASSIGNED_UNIT_NO 0xffff
  147. #define MARKED_FOR_ERASE 0x7fff
  148. typedef struct {
  149.   short noOfFreeSectors;
  150.   short         noOfGarbageSectors;
  151. } Unit;
  152. typedef Unit *UnitPtr;
  153. /* Structure of data on a unit */
  154. #define FREE_SECTOR 0xffffffffl
  155. #define GARBAGE_SECTOR 0
  156. #define ALLOCATED_SECTOR 0xfffffffel
  157. #define FORMAT_SECTOR 0x30
  158. #define DATA_SECTOR 0x40
  159. #define REPLACEMENT_PAGE 0x60
  160. #define BAD_SECTOR 0x70
  161. static char FORMAT_PATTERN[15] = {0x13, 3, 'C', 'I', 'S',
  162.  0x46, 57, 0, 'F', 'T', 'L', '1', '0', '0', 0};
  163. typedef struct {
  164.   char formatPattern[15];
  165.   unsigned char noOfTransferUnits; /* no. of transfer units */
  166.   LEulong wearLevelingInfo;
  167.   LEushort logicalUnitNo;
  168.   unsigned char log2SectorSize;
  169.   unsigned char log2UnitSize;
  170.   LEushort firstPhysicalEUN; /* units reserved for boot image */
  171.   LEushort noOfUnits; /* no. of formatted units */
  172.   LEulong virtualMediumSize; /* virtual size of volume */
  173.   LEulong directAddressingMemory; /* directly addressable memory */
  174.   LEushort noOfPages; /* no. of virtual pages */
  175.   unsigned char flags;
  176.   unsigned char eccCode;
  177.   LEulong serialNumber;
  178.   LEulong altEUHoffset;
  179.   LEulong BAMoffset;
  180.   char reserved[12];
  181.   char embeddedCIS[4]; /* Actual length may be larger. By
  182.    default, this contains FF's */
  183. } UnitHeader;
  184. /* flags assignments */
  185. #define HIDDEN_AREA_FLAG 1
  186. #define REVERSE_POLARITY_FLASH 2
  187. #define DOUBLE_BAI 4
  188. #define dummyUnit ((const UnitHeader *) 0)  /* for offset calculations */
  189. #define logicalUnitNoOffset ((char *) &dummyUnit->logicalUnitNo -
  190.      (char *) dummyUnit)
  191. #ifndef MALLOC_TFFS
  192. #define HEAP_SIZE
  193. ((0x100000l / PAGE_SIZE) *                      
  194. sizeof(LogicalSectorNo) +               
  195.  (0x100000l / ASSUMED_FTL_UNIT_SIZE) *          
  196. (sizeof(Unit) + sizeof(UnitPtr))) *     
  197. MAX_VOLUME_MBYTES +                             
  198. (ASSUMED_VM_LIMIT / SECTOR_SIZE) *              
  199. sizeof(LogicalSectorNo)
  200. #endif
  201. #define cannotWriteOver(newContents, oldContents)
  202. ((newContents) & ~(oldContents))
  203. struct tTLrec {
  204.   FLBoolean badFormat; /* true if FTL format is bad */
  205.   VirtualSectorNo totalFreeSectors; /* Free sectors on volume */
  206.   SectorNo virtualSectors; /* size of virtual volume */
  207.   unsigned int unitSizeBits; /* log2 of unit size */
  208.   unsigned int erasableBlockSizeBits; /* log2 of erasable block size */
  209.   UnitNo noOfUnits;
  210.   UnitNo noOfTransferUnits;
  211.   UnitNo firstPhysicalEUN;
  212.   int noOfPages;
  213.   VirtualSectorNo directAddressingSectors;/* no. of directly addressable sectors */
  214.   VirtualAddress  directAddressingMemory; /* end of directly addressable memory */
  215.   CardAddress unitOffsetMask; /* = 1 << unitSizeBits - 1 */
  216.   CardAddress bamOffset;
  217.   unsigned int sectorsPerUnit;
  218.   unsigned int unitHeaderSectors; /* sectors used by unit header */
  219.   Unit * physicalUnits; /* unit table by physical no. */
  220.   Unit ** logicalUnits; /* unit table by logical no. */
  221.   Unit * transferUnit; /* The active transfer unit */
  222.   LogicalSectorNo * pageTable; /* page translation table */
  223. /* directly addressable sectors */
  224.   LogicalSectorNo replacementPageAddress;
  225.   VirtualSectorNo replacementPageNo;
  226.   SectorNo  mappedSectorNo;
  227.   const void FAR0 * mappedSector;
  228.   CardAddress mappedSectorAddress;
  229.   unsigned long currWearLevelingInfo;
  230. #ifdef BACKGROUND
  231.   Unit * unitEraseInProgress; /* Unit currently being formatted */
  232.   FLStatus garbageCollectStatus; /* Status of garbage collection */
  233.   /* When unit transfer is in the background, and is currently in progress,
  234.      all write operations done on the 'from' unit moust be mirrored on the
  235.      transfer unit. If so, 'mirrorOffset' will be non-zero and will be the
  236.      offset of the alternate address from the original. 'mirrorFrom' and
  237.      'mirrorTo' will be the limits of the original addresses to mirror. */
  238.   long int mirrorOffset;
  239.   CardAddress mirrorFrom,
  240. mirrorTo;
  241. #endif
  242. #ifndef SINGLE_BUFFER
  243.   FLBuffer * volBuffer; /* Define a sector buffer */
  244. #endif
  245.   FLFlash flash;
  246. #ifndef MALLOC_TFFS
  247.   char heap[HEAP_SIZE];
  248. #endif
  249. };
  250. typedef TLrec Flare;
  251. static Flare vols[DRIVES];
  252. #ifdef SINGLE_BUFFER
  253. extern FLBuffer buffer;
  254. #else
  255. #define buffer (*vol.volBuffer)
  256. /* Virtual map cache (shares memory with buffer) */
  257. #define mapCache ((LEulong *) buffer.data)
  258. #endif
  259. /* Unit header buffer (shares memory with buffer) */
  260. #define uh ((UnitHeader *) buffer.data)
  261. /* Transfer sector buffer (shares memory with buffer) */
  262. #define sectorCopy  ((LEulong *) buffer.data)
  263. #define FREE_UNIT -0x400 /* Indicates a transfer unit */
  264. /*----------------------------------------------------------------------*/
  265. /*          p h y s i c a l B a s e */
  266. /* */
  267. /* Returns the physical address of a unit. */
  268. /*                                                                      */
  269. /* Parameters:                                                          */
  270. /* vol : Pointer identifying drive */
  271. /* unit : unit pointer */
  272. /*                                                                      */
  273. /* Returns:                                                             */
  274. /* physical address of unit */
  275. /*----------------------------------------------------------------------*/
  276. static CardAddress physicalBase(Flare vol,  const Unit *unit)
  277. {
  278.   return (CardAddress) (unit - vol.physicalUnits) << vol.unitSizeBits;
  279. }
  280. /*----------------------------------------------------------------------*/
  281. /*       l o g i c a l 2 P h y s i c a l */
  282. /* */
  283. /* Returns the physical address of a logical sector no. */
  284. /*                                                                      */
  285. /* Parameters:                                                          */
  286. /* vol : Pointer identifying drive */
  287. /* address : logical sector no. */
  288. /*                                                                      */
  289. /* Returns:                                                             */
  290. /* CardAddress : physical address of sector */
  291. /*----------------------------------------------------------------------*/
  292. static CardAddress logical2Physical(Flare vol,  LogicalSectorNo address)
  293. {
  294.   return physicalBase(&vol,vol.logicalUnits[address >> (vol.unitSizeBits - SECTOR_SIZE_BITS)]) |
  295.  (((CardAddress) address << SECTOR_SIZE_BITS) & vol.unitOffsetMask);
  296. }
  297. /*----------------------------------------------------------------------*/
  298. /*             m a p L o g i c a l */
  299. /* */
  300. /* Maps a logical sector and returns pointer to physical Flash location.*/
  301. /*                                                                      */
  302. /* Parameters:                                                          */
  303. /* vol : Pointer identifying drive */
  304. /* address : logical sector no. */
  305. /*                                                                      */
  306. /* Returns:                                                             */
  307. /* Pointer to sector on Flash  */
  308. /*----------------------------------------------------------------------*/
  309. static void FAR0 *mapLogical(Flare vol, LogicalSectorNo address)
  310. {
  311.   return vol.flash.map(&vol.flash,logical2Physical(&vol,address),SECTOR_SIZE);
  312. }
  313. /*----------------------------------------------------------------------*/
  314. /*         a l l o c E n t r y O f f s e t */
  315. /* */
  316. /* Returns unit offset of given BAM entry */
  317. /*                                                                      */
  318. /* Parameters:                                                          */
  319. /* vol : Pointer identifying drive */
  320. /* sectorNo : BAM entry no. */
  321. /*                                                                      */
  322. /* Returns:                                                             */
  323. /* Offset of BAM entry in unit */
  324. /*----------------------------------------------------------------------*/
  325. static int allocEntryOffset(Flare vol, int sectorNo)
  326. {
  327.   return (int) (vol.bamOffset + sizeof(VirtualAddress) * sectorNo);
  328. }
  329. /*----------------------------------------------------------------------*/
  330. /*          m a p U n i t H e a d e r  */
  331. /* */
  332. /* Map a unit header and return pointer to it. */
  333. /*                                                                      */
  334. /* Parameters:                                                          */
  335. /* vol : Pointer identifying drive */
  336. /* unit : Unit to map header */
  337. /*                                                                      */
  338. /* Returns:                                                             */
  339. /* Pointer to mapped unit header */
  340. /* blockAllocMap : (optional) Pointer to mapped BAM */
  341. /*----------------------------------------------------------------------*/
  342. static UnitHeader FAR0 *mapUnitHeader(Flare vol,
  343.      const Unit *unit,
  344.      LEulong FAR0 **blockAllocMap)
  345. {
  346.   UnitHeader FAR0 *unitHeader;
  347.   int length = sizeof(UnitHeader);
  348.   if (blockAllocMap)
  349.     length = allocEntryOffset(&vol,vol.sectorsPerUnit);
  350.   unitHeader = (UnitHeader FAR0 *) vol.flash.map(&vol.flash,physicalBase(&vol,unit),length);
  351.   if (blockAllocMap)
  352.     *blockAllocMap = (LEulong FAR0 *) ((char FAR0 *) unitHeader + allocEntryOffset(&vol,0));
  353.   return unitHeader;
  354. }
  355. #ifndef SINGLE_BUFFER
  356. /*----------------------------------------------------------------------*/
  357. /*           s e t u p M a p C a c h e */
  358. /* */
  359. /* Sets up map cache sector to contents of specified Virtual Map page */
  360. /*                                                                      */
  361. /* Parameters:                                                          */
  362. /* vol : Pointer identifying drive */
  363. /* pageNo : Page no. to copy to map cache */
  364. /*                                                                      */
  365. /*----------------------------------------------------------------------*/
  366. static void setupMapCache(Flare vol,  VirtualSectorNo pageNo)
  367. {
  368.   vol.flash.read(&vol.flash,logical2Physical(&vol,vol.pageTable[pageNo]),mapCache,SECTOR_SIZE,0);
  369.   if (pageNo == vol.replacementPageNo) {
  370.     int i;
  371.     LEulong FAR0 *replacementPage =
  372. (LEulong FAR0 *) mapLogical(&vol,vol.replacementPageAddress);
  373.     for (i = 0; (unsigned)i < ADDRESSES_PER_SECTOR; i++) {
  374.       if (LE4(mapCache[i]) == DELETED_ADDRESS)
  375. toLE4(mapCache[i],LE4(replacementPage[i]));
  376.     }
  377.   }
  378.   buffer.sectorNo = pageNo;
  379.   buffer.owner = &vol;
  380. }
  381. #endif
  382. /*----------------------------------------------------------------------*/
  383. /*         v i r t u a l 2 L o g i c a l */
  384. /* */
  385. /* Translates virtual sector no. to logical sector no. */
  386. /*                                                                      */
  387. /* Parameters:                                                          */
  388. /* vol : Pointer identifying drive */
  389. /* sectorNo : Virtual sector no. */
  390. /*                                                                      */
  391. /* Returns:                                                             */
  392. /* Logical sector no. corresponding to virtual sector no. */
  393. /*----------------------------------------------------------------------*/
  394. static LogicalSectorNo virtual2Logical(Flare vol,  VirtualSectorNo sectorNo)
  395. {
  396.   LogicalAddress virtualMapEntry;
  397.   if (sectorNo < vol.directAddressingSectors)
  398.     return vol.pageTable[sectorNo];
  399.   else {
  400.     unsigned pageNo;
  401.     int sectorInPage;
  402.     sectorNo -= vol.noOfPages;
  403.     pageNo = (int) (sectorNo >> (PAGE_SIZE_BITS - SECTOR_SIZE_BITS));
  404.     sectorInPage = (int) (sectorNo) % ADDRESSES_PER_SECTOR;
  405.     {
  406. #ifdef SINGLE_BUFFER
  407.       LogicalAddress FAR0 *virtualMapPage;
  408.       virtualMapPage = (LogicalAddress FAR0 *) mapLogical(&vol, vol.pageTable[pageNo]);
  409.       if (pageNo == vol.replacementPageNo &&
  410.   virtualMapPage[sectorInPage] == DELETED_ADDRESS)
  411. virtualMapPage = (LogicalAddress FAR0 *) mapLogical(&vol, vol.replacementPageAddress);
  412.       virtualMapEntry = LE4(virtualMapPage[sectorInPage]);
  413. #else
  414.       if (buffer.sectorNo != pageNo || buffer.owner != &vol)
  415. setupMapCache(&vol,pageNo);
  416.       virtualMapEntry = LE4(mapCache[sectorInPage]);
  417. #endif
  418.       return (LogicalSectorNo) (virtualMapEntry >> SECTOR_SIZE_BITS);
  419.     }
  420.   }
  421. }
  422. /*----------------------------------------------------------------------*/
  423. /*           v e r i f y F o r m a t  */
  424. /* */
  425. /* Verify an FTL unit header. */
  426. /*                                                                      */
  427. /* Parameters:                                                          */
  428. /* unitHeader : Pointer to unit header */
  429. /*                                                                      */
  430. /* Returns:                                                             */
  431. /* TRUE if header is correct. FALSE if not. */
  432. /*----------------------------------------------------------------------*/
  433. static FLBoolean verifyFormat(UnitHeader FAR0 *unitHeader)
  434. {
  435.   FORMAT_PATTERN[6] = unitHeader->formatPattern[6]; /* TPL_LINK */
  436.   return tffscmp(unitHeader->formatPattern + 2,
  437.  FORMAT_PATTERN + 2,
  438.  sizeof unitHeader->formatPattern - 2) == 0;
  439. }
  440. /*----------------------------------------------------------------------*/
  441. /*           f o r m a t U n i t */
  442. /* */
  443. /* Formats a unit by erasing it and writing a unit header. */
  444. /*                                                                      */
  445. /* Parameters:                                                          */
  446. /* vol : Pointer identifying drive */
  447. /* unit : Unit to format */
  448. /*                                                                      */
  449. /* Returns:                                                             */
  450. /* FLStatus : 0 on success, failed otherwise */
  451. /*----------------------------------------------------------------------*/
  452. static FLStatus formatUnit(Flare vol,  Unit *unit)
  453. {
  454.   unsigned unitHeaderLength = allocEntryOffset(&vol,vol.unitHeaderSectors);
  455.   unit->noOfFreeSectors = FREE_UNIT;
  456.   unit->noOfGarbageSectors = 0;
  457. #ifdef BACKGROUND
  458.   {
  459.     FLStatus status;
  460.     vol.unitEraseInProgress = unit;
  461.     status = vol.flash.erase(&vol.flash,
  462.  (int) (physicalBase(&vol,unit) >> vol.erasableBlockSizeBits),
  463.  1 << (vol.unitSizeBits - vol.erasableBlockSizeBits));
  464.     vol.unitEraseInProgress = NULL;
  465.     if (status != flOK)
  466.       return status;
  467.     /* Note: This suspend to the foreground is not only nice to have, it is
  468.        necessary ! The reason is that we may have a write from the buffer
  469.        waiting for the erase to complete. We are next going to overwrite the
  470.        buffer, so this break enables the write to complete before the data is
  471.        clobbered (what a relief). */
  472.     while (flForeground(1) == BG_SUSPEND)
  473.       ;
  474.   }
  475. #else
  476.   checkStatus(vol.flash.erase(&vol.flash,
  477.   (int) (physicalBase(&vol,unit) >> vol.erasableBlockSizeBits),
  478.   1 << (vol.unitSizeBits - vol.erasableBlockSizeBits)));
  479. #endif
  480.   /* We will copy the unit header as far as the format entries of the BAM
  481.      from another unit (logical unit 0) */
  482. #ifdef SINGLE_BUFFER
  483.   if (buffer.dirty)
  484.     return flBufferingError;
  485. #endif
  486.   buffer.sectorNo = UNASSIGNED_SECTOR;    /* Invalidate map cache so we can
  487.      use it as a buffer */
  488.   if (vol.logicalUnits[vol.firstPhysicalEUN]) {
  489.     vol.flash.read(&vol.flash,
  490.        physicalBase(&vol,vol.logicalUnits[vol.firstPhysicalEUN]),
  491.        uh,
  492.        unitHeaderLength,
  493.        0);
  494.   }
  495.   toLE4(uh->wearLevelingInfo,++vol.currWearLevelingInfo);
  496.   toLE2(uh->logicalUnitNo,UNASSIGNED_UNIT_NO);
  497.   checkStatus(vol.flash.write(&vol.flash,
  498.   physicalBase(&vol,unit),
  499.   uh,
  500.   unitHeaderLength,
  501.   0));
  502.   return flOK;
  503. }
  504. #ifdef BACKGROUND
  505. /*----------------------------------------------------------------------*/
  506. /*           f l a s h W r i t e */
  507. /* */
  508. /* Writes to flash through flash.write, but, if possible, allows a */
  509. /* background erase to continue while writing. */
  510. /*                                                                      */
  511. /* Parameters:                                                          */
  512. /* Same as flash.write */
  513. /*           */
  514. /* Returns:                                                             */
  515. /* Same as flash.write */
  516. /*----------------------------------------------------------------------*/
  517. static FLStatus flashWrite(Flare vol,
  518.  CardAddress address,
  519.  const void FAR1 *from,
  520.  int length,
  521.  FLBoolean overwrite)
  522. {
  523.   if (vol.mirrorOffset != 0 &&
  524.       address >= vol.mirrorFrom && address < vol.mirrorTo) {
  525.     checkStatus(flashWrite(&vol,
  526.    address + vol.mirrorOffset,
  527.    from,
  528.    length,
  529.    overwrite));
  530.   }
  531.   if (vol.unitEraseInProgress) {
  532.     CardAddress startChip = physicalBase(&vol,vol.unitEraseInProgress) &
  533. (-vol.flash.interleaving * vol.flash.chipSize);
  534.     CardAddress endChip = startChip + vol.flash.interleaving * vol.flash.chipSize;
  535.     if (address < startChip || address >= endChip) {
  536.       flBackground(BG_RESUME);
  537.       checkStatus(vol.flash.write(&vol.flash,address,from,length,overwrite));
  538.       flBackground(BG_SUSPEND);
  539.       return flOK;
  540.     }
  541.     else if (!(vol.flash.flags & SUSPEND_FOR_WRITE)) {
  542.       do {
  543. flBackground(BG_RESUME);
  544.       } while (vol.unitEraseInProgress);
  545.     }
  546.   }
  547.   return vol.flash.write(&vol.flash,address,from,length,overwrite);
  548. }
  549. #else
  550. #define flashWrite(v,address,from,length,overwrite)
  551. (v)->flash.write(&(v)->flash,address,from,length,overwrite)
  552. #endif /* BACKGROUND */
  553. /*----------------------------------------------------------------------*/
  554. /*            m o u n t U n i t */
  555. /* */
  556. /* Performs mount scan for a single unit */
  557. /*                                                                      */
  558. /* Parameters:                                                          */
  559. /* vol : Pointer identifying drive */
  560. /* unit : Unit to mount */
  561. /*                                                                      */
  562. /* Returns:                                                             */
  563. /* FLStatus : 0 on success, failed otherwise */
  564. /*----------------------------------------------------------------------*/
  565. static FLStatus mountUnit(Flare vol,  Unit *unit)
  566. {
  567.   unsigned i;
  568.   LogicalSectorNo sectorAddress;
  569.   LEulong FAR0 *blockAllocMap;
  570.   UnitHeader FAR0 *unitHeader = mapUnitHeader(&vol,unit,&blockAllocMap);
  571.   UnitNo logicalUnitNo = LE2(unitHeader->logicalUnitNo);
  572.   unit->noOfGarbageSectors = 0;
  573.   unit->noOfFreeSectors = FREE_UNIT;
  574.   if (!verifyFormat(unitHeader) ||
  575.       ((logicalUnitNo != UNASSIGNED_UNIT_NO) &&
  576.        ((logicalUnitNo >= vol.noOfUnits) ||
  577.         (logicalUnitNo < vol.firstPhysicalEUN) ||
  578.         vol.logicalUnits[logicalUnitNo]))) {
  579.     if (vol.transferUnit == NULL)
  580.       vol.transferUnit = unit;
  581.     return flBadFormat;
  582.   }
  583.   if (logicalUnitNo == UNASSIGNED_UNIT_NO) {
  584.     vol.transferUnit = unit;
  585.     return flOK; /* this is a transfer unit */
  586.   }
  587.   if (LE4(unitHeader->wearLevelingInfo) > vol.currWearLevelingInfo &&
  588.       LE4(unitHeader->wearLevelingInfo) != 0xffffffffl)
  589.     vol.currWearLevelingInfo = LE4(unitHeader->wearLevelingInfo);
  590.   /* count sectors and setup virtual map */
  591.   sectorAddress =
  592.      ((LogicalSectorNo) logicalUnitNo << (vol.unitSizeBits - SECTOR_SIZE_BITS));
  593.   unit->noOfFreeSectors = 0;
  594.   for (i = 0; i < vol.sectorsPerUnit; i++, sectorAddress++) {
  595.     VirtualAddress allocMapEntry = LE4(blockAllocMap[i]);
  596.     if (allocMapEntry == GARBAGE_SECTOR || (unsigned long)allocMapEntry == ALLOCATED_SECTOR)
  597.       unit->noOfGarbageSectors++;
  598.     else if ((unsigned long)allocMapEntry == FREE_SECTOR) {
  599.       unit->noOfFreeSectors++;
  600.       vol.totalFreeSectors++;
  601.     }
  602.     else if (allocMapEntry < vol.directAddressingMemory) {
  603.       char signature = (short) (allocMapEntry) & SECTOR_OFFSET_MASK;
  604.       if (signature == DATA_SECTOR || signature == REPLACEMENT_PAGE) {
  605. int pageNo = (int) (allocMapEntry >> SECTOR_SIZE_BITS) + vol.noOfPages;
  606. if (pageNo >= 0)
  607.   if (signature == DATA_SECTOR)
  608.     vol.pageTable[pageNo] = sectorAddress;
  609.   else {
  610.     vol.replacementPageAddress = sectorAddress;
  611.     vol.replacementPageNo = pageNo;
  612.   }
  613.       }
  614.     }
  615.   }
  616.   /* Place the logical mapping of the unit */
  617.   vol.mappedSectorNo = UNASSIGNED_SECTOR;
  618.   vol.logicalUnits[logicalUnitNo] = unit;
  619.   return flOK;
  620. }
  621. /*----------------------------------------------------------------------*/
  622. /*            a s s i g n U n i t */
  623. /* */
  624. /* Assigns a logical unit no. to a unit */
  625. /*                                                                      */
  626. /* Parameters:                                                          */
  627. /* vol : Pointer identifying drive */
  628. /* unit : Unit to assign */
  629. /*                                                                      */
  630. /* Returns:                                                             */
  631. /* FLStatus : 0 on success, failed otherwise */
  632. /*----------------------------------------------------------------------*/
  633. static FLStatus assignUnit(Flare vol,  Unit *unit, UnitNo logicalUnitNo)
  634. {
  635.   LEushort unitNoToWrite;
  636.   toLE2(unitNoToWrite,logicalUnitNo);
  637.   return flashWrite(&vol,
  638.     physicalBase(&vol,unit) + logicalUnitNoOffset,
  639.     &unitNoToWrite,
  640.     sizeof unitNoToWrite,
  641.     OVERWRITE);
  642. }
  643. /*----------------------------------------------------------------------*/
  644. /*     b e s t U n i t T o T r a n s f e r */
  645. /* */
  646. /* Find best candidate for unit transfer, usually on the basis of which */
  647. /* unit has the most garbage space. A lower wear-leveling info serves */
  648. /* as a tie-breaker. If 'leastUsed' is NOT specified, then the least */
  649. /* wear-leveling info is the only criterion. */
  650. /*                                                                      */
  651. /* Parameters:                                                          */
  652. /* vol : Pointer identifying drive */
  653. /* leastUsed : Whether most garbage space is the criterion */
  654. /*                                                                      */
  655. /* Returns:                                                             */
  656. /* Best unit to transfer */
  657. /*----------------------------------------------------------------------*/
  658. static UnitNo bestUnitToTransfer(Flare vol,  FLBoolean leastUsed)
  659. {
  660.   UnitNo i;
  661.   int mostGarbageSectors = 1;
  662.   unsigned long int leastWearLevelingInfo = 0xffffffffl;
  663.   UnitNo bestUnitSoFar = UNASSIGNED_UNIT_NO;
  664.   for (i = 0; i < vol.noOfUnits; i++) {
  665.     Unit *unit = vol.logicalUnits[i];
  666.     if (unit && (!leastUsed || (unit->noOfGarbageSectors >= mostGarbageSectors))) {
  667.       UnitHeader FAR0 *unitHeader = mapUnitHeader(&vol,unit,NULL);
  668.       if ((leastUsed && (unit->noOfGarbageSectors > mostGarbageSectors)) ||
  669.   (LE4(unitHeader->wearLevelingInfo) < leastWearLevelingInfo)) {
  670. mostGarbageSectors = unit->noOfGarbageSectors;
  671. leastWearLevelingInfo = LE4(unitHeader->wearLevelingInfo);
  672. bestUnitSoFar = i;
  673.       }
  674.     }
  675.   }
  676.   return bestUnitSoFar;
  677. }
  678. /*----------------------------------------------------------------------*/
  679. /*            u n i t T r a n s f e r */
  680. /* */
  681. /* Performs a unit transfer from a selected unit to a tranfer unit. */
  682. /*                                                                      */
  683. /* A side effect is to invalidate the map cache (reused as buffer). */
  684. /* */
  685. /* Parameters:                                                          */
  686. /* vol : Pointer identifying drive */
  687. /* toUnit          : Target transfer unit */
  688. /* fromUnitNo: : Source logical unit no. */
  689. /*                                                                      */
  690. /* Returns:                                                             */
  691. /* FLStatus : 0 on success, failed otherwise */
  692. /*----------------------------------------------------------------------*/
  693. static FLStatus unitTransfer(Flare vol,  Unit *toUnit, UnitNo fromUnitNo)
  694. {
  695.   unsigned i;
  696.   Unit *fromUnit = vol.logicalUnits[fromUnitNo];
  697.   UnitHeader FAR0 *transferUnitHeader = mapUnitHeader(&vol,toUnit,NULL);
  698.   if (!verifyFormat(transferUnitHeader) ||
  699.       LE2(transferUnitHeader->logicalUnitNo) != UNASSIGNED_UNIT_NO)
  700.     /* previous formatting failed or did not complete.  */
  701.     checkStatus(formatUnit(&vol,toUnit));
  702.   /* Should the transfer not complete, the unit is marked to be erased */
  703.   checkStatus(assignUnit(&vol,toUnit,MARKED_FOR_ERASE));
  704. #ifdef BACKGROUND
  705.   vol.mirrorFrom = vol.mirrorTo = physicalBase(&vol,fromUnit);
  706.   vol.mirrorOffset = physicalBase(&vol,toUnit) - vol.mirrorFrom;
  707. #endif
  708.   /* copy the block allocation table and the good sectors */
  709.   for (i = 0; i < vol.sectorsPerUnit;) {
  710.     int j;
  711.     FLBoolean needToWrite = FALSE;
  712.     int firstOffset = allocEntryOffset(&vol,i);
  713.     /* Up to 128 bytes of the BAM are processed per loop */
  714.     int nEntries = (128 - (firstOffset & 127)) / sizeof(VirtualAddress);
  715.     /* We are going to use the Virtual Map cache as our sector buffer in the */
  716.     /* transfer, so let's better invalidate the cache first.    */
  717. #ifdef SINGLE_BUFFER
  718.     if (buffer.dirty)
  719.       return flBufferingError;
  720. #endif
  721.     buffer.sectorNo = UNASSIGNED_SECTOR;
  722.     /* Read some of the BAM */
  723.     vol.flash.read(&vol.flash,
  724.        physicalBase(&vol,fromUnit) + firstOffset,
  725.        sectorCopy,
  726.        nEntries * sizeof(VirtualAddress),
  727.        0);
  728.     /* Convert garbage entries to free entries */
  729.     for (j = 0; j < nEntries && i+j < vol.sectorsPerUnit; j++) {
  730.       unsigned bamSignature = (unsigned) LE4(sectorCopy[j]) & SECTOR_OFFSET_MASK;
  731.       if (bamSignature == DATA_SECTOR ||
  732.   bamSignature == REPLACEMENT_PAGE)
  733. needToWrite = TRUE;
  734.       else if (bamSignature != FORMAT_SECTOR)
  735. toLE4(sectorCopy[j],FREE_SECTOR);
  736.     }
  737.     if (needToWrite) {
  738.       FLStatus status;
  739.       /* Write new BAM, and copy sectors that need to be copied */
  740.       status = flashWrite(&vol,
  741.   physicalBase(&vol,toUnit) + firstOffset,
  742.   sectorCopy,
  743.   nEntries * sizeof(VirtualAddress),
  744.   0);
  745.       if (status != flOK) {
  746. #ifdef BACKGROUND
  747. vol.mirrorOffset = 0; /* no more mirroring */
  748. #endif
  749. return status;
  750.       }
  751.       for (j = 0; j < nEntries && i+j < vol.sectorsPerUnit; j++) {
  752. unsigned bamSignature = (unsigned) LE4(sectorCopy[j]) & SECTOR_OFFSET_MASK;
  753. if (bamSignature == DATA_SECTOR ||
  754.     bamSignature == REPLACEMENT_PAGE) { /* a good sector */
  755.   CardAddress sectorOffset = (CardAddress) (i+j) << SECTOR_SIZE_BITS;
  756.   vol.flash.read(&vol.flash,
  757.      physicalBase(&vol,fromUnit) + sectorOffset,
  758.      sectorCopy,SECTOR_SIZE,0);
  759.   status = flashWrite(&vol,
  760.       physicalBase(&vol,toUnit) + sectorOffset,
  761.       sectorCopy,
  762.       SECTOR_SIZE,
  763.       0);
  764.   if (status != flOK) {
  765. #ifdef BACKGROUND
  766.     vol.mirrorOffset = 0; /* no more mirroring */
  767. #endif
  768.     return status;
  769.   }
  770.   vol.flash.read(&vol.flash,
  771.      physicalBase(&vol,fromUnit) + firstOffset,
  772.      sectorCopy,
  773.      nEntries * sizeof(VirtualAddress),0);
  774. }
  775.       }
  776. #ifdef BACKGROUND
  777.       vol.mirrorTo = vol.mirrorFrom +
  778.      ((CardAddress) (i + nEntries) << SECTOR_SIZE_BITS);
  779.       while (flForeground(1) == BG_SUSPEND)
  780. ;
  781. #endif
  782.     }
  783.     i += nEntries;
  784.   }
  785. #ifdef BACKGROUND
  786.   vol.mirrorOffset = 0; /* no more mirroring */
  787. #endif
  788.   /* Write the new logical unit no. */
  789.   checkStatus(assignUnit(&vol,toUnit,fromUnitNo));
  790.   /* Mount the new unit in place of old one */
  791.   vol.logicalUnits[fromUnitNo] = NULL;
  792.   if (mountUnit(&vol,toUnit) == flOK) {
  793.     vol.totalFreeSectors -= fromUnit->noOfFreeSectors;
  794.     /* Finally, format the source unit (the new transfer unit) */
  795.     vol.transferUnit = fromUnit;
  796.     formatUnit(&vol,fromUnit); /* nothing we can or should do if this fails */
  797.   }
  798.   else { /* Something went wrong */
  799.     vol.logicalUnits[fromUnitNo] = fromUnit; /* reinstate original unit */
  800.     return flGeneralFailure;
  801.   }
  802.   return flOK;
  803. }
  804. /*----------------------------------------------------------------------*/
  805. /*          g a r b a g e C o l l e c t */
  806. /* */
  807. /* Performs a unit transfer, selecting a unit to transfer and a */
  808. /* transfer unit.                                                       */
  809. /*                                                                      */
  810. /* Parameters:                                                          */
  811. /* vol : Pointer identifying drive */
  812. /*                                                                      */
  813. /* Returns:                                                             */
  814. /* FLStatus : 0 on success, failed otherwise */
  815. /*----------------------------------------------------------------------*/
  816. static FLStatus garbageCollect(Flare vol)
  817. {
  818.   FLStatus status;
  819.   UnitNo fromUnitNo;
  820.   if (vol.transferUnit == NULL)
  821.     return flWriteProtect; /* Cannot recover space without a spare unit */
  822.   fromUnitNo = bestUnitToTransfer(&vol,flRandByte() >= 4);
  823.   if (fromUnitNo == UNASSIGNED_UNIT_NO)
  824.     return flGeneralFailure; /* nothing to collect */
  825.   /* Find a unit we can transfer to. */
  826.   status = unitTransfer(&vol,vol.transferUnit,fromUnitNo);
  827.   if (status == flWriteFault) {
  828.     int i;
  829.     Unit *unit = vol.physicalUnits;
  830.     for (i = 0; i < vol.noOfUnits; i++, unit++) {
  831.       if (unit->noOfGarbageSectors == 0 && unit->noOfFreeSectors < 0) {
  832. if (unitTransfer(&vol,unit,fromUnitNo) == flOK)
  833.   return flOK; /* found a good one */
  834.       }
  835.     }
  836.   }
  837.   return status;
  838. }
  839. #ifdef BACKGROUND
  840. /*----------------------------------------------------------------------*/
  841. /*         b g G a r b a g e C o l l e c t */
  842. /* */
  843. /* Entry point for garbage collection in the background. */
  844. /*                                                                      */
  845. /* Status is returned in vol.garbageCollectStatus */
  846. /*                                                                      */
  847. /* Parameters:                                                          */
  848. /* vol : Pointer identifying drive */
  849. /*           */
  850. /* Returns:                                                             */
  851. /* None */
  852. /*----------------------------------------------------------------------*/
  853. static void bgGarbageCollect(void * object)
  854. {
  855.   Flare vol = (Flare *)object;
  856.   vol.garbageCollectStatus = flIncomplete;
  857.   vol.garbageCollectStatus = garbageCollect(&vol);
  858. }
  859. #endif
  860. /*----------------------------------------------------------------------*/
  861. /*                   d e f r a g m e n t */
  862. /* */
  863. /* Performs unit transfers to arrange a minimum number of writable */
  864. /* sectors.                                                             */
  865. /* */
  866. /* Parameters:                                                          */
  867. /* vol : Pointer identifying drive */
  868. /* sectorsNeeded : Minimum required sectors */
  869. /*                                                                      */
  870. /* Returns:                                                             */
  871. /* FLStatus : 0 on success, failed otherwise */
  872. /*----------------------------------------------------------------------*/
  873. #define GARBAGE_COLLECT_THRESHOLD 20
  874. static FLStatus defragment(Flare vol, long FAR2 *sectorsNeeded)
  875. {
  876.   while ((long)(vol.totalFreeSectors) < *sectorsNeeded
  877. #ifdef BACKGROUND
  878.  || vol.totalFreeSectors < GARBAGE_COLLECT_THRESHOLD
  879. #endif
  880.  ) {
  881.     if (vol.badFormat)
  882.       return flBadFormat;
  883. #ifdef BACKGROUND
  884.     if (vol.garbageCollectStatus == flIncomplete)
  885.       flBackground(BG_RESUME);
  886.     else
  887.       flStartBackground(&vol - vols,bgGarbageCollect,&vol);
  888.     if (vol.garbageCollectStatus != flOK &&
  889. vol.garbageCollectStatus != flIncomplete)
  890.       return vol.garbageCollectStatus;
  891.     if (vol.totalFreeSectors >= *sectorsNeeded)
  892.       break;
  893.   }
  894.   if (vol.unitEraseInProgress)
  895.     flBackground(BG_SUSPEND);
  896. #else
  897.     checkStatus(garbageCollect(&vol));
  898.   }
  899. #endif
  900.   *sectorsNeeded = vol.totalFreeSectors;
  901.   return flOK;
  902. }
  903. /*----------------------------------------------------------------------*/
  904. /*     b e s t U n i t T o A l l o c a t e */
  905. /* */
  906. /* Finds the best unit from which to allocate a sector. The unit */
  907. /* selected is the one with most free space. */
  908. /* */
  909. /* Parameters:                                                          */
  910. /* vol : Pointer identifying drive */
  911. /*                                                                      */
  912. /* Returns:                                                             */
  913. /* Best unit to allocate */
  914. /*----------------------------------------------------------------------*/
  915. static Unit *bestUnitToAllocate(Flare vol)
  916. {
  917.   int i;
  918.   int mostFreeSectors = 0;
  919.   Unit *bestUnitSoFar = NULL;
  920.   for (i = 0; i < vol.noOfUnits; i++) {
  921.     Unit *unit = vol.logicalUnits[i];
  922.     if (unit && unit->noOfFreeSectors > mostFreeSectors) {
  923.       mostFreeSectors = unit->noOfFreeSectors;
  924.       bestUnitSoFar = unit;
  925.     }
  926.   }
  927.   return bestUnitSoFar;
  928. }
  929. /*----------------------------------------------------------------------*/
  930. /*        f i n d F r e e S e c t o r */
  931. /* */
  932. /* The allocation strategy goes this way:                               */
  933. /*                                                                      */
  934. /* We try to make consecutive virtual sectors physically consecutive if */
  935. /* possible. If not, we prefer to have consecutive sectors on the same  */
  936. /* unit at least. If all else fails, a sector is allocated on the unit  */
  937. /* with most space available.                                           */
  938. /*                                                                      */
  939. /* The object of this strategy is to cluster related data (e.g. a file  */
  940. /* data) in one unit, and to distribute unrelated data evenly among all */
  941. /* units. */
  942. /* */
  943. /* Parameters:                                                          */
  944. /* vol : Pointer identifying drive */
  945. /* sectorNo        : virtual sector no. that we want to allocate. */
  946. /* */
  947. /* Returns:                                                             */
  948. /* newAddress : Allocated logical sector no. */
  949. /* FLStatus : 0 on success, failed otherwise */
  950. /*----------------------------------------------------------------------*/
  951. static FLStatus findFreeSector(Flare vol,
  952.      VirtualSectorNo sectorNo,
  953.      LogicalSectorNo *newAddress)
  954. {
  955.   unsigned iSector;
  956.   LEulong FAR0 *blockAllocMap;
  957.   UnitHeader FAR0 *unitHeader;
  958.   Unit *allocationUnit = NULL;
  959.   LogicalSectorNo previousSectorAddress =
  960.  sectorNo > 0 ? virtual2Logical(&vol,sectorNo - 1) : UNASSIGNED_SECTOR;
  961. #ifdef DEBUG_PRINT
  962.   DEBUG_PRINT("Debug: findFreeSector -> %d !!n", sectorNo);
  963. #endif
  964.   if (previousSectorAddress != UNASSIGNED_SECTOR &&
  965.       previousSectorAddress != DELETED_SECTOR) {
  966.     allocationUnit =
  967. vol.logicalUnits[previousSectorAddress >> (vol.unitSizeBits - SECTOR_SIZE_BITS)];
  968.     if (allocationUnit->noOfFreeSectors > 0) {
  969.       unsigned int sectorIndex = ((unsigned) previousSectorAddress & (vol.sectorsPerUnit - 1)) + 1;
  970.       LEulong FAR0 *nextSectorAddress =
  971.    (LEulong FAR0 *) vol.flash.map(&vol.flash,
  972.      physicalBase(&vol,allocationUnit) +
  973.                                           allocEntryOffset(&vol, sectorIndex),
  974.      sizeof(VirtualAddress));
  975.       if (sectorIndex < vol.sectorsPerUnit && LE4(*nextSectorAddress) == FREE_SECTOR) {
  976. /* can write sequentially */
  977. *newAddress = previousSectorAddress + 1;
  978. return flOK;
  979.       }
  980.     }
  981.     else
  982.       allocationUnit = NULL; /* no space here, try elsewhere */
  983.   }
  984.   if (allocationUnit == NULL)
  985.     allocationUnit = bestUnitToAllocate(&vol);
  986.   if (allocationUnit == NULL) /* No ? then all is lost */ {
  987. #ifdef DEBUG_PRINT
  988.       DEBUG_PRINT("Debug: findFreeSector -> Unable to find free sector!!n");
  989. #endif
  990.     return flGeneralFailure;
  991.   }
  992.   unitHeader = mapUnitHeader(&vol,allocationUnit,&blockAllocMap);
  993.   for (iSector = vol.unitHeaderSectors; iSector < vol.sectorsPerUnit; iSector++) {
  994.     if (LE4(blockAllocMap[iSector]) == FREE_SECTOR) {
  995.       *newAddress = ((LogicalSectorNo) (LE2(unitHeader->logicalUnitNo)) << (vol.unitSizeBits - SECTOR_SIZE_BITS)) +
  996.     iSector;
  997.       return flOK;
  998.     }
  999.   }
  1000. #ifdef DEBUG_PRINT
  1001.     DEBUG_PRINT("Debug: findFreeSector -> Problem marking allocation map!!n");
  1002. #endif
  1003.   return flGeneralFailure; /* what are we doing here ? */
  1004. }
  1005. /*----------------------------------------------------------------------*/
  1006. /*            m a r k A l l o c M a p */
  1007. /* */
  1008. /* Writes a new value to a BAM entry. */
  1009. /*                                                                      */
  1010. /* This routine also updates the free & garbage sector counts. */
  1011. /* */
  1012. /* Parameters:                                                          */
  1013. /* vol : Pointer identifying drive */
  1014. /* sectorAddress : Logical sector no. whose BAM entry to mark */
  1015. /* allocMapEntry : New BAM entry value */
  1016. /* overwrite : Whether we are overwriting some old value */
  1017. /*                                                                      */
  1018. /* Returns:                                                             */
  1019. /* FLStatus : 0 on success, failed otherwise */
  1020. /*----------------------------------------------------------------------*/
  1021. static FLStatus markAllocMap(Flare vol,
  1022.    LogicalSectorNo sectorAddress,
  1023.    VirtualAddress allocMapEntry,
  1024.    FLBoolean overwrite)
  1025. {
  1026.   UnitNo unitNo = (UnitNo) (sectorAddress >> (vol.unitSizeBits - SECTOR_SIZE_BITS));
  1027.   Unit *unit = vol.logicalUnits[unitNo];
  1028.   int sectorInUnit = (unsigned) sectorAddress & (vol.sectorsPerUnit - 1);
  1029.   LEulong bamEntry;
  1030.   if (unitNo >= vol.noOfUnits - vol.noOfTransferUnits)
  1031.     return flGeneralFailure;
  1032.   if (allocMapEntry == GARBAGE_SECTOR)
  1033.     unit->noOfGarbageSectors++;
  1034.   else if (!overwrite) {
  1035.     unit->noOfFreeSectors--;
  1036.     vol.totalFreeSectors--;
  1037.   }
  1038.   toLE4(bamEntry,allocMapEntry);
  1039.   return flashWrite(&vol,
  1040.     physicalBase(&vol,unit) + allocEntryOffset(&vol,sectorInUnit),
  1041.     &bamEntry,
  1042.     sizeof bamEntry,
  1043.     overwrite);
  1044. }
  1045. /*----------------------------------------------------------------------*/
  1046. /*             d e l e t e L o g i c a l S e c t o r */
  1047. /* */
  1048. /* Marks a logical sector as deleted. */
  1049. /* */
  1050. /* Parameters:                                                          */
  1051. /* vol : Pointer identifying drive */
  1052. /* sectorAddress : Logical sector no. to delete */
  1053. /*                                                                      */
  1054. /* Returns:                                                             */
  1055. /* FLStatus : 0 on success, failed otherwise */
  1056. /*----------------------------------------------------------------------*/
  1057. static FLStatus deleteLogicalSector(Flare vol,  LogicalSectorNo sectorAddress)
  1058. {
  1059.   if (sectorAddress == UNASSIGNED_SECTOR ||
  1060.       sectorAddress == DELETED_SECTOR)
  1061.     return flOK;
  1062.   return markAllocMap(&vol,sectorAddress,GARBAGE_SECTOR,TRUE);
  1063. }
  1064. /* forward definition */
  1065. static FLStatus setVirtualMap(Flare vol,
  1066.     VirtualSectorNo sectorNo,
  1067.     LogicalSectorNo newAddress);
  1068. /*----------------------------------------------------------------------*/
  1069. /*            a l l o c a t e A n d W r i t e S e c t o r */
  1070. /* */
  1071. /* Allocates a sector or replacement page and (optionally) writes it. */
  1072. /*                                                                      */
  1073. /* An allocated replacement page also becomes the active replacement  */
  1074. /* page. */
  1075. /* */
  1076. /* Parameters:                                                          */
  1077. /* vol : Pointer identifying drive */
  1078. /* sectorNo : Virtual sector no. to write */
  1079. /* fromAddress : Address of sector data. If NULL, sector is */
  1080. /*   not written. */
  1081. /* replacementPage : This is a replacement page sector. */
  1082. /*                                                                      */
  1083. /* Returns:                                                             */
  1084. /* FLStatus : 0 on success, failed otherwise */
  1085. /*----------------------------------------------------------------------*/
  1086. static FLStatus allocateAndWriteSector(Flare vol,
  1087.      VirtualSectorNo sectorNo,
  1088.      void FAR1 *fromAddress,
  1089.      FLBoolean replacementPage)
  1090. {
  1091.   FLStatus status;
  1092.   LogicalSectorNo sectorAddress;
  1093.   VirtualAddress bamEntry =
  1094. ((VirtualAddress) sectorNo - vol.noOfPages) << SECTOR_SIZE_BITS;
  1095.   long sectorsNeeded = 1;
  1096. #ifdef DEBUG_PRINT
  1097.   DEBUG_PRINT("Debug: calling defrgment routine!!n");
  1098. #endif
  1099.   checkStatus(defragment(&vol,&sectorsNeeded));  /* Organize a free sector */
  1100. #ifdef DEBUG_PRINT
  1101.   DEBUG_PRINT("Debug: calling routine findFreeSector !!n");
  1102. #endif
  1103.   checkStatus(findFreeSector(&vol,sectorNo,&sectorAddress));
  1104.   if (replacementPage)
  1105.     bamEntry |= REPLACEMENT_PAGE;
  1106.   else
  1107.     bamEntry |= DATA_SECTOR;
  1108.   status = markAllocMap(&vol,
  1109. sectorAddress,
  1110. sectorNo < vol.directAddressingSectors ?
  1111.   ALLOCATED_SECTOR : bamEntry,
  1112. FALSE);
  1113.   if (status == flOK && fromAddress)
  1114.     status = flashWrite(&vol,
  1115. logical2Physical(&vol,sectorAddress),
  1116. fromAddress,
  1117. SECTOR_SIZE,
  1118. 0);
  1119.   if (sectorNo < vol.directAddressingSectors && status == flOK)
  1120.     status = markAllocMap(&vol,
  1121.   sectorAddress,
  1122.   bamEntry,
  1123.   TRUE);
  1124.   if (status == flOK)
  1125.     if (replacementPage) {
  1126.       vol.replacementPageAddress = sectorAddress;
  1127.       vol.replacementPageNo = sectorNo;
  1128.     }
  1129.     else
  1130.       status = setVirtualMap(&vol,sectorNo,sectorAddress);
  1131.   if (status != flOK)
  1132.     status = markAllocMap(&vol,sectorAddress,GARBAGE_SECTOR,TRUE);
  1133. #ifdef DEBUG_PRINT
  1134.   if (status != flOK)
  1135.   DEBUG_PRINT("Debug: Bad status code at Allocate and Write sector !n");
  1136.   DEBUG_PRINT("Debug: MarkAllocMap returned %d !n", status);
  1137. #endif
  1138.   return status;
  1139. }
  1140. /*----------------------------------------------------------------------*/
  1141. /*            c l o s e R e p l a c e m e n t P a g e */
  1142. /* */
  1143. /* Closes the replacement page by merging it with the primary page. */
  1144. /* */
  1145. /* Parameters:                                                          */
  1146. /* vol : Pointer identifying drive */
  1147. /*                                                                      */
  1148. /* Returns:                                                             */
  1149. /* FLStatus : 0 on success, failed otherwise */
  1150. /*----------------------------------------------------------------------*/
  1151. static FLStatus closeReplacementPage(Flare vol)
  1152. {
  1153.   FLStatus status;
  1154. #ifdef SINGLE_BUFFER
  1155.   int i;
  1156.   LogicalSectorNo nextReplacementPageAddress = vol.replacementPageAddress;
  1157.   VirtualSectorNo firstSectorNo =
  1158. ((VirtualSectorNo) vol.replacementPageNo << (PAGE_SIZE_BITS - SECTOR_SIZE_BITS)) +
  1159. vol.noOfPages;
  1160. pageRetry:
  1161.   for (i = 0; i < ADDRESSES_PER_SECTOR; i++) {
  1162.     LogicalSectorNo logicalSectorNo = virtual2Logical(&vol,firstSectorNo + i);
  1163.     LEulong entryToWrite;
  1164.     toLE4(entryToWrite,logicalSectorNo == UNASSIGNED_SECTOR ?
  1165.        UNASSIGNED_ADDRESS :
  1166.        (LogicalAddress) logicalSectorNo << SECTOR_SIZE_BITS);
  1167.     if (flashWrite(&vol,
  1168.    logical2Physical(&vol,nextReplacementPageAddress) +
  1169. i * sizeof(LogicalAddress),
  1170.    &entryToWrite,
  1171.    sizeof entryToWrite,
  1172.    OVERWRITE) != flOK)
  1173.       break;
  1174.   }
  1175.   if (i < ADDRESSES_PER_SECTOR &&
  1176.       nextReplacementPageAddress == vol.replacementPageAddress) {
  1177.     /* Uh oh. Trouble. Let's replace this replacement page. */
  1178.     LogicalSectorNo prevReplacementPageAddress = vol.replacementPageAddress;
  1179.     checkStatus(allocateAndWriteSector(&vol,vol.replacementPageNo,NULL,TRUE));
  1180.     nextReplacementPageAddress = vol.replacementPageAddress;
  1181.     vol.replacementPageAddress = prevReplacementPageAddress;
  1182.     goto pageRetry;
  1183.   }
  1184.   if (nextReplacementPageAddress != vol.replacementPageAddress) {
  1185.     LogicalSectorNo prevReplacementPageAddress = vol.replacementPageAddress;
  1186.     vol.replacementPageAddress = nextReplacementPageAddress;
  1187.     checkStatus(deleteLogicalSector(&vol,prevReplacementPageAddress));
  1188.   }
  1189. #else
  1190.   setupMapCache(&vol,vol.replacementPageNo); /* read replacement page into map cache */
  1191.   status = flashWrite(&vol,
  1192.       logical2Physical(&vol,vol.replacementPageAddress),
  1193.       mapCache,SECTOR_SIZE,OVERWRITE);
  1194.   if (status != flOK) {
  1195.     /* Uh oh. Trouble. Let's replace this replacement page. */
  1196.     LogicalSectorNo prevReplacementPageAddress = vol.replacementPageAddress;
  1197.     checkStatus(allocateAndWriteSector(&vol,vol.replacementPageNo,mapCache,TRUE));
  1198.     checkStatus(deleteLogicalSector(&vol,prevReplacementPageAddress));
  1199.   }
  1200. #endif
  1201.   checkStatus(setVirtualMap(&vol,vol.replacementPageNo,vol.replacementPageAddress));
  1202.   checkStatus(markAllocMap(&vol,
  1203.    vol.replacementPageAddress,
  1204.    (((VirtualAddress) vol.replacementPageNo - vol.noOfPages)
  1205. << SECTOR_SIZE_BITS) | DATA_SECTOR,
  1206.    TRUE));
  1207.   vol.replacementPageNo = UNASSIGNED_SECTOR;
  1208.   return flOK;
  1209. }
  1210. /*----------------------------------------------------------------------*/
  1211. /*                 s e t V i r t u a l M a p */
  1212. /* */
  1213. /* Changes an entry in the virtual map */
  1214. /* */
  1215. /* Parameters:                                                          */
  1216. /* vol : Pointer identifying drive */
  1217. /* sectorNo : Virtual sector no. whose entry is changed. */
  1218. /* newAddress : Logical sector no. to assign in Virtual Map. */
  1219. /*                                                                      */
  1220. /* Returns:                                                             */
  1221. /* FLStatus : 0 on success, failed otherwise */
  1222. /*----------------------------------------------------------------------*/
  1223. static FLStatus setVirtualMap(Flare vol,
  1224.     VirtualSectorNo sectorNo,
  1225.     LogicalSectorNo newAddress)
  1226. {
  1227.   unsigned pageNo;
  1228.   int sectorInPage;
  1229.   CardAddress virtualMapEntryAddress;
  1230.   LEulong addressToWrite;
  1231.   LogicalAddress oldAddress;
  1232.   LogicalSectorNo updatedPage;
  1233.   vol.mappedSectorNo = UNASSIGNED_SECTOR;
  1234.   if (sectorNo < vol.directAddressingSectors) {
  1235.     checkStatus(deleteLogicalSector(&vol,vol.pageTable[sectorNo]));
  1236.     vol.pageTable[sectorNo] = newAddress;
  1237.     return flOK;
  1238.   }
  1239.   sectorNo -= vol.noOfPages;
  1240.   pageNo = sectorNo >> (PAGE_SIZE_BITS - SECTOR_SIZE_BITS);
  1241.   sectorInPage = (int) (sectorNo) % ADDRESSES_PER_SECTOR;
  1242.   updatedPage = vol.pageTable[pageNo];
  1243.   virtualMapEntryAddress = logical2Physical(&vol,updatedPage) +
  1244.  sectorInPage * sizeof(LogicalAddress);
  1245.   oldAddress = LE4(*(LEulong FAR0 *)
  1246. vol.flash.map(&vol.flash,virtualMapEntryAddress,sizeof(LogicalAddress)));
  1247.   if (oldAddress == DELETED_ADDRESS && vol.replacementPageNo == pageNo) {
  1248.     updatedPage = vol.replacementPageAddress;
  1249.     virtualMapEntryAddress = logical2Physical(&vol,updatedPage) +
  1250.    sectorInPage * sizeof(LogicalAddress);
  1251.     oldAddress = LE4(*(LEulong FAR0 *)
  1252.   vol.flash.map(&vol.flash,virtualMapEntryAddress,sizeof(LogicalAddress)));
  1253.   }
  1254.   if (newAddress == DELETED_ADDRESS && ((unsigned long)oldAddress == UNASSIGNED_ADDRESS))
  1255.     return flOK;
  1256.   toLE4(addressToWrite,(LogicalAddress) newAddress << SECTOR_SIZE_BITS);
  1257.   if (cannotWriteOver(LE4(addressToWrite),oldAddress)) {
  1258.     FLStatus status;
  1259.     if (pageNo != vol.replacementPageNo ||
  1260. updatedPage == vol.replacementPageAddress) {
  1261.       if (vol.replacementPageNo != UNASSIGNED_SECTOR)
  1262. checkStatus(closeReplacementPage(&vol));
  1263.       checkStatus(allocateAndWriteSector(&vol,pageNo,NULL,TRUE));
  1264.     }
  1265.     status = flashWrite(&vol,
  1266. logical2Physical(&vol,vol.replacementPageAddress) +
  1267.       sectorInPage * sizeof(LogicalAddress),
  1268. &addressToWrite,
  1269. sizeof addressToWrite,
  1270. 0);
  1271.     if (status != flOK) {
  1272.       closeReplacementPage(&vol);
  1273. /* we may get a write-error because a
  1274.    previous cache update did not complete. */
  1275.       return status;
  1276.     }
  1277.     toLE4(addressToWrite,DELETED_ADDRESS);
  1278.     updatedPage = vol.pageTable[pageNo];
  1279.   }
  1280.   checkStatus(flashWrite(&vol,
  1281.  logical2Physical(&vol,updatedPage) +
  1282.    sectorInPage * sizeof(LogicalAddress),
  1283.  &addressToWrite,
  1284.  sizeof addressToWrite,
  1285.  (unsigned long)oldAddress != UNASSIGNED_ADDRESS));
  1286. #ifndef SINGLE_BUFFER
  1287.   if (buffer.sectorNo == pageNo && buffer.owner == &vol)
  1288.     toLE4(mapCache[sectorInPage],(LogicalAddress) newAddress << SECTOR_SIZE_BITS);
  1289. #endif
  1290.   return deleteLogicalSector(&vol,(LogicalSectorNo) (oldAddress >> SECTOR_SIZE_BITS));
  1291. }
  1292. /*----------------------------------------------------------------------*/
  1293. /*            c h e c k F o r W r i t e I n p l a c e */
  1294. /* */
  1295. /* Checks possibility for writing Flash data inplace. */
  1296. /* */
  1297. /* Parameters:                                                          */
  1298. /* newData : New data to write. */
  1299. /* oldData : Old data at this location. */
  1300. /*                                                                      */
  1301. /* Returns:                                                             */
  1302. /* < 0 => Writing inplace not possible */
  1303. /* >= 0 => Writing inplace is possible. Value indicates    */
  1304. /* how many bytes at the start of data are */
  1305. /* identical and may be skipped. */
  1306. /*----------------------------------------------------------------------*/
  1307. static int checkForWriteInplace(long FAR1 *newData,
  1308. long FAR0 *oldData)
  1309. {
  1310.   int i;
  1311.   int skipBytes = 0;
  1312.   FLBoolean stillSame = TRUE;
  1313.   for (i = SECTOR_SIZE / sizeof *newData; i > 0; i--, newData++, oldData++) {
  1314.     if (cannotWriteOver(*newData,*oldData))
  1315.       return -1;
  1316.     if (stillSame && *newData == *oldData)
  1317.       skipBytes += sizeof *newData;
  1318.     else
  1319.       stillSame = FALSE;
  1320.   }
  1321.   return skipBytes;
  1322. }
  1323. /*----------------------------------------------------------------------*/
  1324. /*                     i n i t F T L */
  1325. /* */
  1326. /* Initializes essential volume data as a preparation for mount or */
  1327. /* format. */
  1328. /* */
  1329. /* Parameters:                                                          */
  1330. /* vol : Pointer identifying drive */
  1331. /*                                                                      */
  1332. /* Returns:                                                             */
  1333. /* FLStatus : 0 on success, failed otherwise */
  1334. /*----------------------------------------------------------------------*/
  1335. static FLStatus initFTL(Flare vol)
  1336. {
  1337.   long int size = 1;
  1338.   for (vol.erasableBlockSizeBits = 0; size < vol.flash.erasableBlockSize;
  1339.        vol.erasableBlockSizeBits++, size <<= 1);
  1340.   vol.unitSizeBits = vol.erasableBlockSizeBits;
  1341.   if (vol.unitSizeBits < 16)
  1342.     vol.unitSizeBits = 16; /* At least 64 KB */
  1343.   vol.noOfUnits = (unsigned) ((vol.flash.noOfChips * vol.flash.chipSize) >> vol.unitSizeBits);
  1344.   vol.unitOffsetMask = (1L << vol.unitSizeBits) - 1;
  1345.   vol.sectorsPerUnit = 1 << (vol.unitSizeBits - SECTOR_SIZE_BITS);
  1346.   vol.bamOffset = sizeof(UnitHeader);
  1347.   vol.unitHeaderSectors = ((allocEntryOffset(&vol,vol.sectorsPerUnit) - 1) >>
  1348.     SECTOR_SIZE_BITS) + 1;
  1349.   vol.transferUnit = NULL;
  1350.   vol.replacementPageNo = UNASSIGNED_SECTOR;
  1351.   vol.badFormat = TRUE; /* until mount completes */
  1352.   vol.mappedSectorNo = UNASSIGNED_SECTOR;
  1353.   vol.currWearLevelingInfo = 0;
  1354. #ifdef BACKGROUND
  1355.   vol.unitEraseInProgress = NULL;
  1356.   vol.garbageCollectStatus = flOK;
  1357.   vol.mirrorOffset = 0;
  1358. #endif
  1359.   return flOK;
  1360. }
  1361. /*----------------------------------------------------------------------*/
  1362. /*                   i n i t T a b l e s */
  1363. /* */
  1364. /* Allocates and initializes the dynamic volume table, including the */
  1365. /* unit tables and secondary virtual map. */
  1366. /* */
  1367. /* Parameters:                                                          */
  1368. /* vol : Pointer identifying drive */
  1369. /*                                                                      */
  1370. /* Returns:                                                             */
  1371. /* FLStatus : 0 on success, failed otherwise */
  1372. /*----------------------------------------------------------------------*/
  1373. static FLStatus initTables(Flare vol)
  1374. {
  1375.   VirtualSectorNo iSector;
  1376.   UnitNo iUnit;
  1377.   /* Allocate the conversion tables */
  1378. #ifdef MALLOC_TFFS
  1379.   vol.physicalUnits = (Unit *) MALLOC_TFFS(vol.noOfUnits * sizeof(Unit));
  1380.   vol.logicalUnits = (UnitPtr *) MALLOC_TFFS(vol.noOfUnits * sizeof(UnitPtr));
  1381.   vol.pageTable = (LogicalSectorNo *)
  1382.      MALLOC_TFFS(vol.directAddressingSectors * sizeof(LogicalSectorNo));
  1383.   if (vol.physicalUnits == NULL ||
  1384.       vol.logicalUnits == NULL ||
  1385.       vol.pageTable == NULL)
  1386.     return flNotEnoughMemory;
  1387. #else
  1388.   char *heapPtr;
  1389.   heapPtr = vol.heap;
  1390.   vol.physicalUnits = (Unit *) heapPtr;
  1391.   heapPtr += vol.noOfUnits * sizeof(Unit);
  1392.   vol.logicalUnits = (UnitPtr *) heapPtr;
  1393.   heapPtr += vol.noOfUnits * sizeof(UnitPtr);
  1394.   vol.pageTable = (LogicalSectorNo *) heapPtr;
  1395.   heapPtr += vol.directAddressingSectors * sizeof(LogicalSectorNo);
  1396.   if (heapPtr > vol.heap + sizeof vol.heap)
  1397.     return flNotEnoughMemory;
  1398. #endif
  1399. #ifndef SINGLE_BUFFER
  1400.   vol.volBuffer = flBufferOf(flSocketNoOf(vol.flash.socket));
  1401. #endif
  1402.   buffer.sectorNo = UNASSIGNED_SECTOR;
  1403.   for (iSector = 0; iSector < vol.directAddressingSectors; iSector++)
  1404.     vol.pageTable[iSector] = UNASSIGNED_SECTOR;
  1405.   for (iUnit = 0; iUnit < vol.noOfUnits; iUnit++)
  1406.     vol.logicalUnits[iUnit] = NULL;
  1407.   return flOK;
  1408. }
  1409. /*----------------------------------------------------------------------*/
  1410. /*                    m a p S e c t o r */
  1411. /* */
  1412. /* Maps and returns location of a given sector no. */
  1413. /* NOTE: This function is used in place of a read-sector operation. */
  1414. /* */
  1415. /* A one-sector cache is maintained to save on map operations. */
  1416. /* */
  1417. /* Parameters:                                                          */
  1418. /* vol : Pointer identifying drive */
  1419. /* sectorNo : Sector no. to read */
  1420. /* physAddress : Optional pointer to receive sector address */
  1421. /*                                                                      */
  1422. /* Returns:                                                             */
  1423. /* Pointer to physical sector location. NULL returned if sector */
  1424. /* does not exist. */
  1425. /*----------------------------------------------------------------------*/
  1426. static const void FAR0 *mapSector(Flare vol, SectorNo sectorNo, CardAddress *physAddress)
  1427. {
  1428.   if (sectorNo != vol.mappedSectorNo || vol.flash.socket->remapped) {
  1429.     LogicalSectorNo sectorAddress;
  1430.     if (sectorNo >= vol.virtualSectors)
  1431.       vol.mappedSector = NULL;
  1432.     else {
  1433.       sectorAddress = virtual2Logical(&vol,sectorNo + vol.noOfPages);
  1434.       if (sectorAddress == UNASSIGNED_SECTOR || sectorAddress == DELETED_SECTOR)
  1435. vol.mappedSector = NULL; /* no such sector */
  1436.       else {
  1437. vol.mappedSectorAddress = logical2Physical(&vol,sectorAddress);
  1438. vol.mappedSector = vol.flash.map(&vol.flash,
  1439.  vol.mappedSectorAddress,
  1440.  SECTOR_SIZE);
  1441.       }
  1442.     }
  1443.     vol.mappedSectorNo = sectorNo;
  1444.     vol.flash.socket->remapped = FALSE;
  1445.   }
  1446.   if (physAddress)
  1447.     *physAddress = vol.mappedSectorAddress;
  1448.   return vol.mappedSector;
  1449. }
  1450. /*----------------------------------------------------------------------*/
  1451. /*                 w r i t e S e c t o r */
  1452. /* */
  1453. /* Writes a sector. */
  1454. /* */
  1455. /* Parameters:                                                          */
  1456. /* vol : Pointer identifying drive */
  1457. /* sectorNo : Sector no. to write */
  1458. /*                                                                      */
  1459. /* Returns:                                                             */
  1460. /* FLStatus : 0 on success, failed otherwise */
  1461. /*----------------------------------------------------------------------*/
  1462. static FLStatus writeSector(Flare vol,  SectorNo sectorNo, void FAR1 *fromAddress)
  1463. {
  1464.   LogicalSectorNo oldSectorAddress;
  1465.   int skipBytes;
  1466.   FLStatus status;
  1467.   if (vol.badFormat)
  1468.     return flBadFormat;
  1469.   if (sectorNo >= vol.virtualSectors)
  1470.     return flSectorNotFound;
  1471.   sectorNo += vol.noOfPages;
  1472.   oldSectorAddress = virtual2Logical(&vol,sectorNo);
  1473.   if (oldSectorAddress != UNASSIGNED_SECTOR && oldSectorAddress != DELETED_SECTOR &&
  1474.       (skipBytes = checkForWriteInplace((long FAR1 *) fromAddress,
  1475.      (long FAR0 *) mapLogical(&vol,oldSectorAddress))) >= 0) {
  1476.     if (skipBytes < SECTOR_SIZE)
  1477.       status = flashWrite(&vol,
  1478.   logical2Physical(&vol,oldSectorAddress) + skipBytes,
  1479.   (char FAR1 *) fromAddress + skipBytes,
  1480.   SECTOR_SIZE - skipBytes,
  1481.   OVERWRITE);
  1482.     else
  1483.       status = flOK; /* nothing to write */
  1484.   }
  1485.   else
  1486.     status = allocateAndWriteSector(&vol,sectorNo,fromAddress,FALSE);
  1487.   if (status == flWriteFault) /* Automatic retry */
  1488.     status = allocateAndWriteSector(&vol,sectorNo,fromAddress,FALSE);
  1489.   return status;
  1490. }
  1491. /*----------------------------------------------------------------------*/
  1492. /*                 t l S e t B u s y */
  1493. /* */
  1494. /* Notifies the start and end of a file-system operation. */
  1495. /* */
  1496. /* Parameters:                                                          */
  1497. /* vol : Pointer identifying drive */
  1498. /*      state : TFFS_ON (1) = operation entry */
  1499. /*   TFFS_OFF(0) = operation exit */
  1500. /*                                                                      */
  1501. /*----------------------------------------------------------------------*/
  1502. static void tlSetBusy(Flare vol, FLBoolean state)
  1503. {
  1504. #ifdef BACKGROUND
  1505.   if (vol.unitEraseInProgress)
  1506.     flBackground(state == TFFS_ON ? BG_SUSPEND : BG_RESUME);
  1507. #endif
  1508. }
  1509. /*----------------------------------------------------------------------*/
  1510. /*                d e l e t e S e c t o r */
  1511. /* */
  1512. /* Marks contiguous sectors as deleted */
  1513. /* */
  1514. /* Parameters:                                                          */
  1515. /* vol : Pointer identifying drive */
  1516. /* sectorNo : First sector no. to delete */
  1517. /* noOfSectors : No. of sectors to delete */
  1518. /*                                                                      */
  1519. /* Returns:                                                             */
  1520. /* FLStatus : 0 on success, failed otherwise */
  1521. /*----------------------------------------------------------------------*/
  1522. static FLStatus deleteSector(Flare vol,  SectorNo sectorNo, int noOfSectors)
  1523. {
  1524.   int iSector;
  1525.   if (vol.badFormat)
  1526.     return flBadFormat;
  1527.   if (sectorNo + noOfSectors > vol.virtualSectors)
  1528.     return flSectorNotFound;
  1529.   sectorNo += vol.noOfPages;
  1530.   for (iSector = 0; iSector < noOfSectors; iSector++, sectorNo++)
  1531.     checkStatus(setVirtualMap(&vol,sectorNo,DELETED_SECTOR));
  1532.   return flOK;
  1533. }
  1534. #ifdef FORMAT_VOLUME
  1535. /*----------------------------------------------------------------------*/
  1536. /*               s e c t o r s I n V o l u m e */
  1537. /* */
  1538. /* Gets the total number of sectors in the volume */
  1539. /* */
  1540. /* Parameters:                                                          */
  1541. /* vol : Pointer identifying drive */
  1542. /*                                                                      */
  1543. /* Returns:                                                             */
  1544. /* Number of sectors in the volume */
  1545. /*----------------------------------------------------------------------*/
  1546. static SectorNo sectorsInVolume(Flare vol)
  1547. {
  1548.   return vol.virtualSectors;
  1549. }
  1550. /*----------------------------------------------------------------------*/
  1551. /*                  f o r m a t F T L */
  1552. /* */
  1553. /* Formats the Flash volume for FTL */
  1554. /* */
  1555. /* Parameters:                                                          */
  1556. /* volNo : Volume no. */
  1557. /* formatParams : Address of FormatParams structure to use */
  1558. /*                                                                      */
  1559. /* Returns:                                                             */
  1560. /* FLStatus : 0 on success, failed otherwise */
  1561. /*----------------------------------------------------------------------*/
  1562. /*static*/ FLStatus formatFTL(FLFlash *flash, FormatParams FAR1 *formatParams)
  1563. {
  1564.   Flare vol = &vols[flSocketNoOf(flash->socket)];
  1565.   UnitNo iUnit;
  1566.   int iPage;
  1567.   SectorNo iSector;
  1568.   unsigned noOfBadUnits = 0;
  1569.   LEulong *formatEntries;
  1570.   vol.flash = *flash;
  1571.   checkStatus(initFTL(&vol));
  1572.   vol.firstPhysicalEUN =
  1573.       (UnitNo) ((formatParams->bootImageLen - 1) >> vol.unitSizeBits) + 1;
  1574.   vol.noOfTransferUnits = formatParams->noOfSpareUnits;
  1575.   if (vol.noOfUnits <= vol.firstPhysicalEUN + formatParams->noOfSpareUnits) {
  1576. #ifdef DEBUG_PRINT
  1577.       DEBUG_PRINT("Debug: Volume too small !!n");
  1578. #endif
  1579.     return flVolumeTooSmall;
  1580.   }
  1581.   vol.virtualSectors = (unsigned long) (vol.noOfUnits - vol.firstPhysicalEUN - formatParams->noOfSpareUnits) *
  1582.    (vol.sectorsPerUnit - vol.unitHeaderSectors) *
  1583.    formatParams->percentUse / 100;
  1584.   vol.noOfPages = (((long) vol.virtualSectors * SECTOR_SIZE - 1) >> PAGE_SIZE_BITS) + 1;
  1585.   /* take off size of virtual table, and one extra sector for sector writes */
  1586.   vol.virtualSectors -= (vol.noOfPages + 1);
  1587.   vol.directAddressingMemory = formatParams->vmAddressingLimit;
  1588.   vol.directAddressingSectors = (SectorNo) (formatParams->vmAddressingLimit / SECTOR_SIZE) +
  1589. vol.noOfPages;
  1590.   checkStatus(initTables(&vol));
  1591.   tffsset(uh,0xff,SECTOR_SIZE);
  1592.   toLE2(uh->noOfUnits,vol.noOfUnits - vol.firstPhysicalEUN);
  1593.   toLE2(uh->firstPhysicalEUN,vol.firstPhysicalEUN);
  1594.   uh->noOfTransferUnits = (unsigned char) vol.noOfTransferUnits;
  1595.   tffscpy(uh->formatPattern,FORMAT_PATTERN,sizeof uh->formatPattern);
  1596.   uh->log2SectorSize = SECTOR_SIZE_BITS;
  1597.   uh->log2UnitSize = vol.unitSizeBits;
  1598.   toLE4(uh->directAddressingMemory,vol.directAddressingMemory);
  1599.   uh->flags = 0;
  1600.   uh->eccCode = 0xff;
  1601.   toLE4(uh->serialNumber,0);
  1602.   toLE4(uh->altEUHoffset,0);
  1603.   toLE4(uh->virtualMediumSize,(long) vol.virtualSectors * SECTOR_SIZE);
  1604.   toLE2(uh->noOfPages,vol.noOfPages);
  1605.   if (formatParams->embeddedCISlength > 0) {
  1606.     tffscpy(uh->embeddedCIS,formatParams->embeddedCIS,formatParams->embeddedCISlength);
  1607.     vol.bamOffset = sizeof(UnitHeader) - sizeof uh->embeddedCIS +
  1608.     (formatParams->embeddedCISlength + 3) / 4 * 4;
  1609.   }
  1610.   toLE4(uh->BAMoffset,vol.bamOffset);
  1611.   formatEntries = (LEulong *) ((char *) uh + allocEntryOffset(&vol,0));
  1612.   for (iSector = 0; iSector < vol.unitHeaderSectors; iSector++)
  1613.     toLE4(formatEntries[iSector], FORMAT_SECTOR);
  1614.   for (iUnit = vol.firstPhysicalEUN; iUnit < vol.noOfUnits; iUnit++) {
  1615.     FLStatus status;
  1616.     status = formatUnit(&vol,&vol.physicalUnits[iUnit]);
  1617.     if (status != flOK)
  1618.       status = formatUnit(&vol,&vol.physicalUnits[iUnit]); /* Do it again */
  1619.     if (status == flWriteFault) {
  1620.       noOfBadUnits++;
  1621.       if (noOfBadUnits >= formatParams->noOfSpareUnits) {
  1622. #ifdef DEBUG_PRINT
  1623.   DEBUG_PRINT("Too many bad units !! n");
  1624. #endif
  1625. return status;
  1626.       }
  1627.       else
  1628. vol.transferUnit = &vol.physicalUnits[iUnit];
  1629.     }
  1630.     else if (status == flOK) {
  1631.       if (iUnit - noOfBadUnits < vol.noOfUnits - formatParams->noOfSpareUnits) {
  1632. checkStatus(assignUnit(&vol,
  1633.        &vol.physicalUnits[iUnit],
  1634.                                (UnitNo)(iUnit - noOfBadUnits)));
  1635.         vol.physicalUnits[iUnit].noOfFreeSectors = vol.sectorsPerUnit - vol.unitHeaderSectors;
  1636. vol.logicalUnits[iUnit - noOfBadUnits] = &vol.physicalUnits[iUnit];
  1637.       }
  1638.       else
  1639. vol.transferUnit = &vol.physicalUnits[iUnit];
  1640.     }
  1641.     else {
  1642. #ifdef DEBUG_PRINT
  1643. DEBUG_PRINT("Should not have gotten here !!n");
  1644. #endif
  1645.       return status;
  1646.     }
  1647.     if (formatParams->progressCallback)
  1648.       checkStatus((*formatParams->progressCallback)
  1649. (vol.noOfUnits - vol.firstPhysicalEUN,
  1650.  (iUnit + 1) - vol.firstPhysicalEUN));
  1651.   }
  1652.   /* Allocate and write all page sectors */
  1653.   vol.totalFreeSectors = vol.noOfPages; /* Fix for SPR 31147 */
  1654.   for (iPage = 0; iPage < vol.noOfPages; iPage++)
  1655.     checkStatus(allocateAndWriteSector(&vol,iPage,NULL,FALSE));
  1656.   return flOK;
  1657. }
  1658. #endif
  1659. /*----------------------------------------------------------------------*/
  1660. /*                d i s m o u n t F T L */
  1661. /* */
  1662. /* Dismount FTL volume */
  1663. /* */
  1664. /* Parameters:                                                          */
  1665. /* vol : Pointer identifying drive */
  1666. /* */
  1667. /*----------------------------------------------------------------------*/
  1668. static void dismountFTL(Flare vol)
  1669. {
  1670. #ifdef MALLOC_TFFS
  1671.   FREE_TFFS(vol.physicalUnits);
  1672.   FREE_TFFS(vol.logicalUnits);
  1673.   FREE_TFFS(vol.pageTable);
  1674. #endif
  1675. }
  1676. /*----------------------------------------------------------------------*/
  1677. /*                  m o u n t F T L */
  1678. /* */
  1679. /* Mount FTL volume */
  1680. /* */
  1681. /* Parameters:                                                          */
  1682. /* volNo : Volume no. */
  1683. /* tl : Where to store translation layer methods */
  1684. /*      volForCallback : Pointer to FLFlash structure for power on */
  1685. /*   callback routine. */
  1686. /*                                                                      */
  1687. /* Returns:                                                             */
  1688. /* FLStatus : 0 on success, failed otherwise */
  1689. /*----------------------------------------------------------------------*/
  1690. /*static*/ FLStatus mountFTL(FLFlash *flash, TL *tl, FLFlash **volForCallback)
  1691. {
  1692.   Flare vol = &vols[flSocketNoOf(flash->socket)];
  1693.   UnitHeader unitHeader;
  1694.   UnitNo iUnit;
  1695.   int iPage;
  1696.   vol.flash = *flash;
  1697.   *volForCallback = &vol.flash;
  1698.   checkStatus(initFTL(&vol));
  1699.   /* Find the first properly formatted unit */
  1700.   for (iUnit = 0; iUnit < vol.noOfUnits; iUnit++) {
  1701.     vol.flash.read(&vol.flash,
  1702.        (CardAddress) iUnit << vol.unitSizeBits,
  1703.        &unitHeader,
  1704.        sizeof(UnitHeader),
  1705.        0);
  1706.     if (verifyFormat(&unitHeader)) {
  1707.       if (unitHeader.flags || unitHeader.log2SectorSize != SECTOR_SIZE_BITS ||
  1708.   (unitHeader.eccCode != 0xff && unitHeader.eccCode != 0))
  1709. return flBadFormat;
  1710.       break;
  1711.     }
  1712.   }
  1713.   if (iUnit >= vol.noOfUnits)
  1714.     return flUnknownMedia;
  1715.   /* Get volume information from unit header */
  1716.   vol.noOfUnits = LE2(unitHeader.noOfUnits);
  1717.   vol.noOfTransferUnits = unitHeader.noOfTransferUnits;
  1718.   vol.firstPhysicalEUN = LE2(unitHeader.firstPhysicalEUN);
  1719.   vol.bamOffset = LE4(unitHeader.BAMoffset);
  1720.   vol.virtualSectors = (SectorNo) (LE4(unitHeader.virtualMediumSize) >> SECTOR_SIZE_BITS);
  1721.   vol.noOfPages = LE2(unitHeader.noOfPages);
  1722.   vol.noOfUnits += vol.firstPhysicalEUN;
  1723.   vol.unitSizeBits = unitHeader.log2UnitSize;
  1724.   vol.directAddressingMemory = LE4(unitHeader.directAddressingMemory);
  1725.   vol.directAddressingSectors = vol.noOfPages +
  1726.   (SectorNo) (vol.directAddressingMemory >> SECTOR_SIZE_BITS);
  1727.   vol.unitOffsetMask = (1L << vol.unitSizeBits) - 1;
  1728.   vol.sectorsPerUnit = 1 << (vol.unitSizeBits - SECTOR_SIZE_BITS);
  1729.   vol.unitHeaderSectors = ((allocEntryOffset(&vol,vol.sectorsPerUnit) - 1) >>
  1730.     SECTOR_SIZE_BITS) + 1;
  1731.   if (vol.noOfUnits <= vol.firstPhysicalEUN ||
  1732.       LE4(unitHeader.virtualMediumSize) > MAX_VOLUME_MBYTES * 0x100000l ||
  1733.       allocEntryOffset(&vol,vol.unitHeaderSectors) > SECTOR_SIZE ||
  1734.       (int)(vol.virtualSectors >> (PAGE_SIZE_BITS - SECTOR_SIZE_BITS)) > vol.noOfPages ||
  1735.       (int)(vol.virtualSectors >> (vol.unitSizeBits - SECTOR_SIZE_BITS)) > (vol.noOfUnits - vol.firstPhysicalEUN))
  1736.     return flBadFormat;
  1737.   checkStatus(initTables(&vol));
  1738.   vol.totalFreeSectors = 0;
  1739.   /* Mount all units */
  1740.   for (iUnit = vol.firstPhysicalEUN; iUnit < vol.noOfUnits; iUnit++)
  1741.     mountUnit(&vol,&vol.physicalUnits[iUnit]);
  1742.   /* Verify the conversion tables */
  1743.   vol.badFormat = FALSE;
  1744.   for (iUnit = vol.firstPhysicalEUN; iUnit < vol.noOfUnits - vol.noOfTransferUnits; iUnit++)
  1745.     if (vol.logicalUnits[iUnit] == NULL)
  1746.       vol.badFormat = TRUE;
  1747.   if (vol.replacementPageNo != UNASSIGNED_SECTOR &&
  1748.       vol.pageTable[vol.replacementPageNo] == UNASSIGNED_SECTOR) {
  1749.     /* A lonely replacement page. Mark it as a regular page (may fail   */
  1750.     /* because of write protection) and use it. */
  1751.     markAllocMap(&vol,
  1752.  vol.replacementPageAddress,
  1753.  (((VirtualAddress) vol.replacementPageNo - vol.noOfPages)
  1754. << SECTOR_SIZE_BITS) | DATA_SECTOR,
  1755.  TRUE);
  1756.     vol.pageTable[vol.replacementPageNo] = vol.replacementPageAddress;
  1757.     vol.replacementPageNo = UNASSIGNED_SECTOR;
  1758.   }
  1759.   for (iPage = 0; iPage < vol.noOfPages; iPage++)
  1760.     if (vol.pageTable[iPage] == UNASSIGNED_SECTOR)
  1761.       vol.badFormat = TRUE;
  1762.   tl->rec = &vol;
  1763.   tl->mapSector = mapSector;
  1764.   tl->writeSector = writeSector;
  1765.   tl->deleteSector = deleteSector;
  1766. #if defined(DEFRAGMENT_VOLUME) || defined(SINGLE_BUFFER)
  1767.   tl->defragment = defragment;
  1768. #endif
  1769. #ifdef FORMAT_VOLUME
  1770.   tl->sectorsInVolume = sectorsInVolume;
  1771. #endif
  1772.   tl->tlSetBusy = tlSetBusy;
  1773.   tl->dismount = dismountFTL;
  1774.   return vol.badFormat ? flBadFormat : flOK;
  1775. }
  1776. #if FALSE
  1777. /*----------------------------------------------------------------------*/
  1778. /*               f l R e g i s t e r F T L */
  1779. /* */
  1780. /* Register this translation layer */
  1781. /* */
  1782. /* Parameters:                                                          */
  1783. /* None */
  1784. /*                                                                      */
  1785. /* Returns: */
  1786. /*  FLStatus  : 0 on succes, otherwise failure */
  1787. /*----------------------------------------------------------------------*/
  1788. FLStatus flRegisterFTL(void)
  1789. {
  1790.   if (noOfTLs >= TLS)
  1791.     return flTooManyComponents;
  1792.   tlTable[noOfTLs].mountRoutine = mountFTL;
  1793. #ifdef FORMAT_VOLUME
  1794.   tlTable[noOfTLs].formatRoutine = formatFTL;
  1795. #endif
  1796.   noOfTLs++;
  1797.   return flOK;
  1798. }
  1799. #endif /* FALSE */