|
|
/***********************************************************************************/ /* M-Systems Confidential */ /* Copyright (C) M-Systems Flash Disk Pioneers Ltd. 1995-2001 */ /* All Rights Reserved */ /***********************************************************************************/ /* NOTICE OF M-SYSTEMS OEM */ /* SOFTWARE LICENSE AGREEMENT */ /* */ /* THE USE OF THIS SOFTWARE IS GOVERNED BY A SEPARATE LICENSE */ /* AGREEMENT BETWEEN THE OEM AND M-SYSTEMS. REFER TO THAT AGREEMENT */ /* FOR THE SPECIFIC TERMS AND CONDITIONS OF USE, */ /* OR CONTACT M-SYSTEMS FOR LICENSE ASSISTANCE: */ /* E-MAIL = [email protected] */ /***********************************************************************************/
/*
* $Log: V:/Flite/archives/TrueFFS5/Src/flmtl.c_V $ * * Rev 1.11 Nov 08 2001 10:49:20 oris * Added support for up to 1GB DiskOnChips. * * Rev 1.10 Sep 24 2001 18:23:40 oris * Removed warnings. * * Rev 1.9 Sep 15 2001 23:46:16 oris * Changed progress callback routine to support up to 64K units. * * Rev 1.8 Jul 13 2001 01:05:16 oris * Removed warnings. * Bug fix - exception when format routine is called with null progress call back routine. * Report noOfDrives as 1. * * Rev 1.7 Jun 17 2001 08:18:40 oris * Add improoved the format progress call back routine. * Removed fack number of TLS in mtlPreMount routine. * * Rev 1.6 May 21 2001 16:13:08 oris * Replaced memcpy with tffscpy Macro. * * Rev 1.5 May 17 2001 18:54:26 oris * Removed warnings. * * Rev 1.4 May 16 2001 21:19:02 oris * Changed the fl_MTLdefragMode variable to a global environment variable. * MTL now changes the noOfDriver variable after the first mount and restores it after uninstall. * Added missing ifdef directives. * Removed warnings. * Removed readBBT and writeBBT routines. * Improved MTL protection routine. * * Rev 1.3 Apr 01 2001 08:01:18 oris * copywrite notice. * Alligned left all # directives. * * Rev 1.2 Feb 18 2001 12:06:54 oris * Install mtl will now fake the noOfTLs in order to be the only TL. * Placed mtlFormat under FORMAT_VOLUME compilation flag. * Place mtlProtection under HW_PROTECTION compilation flag. * Changed mtlPreMount arg sanity check to include partition number. * Changed tmpflash to tmpFlash. * * Rev 1.1 Feb 14 2001 02:09:38 oris * Changed readBBT to return media size. * Added boundry argument to writeBBT. * * Rev 1.0 Feb 12 2001 12:07:02 oris * Initial revision. * * Rev 1.3 Jan 24 2001 18:10:48 oris * Bug fix: MTL failed to register because noOfTLs wan't updated * * Rev 1.2 Jan 24 2001 16:34:06 oris * MTL defragmentation changed, alt. defragmentation added. * * Rev 1.1 Jan 22 2001 22:10:50 amirm * #define FL_MTL_HIDDEN_SECTORS added * * Rev 1.0 Jan 22 2001 18:27:54 amirm * Initial revision. * */
/*
* Include */
#include "fltl.h"
/*
* Configuration */
/* This defined sets the number of sectors to ignore starting from the
* first device. The default value should be 1 therfore ignoring sector * 0 of the first device. Ignioring sector 0 gurentees that the combined * device does not use the BPB of the first device, which does not report * the C/H/S of the new combined media. The next format operation would * write a new BPB that would fit the new combined media size. */
#define FL_MTL_HIDDEN_SECTORS 1
/*
* Extern */
/*
* Globals */
FLStatus flRegisterMTL (void); /* see also stdcomp.h */ FLStatus flmtlInstall (void); FLStatus flmtlUninstall (void);
/*
* Local types */
/* I/O vector for splitting I/O among physical devices */
typedef struct { SectorNo startSector; SectorNo sectors; } tMTLiov;
/* Physical flash device. Part of MTL volume. */
typedef struct { SectorNo virtualSectors; TL tl; dword physicalSize; } tMTLPhysDev;
/* MTL volume */
struct tTLrec { int noOfTLs; int noOfDrives; SectorNo virtualSectors; tMTLPhysDev devs[SOCKETS]; };
typedef TLrec MTL;
/*
* Local data */
/* only one MTL volume is supported */
static MTL mvol;
/* progress callBack routine */
FLProgressCallback globalProgressCallback = NULL;
/* access macros for MTL volume */
#define mT(dev) (mvol.devs[dev].tl)
#define mS(dev) (mvol.devs[dev].virtualSectors)
#define mP(dev) (mvol.devs[dev].physicalSize)
#define mpT(pvol,dev) ((pvol)->devs[dev].tl)
#define mpF(pvol,dev) ((pvol)->devs[dev].flash)
#define mpS(pvol,dev) ((pvol)->devs[dev].virtualSectors)
/*
* Local routines */
static FLStatus mtlSplitIO (MTL *pvol, SectorNo startSector, SectorNo sectors, tMTLiov *iov); static FLStatus mtlWrite (MTL *pvol, SectorNo startSector, SectorNo *pSectorsToWrite, void FAR1 *buf); static FLStatus mtlMount (unsigned volNo, TL *tl, FLFlash *flash, FLFlash **notUsed); #if defined(DEFRAGMENT_VOLUME) || defined(SINGLE_BUFFER)
static FLStatus mtlDefragment (MTL *pvol, long FAR2 *sectorsNeeded); #ifdef ENVIRONMENT_VARS
static FLStatus mtlDefragmentAlt (MTL *pvol, long FAR2 *sectorsNeeded); #endif /* ENVIRNOMETN_VARS */
#endif /* DEFRAGMENT_VOLUME || SINGLE_BUFFER */
static void mtlUnmount (MTL *pvol); #ifdef FORMAT_VOLUME
static FLStatus mtlFormat (unsigned volNo, TLFormatParams* formatParams, FLFlash *flash); #endif /* FORMAT_VOLUME */
static FLStatus mtlWriteSector (MTL *pvol, SectorNo sectorNo, void FAR1 *fromAddress); static FLStatus mtlDeleteSector (MTL *pvol, SectorNo sectorNo, SectorNo noOfSectors); static FLStatus mtlInfo (MTL *pvol, TLInfo *tlInfo); static FLStatus mtlSetBusy (MTL *pvol, FLBoolean state); static SectorNo mtlSectorsInVolume (MTL *pvol); static const void FAR0 *mtlMapSector (MTL *pvol, SectorNo sectorNo, CardAddress *physAddress); #ifdef HW_PROTECTION
static FLStatus mtlProtection(FLFunctionNo callType, IOreq FAR2* ioreq, FLFlash* flash); #endif /* HW_PROTECTION */
static FLStatus mtlPreMount(FLFunctionNo callType, IOreq FAR2* ioreq , FLFlash* flash,FLStatus* status);
/* -------------------------------------------------------------------------- *
* * * m t l S p l i t I O * * * * Setup I/O vector for splitting I/O request among physical devices. * * * * Parameters : * * * * pvol : Pointer identifying drive * * startSector : starting sector # (zero-based) * * sectors : total number of sectors * * iov : I/O vector to setup * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlSplitIO (MTL *pvol, SectorNo startSector, SectorNo sectors, tMTLiov *iov) { SectorNo devFirstSectNo; SectorNo devLastSectNo; int iDev;
/* check 'pvol' for sanity */
if (pvol != &mvol) return flBadDriveHandle;
/* clear I/O vector */
for (iDev = 0; iDev < SOCKETS; iDev++) { iov[iDev].sectors = (SectorNo) 0; iov[iDev].startSector = (SectorNo)(-1); }
/* split I/O operation among physical devices */
devFirstSectNo = (SectorNo) 0;
for (iDev = 0; (iDev < noOfSockets) && (sectors > ((SectorNo) 0)); iDev++) {
devLastSectNo = devFirstSectNo + (mpS(pvol,iDev) - ((SectorNo) 1));
if ((startSector >= devFirstSectNo) && (startSector <= devLastSectNo)) {
iov[iDev].startSector = startSector - devFirstSectNo + FL_MTL_HIDDEN_SECTORS; iov[iDev].sectors = devLastSectNo - startSector + ((SectorNo) 1);
startSector = devLastSectNo + ((SectorNo) 1);
if (sectors <= iov[iDev].sectors) { iov[iDev].sectors = sectors; startSector = (SectorNo) 0; sectors = (SectorNo) 0; } else { sectors -= iov[iDev].sectors; } }
devFirstSectNo = devLastSectNo + ((SectorNo) 1); }
if (sectors > ((SectorNo) 0)) { DEBUG_PRINT(("Debug: can't split I/O request among physical devices.\n")); return flNoSpaceInVolume; }
return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l M a p S e c t o r * * * * TL's standard 'map one sector' routine. * * * * Parameters : * * * * pvol : Pointer identifying drive * * sectorNo : sector # to map (zero-based) * * physAddress : optional pointer to receive sector's physical * * address on the media * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static const void FAR0 *mtlMapSector (MTL *pvol, SectorNo sectorNo, CardAddress *physAddress) { SectorNo sectorsToMap; tMTLiov iov[SOCKETS]; int iDev;
/* pass call to the TL of the respective underlaying physical device */
sectorsToMap = (SectorNo) 1; if (mtlSplitIO(pvol, sectorNo, sectorsToMap, iov) != flOK) return NULL;
for (iDev = 0; iDev < noOfSockets; iDev++) { if (iov[iDev].sectors != ((SectorNo) 0)) { return mpT(pvol,iDev).mapSector (mpT(pvol,iDev).rec, iov[iDev].startSector, physAddress); } }
return NULL; }
/* -------------------------------------------------------------------------- *
* * * m t l W r i t e * * * * Split call to write multiple consequitive sectors among TLs of the * * underlaying physical devices. * * * * Parameters : * * * * pvol : Pointer identifying drive * * startSector : starting sector # (zero-based) * * pSectorsToWrite : on entry - total number of sectors to write * * on exit - total number of sectors written * * buf : buffer containing data to write to the media * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlWrite (MTL *pvol, SectorNo startSector, SectorNo *pSectorsToWrite, void FAR1 *buf) { tMTLiov iov[SOCKETS]; int iDev;
/* split call among TLs of the underlaying physical devices */
checkStatus( mtlSplitIO(pvol, startSector, *pSectorsToWrite, iov) );
for (iDev = 0; iDev < noOfSockets; iDev++) {
if (iov[iDev].sectors != ((SectorNo) 0)) { checkStatus( mpT(pvol,iDev).writeSector(mpT(pvol,iDev).rec, iov[iDev].startSector,buf) ); *pSectorsToWrite -= iov[iDev].sectors; buf = BYTE_ADD_FAR(buf,(CardAddress)iov[iDev].sectors << SECTOR_SIZE_BITS); }
}
if (*pSectorsToWrite != ((SectorNo) 0)) return flIncomplete;
return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l W r i t e S e c t o r * * * * TL's standard 'write one sector' routine. * * * * Parameters : * * * * pvol : Pointer identifying drive * * sectorNo : sector # to write to (zero-based) * * fromAddress : buffer containing data to write to the media * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlWriteSector (MTL *pvol, SectorNo sectorNo, void FAR1 *fromAddress) { SectorNo sectorsToWrite = (SectorNo) 1;
/* pass call to the TL of the respective underlaying physical device */
checkStatus( mtlWrite(pvol, sectorNo, §orsToWrite, (char FAR1 *)fromAddress) );
if (sectorsToWrite != ((SectorNo) 0)) return flIncomplete;
return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l D e l e t e S e c t o r * * * * TL's standard 'delete range of sectors' routine. * * * * Parameters : * * * * pvol : Pointer identifying drive * * startSector : starting sector # (zero-based) * * sectors : total number of sectors to delete * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlDeleteSector (MTL *pvol, SectorNo startSector, SectorNo sectors) { tMTLiov iov[SOCKETS]; int iDev;
/* split call among TLs of the underlaying physical devices */
checkStatus( mtlSplitIO(pvol, startSector, sectors, iov) );
for (iDev = 0; iDev < noOfSockets; iDev++) {
if (iov[iDev].sectors != ((SectorNo) 0)) { checkStatus( mpT(pvol,iDev).deleteSector(mpT(pvol,iDev).rec, iov[iDev].startSector, iov[iDev].sectors) ); }
sectors -= iov[iDev].sectors; }
if (sectors != ((SectorNo) 0)) return flIncomplete;
return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l I n f o * * * * TL's standard 'get info' routine. * * * * Parameters : * * * * pvol : Pointer identifying drive * * pTLinfo : pointer to the TLInfo structure to fill in * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlInfo (MTL *pvol, TLInfo *pTLinfo) { TLInfo tmp; int iDev;
/* check 'pvol' for sanity */
if (pvol != &mvol) return flBadDriveHandle;
pTLinfo->sectorsInVolume = pvol->virtualSectors;
/*
* The 'eraseCycles' is reported as a sum of that of all the underlaying * physical devices. The 'bootAreaSize' is set to the one of the 1st * underlaying physical device. */
pTLinfo->bootAreaSize = (dword) 0; pTLinfo->eraseCycles = (dword) 0;
for (iDev = 0; iDev < noOfSockets; iDev++) { if (mpT(pvol,iDev).getTLInfo != NULL) { checkStatus( mpT(pvol,iDev).getTLInfo(mpT(pvol,iDev).rec, &tmp) );
pTLinfo->eraseCycles += tmp.eraseCycles;
if (iDev == 0) pTLinfo->bootAreaSize = tmp.bootAreaSize; } }
return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l S e t B u s y * * * * TL's standard routine which is called at the beginning and and the end of * * the block device operation. * * * * Parameters : * * * * pvol : Pointer identifying drive * * state : FL_ON - start of block device operation * * FL_OFF - end of block device operation * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlSetBusy (MTL *pvol, FLBoolean state) { int iDev;
/* check 'pvol' for sanity */
if (pvol != &mvol) return flBadDriveHandle;
/* broadcast this call to TLs of all the underlaying physical devices */
for (iDev = 0; iDev < noOfSockets; iDev++) { if (mpT(pvol,iDev).tlSetBusy != NULL) { checkStatus( mpT(pvol,iDev).tlSetBusy(mpT(pvol,iDev).rec, state) ); } }
return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l S e c t o r s I n V o l u m e * * * * Report the total number of sectors in the volume. * * * * Parameters : * * * * pvol : Pointer identifying drive * * * * Returns : * * * * Total number of sectors in the volume, or zero in case of error. * * * * -------------------------------------------------------------------------- */
static SectorNo mtlSectorsInVolume (MTL *pvol) { /* check 'pvol' for sanity */
if (pvol != &mvol) return ((SectorNo) 0);
return pvol->virtualSectors; }
#if defined(DEFRAGMENT_VOLUME) || defined(SINGLE_BUFFER)
/* -------------------------------------------------------------------------- *
* * * m t l D e f r a g m e n t * * * * TL's standard garbage collection / volume defragmentaion routine. * * * * Note : The garbage collection algorithm will try and free the required * * number of sectors on each of the combined devices. * * * * Parameters : * * * * pvol : Pointer identifying drive * * sectorsNeeded : On entry - minimum number of free sectors that * * are requested to be on the media upon call * * completion. Two special cases: zero for * * complete defragmentation of all the physical * * devices, and '-1' for minimal defragmentation * * of each physical device. * * On exit - actual number of free sectors on * * the media. * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlDefragment (MTL *pvol, long FAR2 *sectorsNeeded) { long freeSectors; FLStatus status; int iDev; long tmp; FLStatus tmpStatus;
/* check args for sanity */
if (pvol != &mvol) return flBadDriveHandle;
/*
* Pass call to the TL of the respective underlaying physical device. * Count total number of free sectors on all devices. */
status = flOK;
freeSectors = (long) 0;
for (iDev = 0; iDev < noOfSockets; iDev++) {
if (mpT(pvol,iDev).defragment != NULL) {
switch (*sectorsNeeded) {
case ((long)(-1)): /* minimal defragmenation */ tmp = (long)(-1); break;
case ((long) 0): /* complete defragmenation */ tmp = mpS(pvol,iDev); break;
default: /* partial defragmentation */ if (*sectorsNeeded < (long) mpS(pvol,iDev)) { tmp = *sectorsNeeded; } else { tmp = mpS(pvol,iDev); /* complete defragmentation */ } break; }
tmpStatus = mpT(pvol,iDev).defragment (mpT(pvol,iDev).rec, ((long FAR2 *) &tmp)); if (tmpStatus != flBadFormat) { freeSectors += tmp; } else { status = tmpStatus; } } }
*sectorsNeeded = freeSectors;
if (*sectorsNeeded == ((long) 0)) return flNoSpaceInVolume;
return status; }
#ifdef ENVIRONMENT_VARS
/* -------------------------------------------------------------------------- *
* * * m t l D e f r a g m e n t A l t * * * * TL's alternative garbage collection / volume defragmentaion routine. * * * * Note : The garbage collection algorithm Perform quick gurbage collections * * from drive 0 until there is no more "garbage" to collect or until * * there is enough clean space. If the specified clean spage was not * * achieved try the next device. * * While this method is faster then the standard defragment, it does * * not gurantee that when the clean sectors are needed they will be * * available. This is becuase write operation on MTL will directed * * the write operation to a specific device according to the specifed * * virtual sector number (not necceseraly starting from device #0). * * * * Parameters : * * * * pvol : Pointer identifying drive * * sectorsNeeded : On entry - minimum number of free sectors that * * are requested to be on the media upon call * * completion. Two special cases: zero for * * complete defragmentation of all the physical * * devices, and '-1' for minimal defragmentation * * of each physical device. * * On exit - actual number of free sectors on * * the media. * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlDefragmentAlt (MTL *pvol, long FAR2 *sectorsNeeded) { long freeSectors; FLBoolean keepWorking; FLBoolean driveDone[SOCKETS]; long freeSectorsOnDrive[SOCKETS]; FLStatus status; int iDev; FLStatus tmpStatus; long tmp;
/* check args for sanity */
if (pvol != &mvol) return flBadDriveHandle;
/*
* Pass call to the TL of the respective underlaying physical device. * Count total number of free sectors on all devices. */
status = flOK;
freeSectors = (long) 0;
if ((*sectorsNeeded == ((long) -1)) || (*sectorsNeeded == (long)0)) {
/* Either total or minimal defragmentation of all physical devices. */
for (iDev = 0; iDev < noOfSockets; iDev++) {
if (mpT(pvol,iDev).defragment != NULL) {
if (*sectorsNeeded == ((long) -1)) tmp = (long)(-1); /* minimal defragmenation */ else tmp = mpS(pvol,iDev); /* complete defragmenation */
tmpStatus = mpT(pvol,iDev).defragment (mpT(pvol,iDev).rec, ((long FAR2 *) &tmp));
if (tmpStatus != flBadFormat) { freeSectors += tmp; } else { DEBUG_PRINT(("Debug: Error defragmenting physical device.\n")); status = tmpStatus; }
} } } else { /* Partial defragmentaion of the MTL volume */
for (iDev = 0; iDev < SOCKETS; iDev++) { freeSectorsOnDrive[iDev] = (long) 0; if ((iDev < noOfSockets) && (mpT(pvol,iDev).defragment != NULL)) driveDone[iDev] = FALSE; else driveDone[iDev] = TRUE; }
keepWorking = TRUE;
while (keepWorking == TRUE) {
keepWorking = FALSE;
for (iDev = 0; iDev < noOfSockets; iDev++) {
/*
* Do minimal defragmentation of this physical device. If we * have got error, or haven't gained any more free sectors, * this physical device is done. If that is the case for all * physical devices, the MTL defragmentation is done. If the * required number of free sectors has been reached, MTL * defragmentation is done. */
if (driveDone[iDev] != TRUE) {
tmp = (long) -1; tmpStatus = mpT(pvol,iDev).defragment (mpT(pvol,iDev).rec, ((long FAR2 *) &tmp));
if (tmpStatus != flBadFormat) {
if (freeSectorsOnDrive[iDev] < tmp) {
/* got few more free sectors on that physical device */
keepWorking = TRUE;
freeSectors += (tmp - freeSectorsOnDrive[iDev]); freeSectorsOnDrive[iDev] = tmp;
if (freeSectors >= *sectorsNeeded) {
/* required number of free sectors reached */
keepWorking = FALSE; break; } } else { /* didn't gain any free sectors */ driveDone[iDev] = TRUE; } } else { DEBUG_PRINT(("Debug: Error defragmenting physical device.\n")); driveDone[iDev] = TRUE; status = tmpStatus; } }
} /* for (iDev) */ } /* while (keepWorking */ }
*sectorsNeeded = freeSectors;
if (*sectorsNeeded == ((long) 0)) return flNoSpaceInVolume;
return status; } #endif /* ENVIRONEMENT_VARS */
#endif /* DEFRAGMENT_VOLUME || SINGLE_BUFFER */
#ifdef HW_PROTECTION
/* -------------------------------------------------------------------------- *
* * * m t l P r o t e c t i o n * * * * TL's protection routine. * * * * Parameters : * * * * callType : pre mount protection operation type. * * ioreq : pointer to the structure containing i\o fields * * flash : pointer to the flash record of device #0 * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlProtection(FLFunctionNo callType, IOreq FAR2* ioreq, FLFlash* flash)
{ FLSocket *socket; FLStatus status; FLStatus callStatus; FLFlash tmpFlash; int iTL; int iDev = 0; unsigned flags = 0;
/*
* Do flash recognition and identify protection attributes for devices * #0 .. (mvol.noOfSockets - 1) verifing that the operation can be * preformed and that the protection attributes of all the devieces * match. */
tffscpy(&tmpFlash,flash,sizeof (tmpFlash)); /* Use the given flash */
while(1) { /* The tmpFlash record is already intialized Try all the TLs */
status = flUnknownMedia; for (iTL = 1;(iTL < mvol.noOfTLs) && (status == flUnknownMedia); iTL++) { if ((tlTable[iTL].formatRoutine == NULL) || /* TL filter */ (tlTable[iTL].preMountRoutine == NULL)) continue; status = tlTable[iTL].preMountRoutine(FL_PROTECTION_GET_TYPE, ioreq,&tmpFlash,&callStatus); } if (status != flOK) { DEBUG_PRINT(("Debug: no TL recognized the device, MTL protection aborted.\n")); return flFeatureNotSupported; } if (callStatus != flOK) { return callStatus; }
/* Check protection attributes */
if ((ioreq->irFlags & PROTECTABLE) == 0) return flNotProtected;
if (iDev == 0) /* First device */ { flags = ioreq->irFlags; } else { /* Diffrent protection attributes on diffrent devices */ if (ioreq->irFlags != flags) return flMultiDocContrediction; }
/* Validity check for the proper function call */
switch(callType) { case FL_PROTECTION_GET_TYPE: /* Identify protection */ if (iDev == noOfSockets-1) return flOK; break; case FL_PROTECTION_SET_LOCK: /* Change protection */ case FL_PROTECTION_CHANGE_KEY: case FL_PROTECTION_CHANGE_TYPE: if (!(flags & CHANGEABLE_PROTECTION ) || (tmpFlash.protectionBoundries == NULL ) || (tmpFlash.protectionSet == NULL )) { return flUnchangeableProtection; } default: /* Insert and remove Key */ break; }
/* Identify flash for next device */
if (iDev < noOfSockets - 1) { iDev++; socket = flSocketOf (iDev);
/* Identify */
status = flIdentifyFlash (socket, &tmpFlash); if ((status != flOK) && (status != flUnknownMedia)) { DEBUG_PRINT(("Debug: no MTD recognized the device, MTL protection aborted.\n")); return status; } } else break;
} /* for(iDev) */
/*
* Pass call to the TL of the respective underlaying physical device. * Do flash recognition try all TLs registered in tlTable[]. Assume MTL * is in tlTable[0], so skip it. Skip all the TL filters as well. */
for (iDev = 0, callStatus = flOK; (iDev < noOfSockets) && (callStatus == flOK); iDev++) { socket = flSocketOf (iDev);
/* Identify */
status = flIdentifyFlash (socket, &tmpFlash); if ((status != flOK) && (status != flUnknownMedia)) { DEBUG_PRINT(("Debug: no MTD recognized the device, MTL protection aborted.\n")); return status; }
/* Try all the TLs */
status = flUnknownMedia; for (iTL = 1; (iTL < mvol.noOfTLs) && (status == flUnknownMedia); iTL++) { if ((tlTable[iTL].formatRoutine == NULL) || /* TL filter */ (tlTable[iTL].preMountRoutine == NULL)) continue; status = tlTable[iTL].preMountRoutine(callType,ioreq, &tmpFlash,&callStatus); } if (status != flOK) { DEBUG_PRINT(("Debug: no TL recognized the device, MTL protection aborted.\n")); return flFeatureNotSupported; } } return callStatus; } #endif /* HW_PROTECTION */
/* -------------------------------------------------------------------------- *
* * * m t l P r e M o u n t * * * * TL's standard volume pre mount routine. * * * * Parameters : * * * * callType : pre mount operation type. * * ioreq : pointer to the structure containing i\o fields * * flash : MTD attached to the 1st underlaying physical * * device * * * * Returns : * * * * The routine always return flOK in order to stop other TLs from trying * * to perform the operation. The true status code is returned in the * * 'status' parameter. flOK on success, otherwise respective error code. * * * * * -------------------------------------------------------------------------- */
static FLStatus mtlPreMount(FLFunctionNo callType, IOreq FAR2* ioreq , FLFlash* flash,FLStatus* status) { /* arg sanity check */
if (ioreq->irHandle != 0) { DEBUG_PRINT(("Debug: can't execute, MTL must address first volume of socket 0.\n")); *status = flBadParameter; return flOK; }
switch (callType) { case FL_COUNT_VOLUMES:
/* Count VOLUMES routine. We assume that while MTL is mounted only
* one device of each socket can be mounted. */
ioreq->irFlags = 1; *status = flOK; break;
/* Protection rouines. Call each of the underlaying physical devices. */
#ifdef HW_PROTECTION
case FL_PROTECTION_GET_TYPE: case FL_PROTECTION_SET_LOCK: case FL_PROTECTION_CHANGE_KEY: case FL_PROTECTION_CHANGE_TYPE: case FL_PROTECTION_REMOVE_KEY: case FL_PROTECTION_INSERT_KEY: *status = mtlProtection(callType,ioreq,flash); break; #endif /* HW_PROTECTION */
/* Write Bad Block Table. Call each of the underlaying physical device. */
case FL_WRITE_BBT: *status = flFeatureNotSupported/*mtlWriteBBT(ioreq)*/; return flFeatureNotSupported;
default: return flBadParameter; }
DEBUG_PRINT(("Debug: MTL premount succeeded.\n"));
return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l U n m o u n t * * * * TL's standard volume unmount routine. * * * * Parameters : * * * * pvol : Pointer identifying drive * * * * Returns : * * * * none * * * * -------------------------------------------------------------------------- */
static void mtlUnmount (MTL *pvol) { int iDev;
/* check 'pvol' for sanity */
if (pvol != &mvol) return;
/* broadcast this call to TLs of all the underlaying physical devices */
for (iDev = 0; iDev < noOfSockets; iDev++) { if (mpT(pvol,iDev).dismount != NULL) { mpT(pvol,iDev).dismount (mpT(pvol,iDev).rec); } }
/* Return the real number of drives */ noOfDrives = mvol.noOfDrives;
DEBUG_PRINT(("Debug: MTL dismounted succeeded.\n"));
}
/* -------------------------------------------------------------------------- *
* * * m t l M o u n t * * * * TL's standard volume mount routine. * * * * Parameters : * * * * volNo : volume #, must be zero * * tl : pointer to TL structure to fill in * * flash : MTD attached to the 1st underlaying physical * * device * * forCallback : MTD for power on callback (not used). * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlMount (unsigned volNo, TL *tl, FLFlash *flash, FLFlash **forCallback) { FLFlash tmpFlash; FLFlash *volForCallback; FLSocket *socket; FLStatus status = flUnknownMedia; int iTL; int iDev = 0;
/* Arg sanity check */
if (volNo != ((unsigned) 0)) { DEBUG_PRINT(("Debug: can't mount, MTL volume # is not zero.\n")); return flBadParameter; }
/*
* Do TL mount for device #0. Routine flIdentifyFlash() has already been * called for this device (see arguement 'flash') */
volForCallback = NULL;
/* mT(0).recommendedClusterInfo = NULL;
mT(0).writeMultiSector = NULL; mT(0).readSectors = NULL; */
/*
* Try all TLs registered in tlTable[]. Assume MTL is in tlTable[0], so * skip it. Skip all the TL filters as well. */
for (iTL = 1; (iTL < mvol.noOfTLs) && (status != flOK); iTL++) { if (tlTable[iTL].formatRoutine == NULL) /* TL filter */ continue; status = tlTable[iTL].mountRoutine (0, &mT(0), flash, &volForCallback); } if (status != flOK) { DEBUG_PRINT(("Debug: no TL recognized device #0, MTL mount aborted.\n")); return status; }
mP(iDev) = (dword)(flash->chipSize * flash->noOfChips); /* Physical size */
if (volForCallback) volForCallback->setPowerOnCallback (volForCallback);
/*
* Do flash recognition and TL mount for devices #1 .. (mvol.noOfSockets - 1). * First call flIdentifyFlash() to find MTD, then try all TLs registered * in tlTable[]. Assume MTL is in tlTable[0], so skip it. Skip all the * TL filters as well. */
for (iDev = 1; iDev < noOfSockets; iDev++) {
socket = flSocketOf (iDev);
status = flIdentifyFlash (socket, &tmpFlash); if ((status != flOK) && (status != flUnknownMedia)) { DEBUG_PRINT(("Debug: no MTD recognized the device, MTL mount aborted.\n")); goto exitMount; }
volForCallback = NULL; mP(iDev) = (dword)(tmpFlash.chipSize * tmpFlash.noOfChips); /* Physical size */ mT(iDev).partitionNo = 0; mT(iDev).socketNo = (byte)iDev;
/* mT(iDev).recommendedClusterInfo = NULL;
mT(iDev).writeMultiSector = NULL; mT(iDev).readSectors = NULL;*/
status = flUnknownMedia; for (iTL = 1; (iTL < mvol.noOfTLs) && (status != flOK); iTL++) { if (tlTable[iTL].formatRoutine == NULL) /* TL filter */ continue; status = tlTable[iTL].mountRoutine (iDev, &mT(iDev), &tmpFlash, &volForCallback); } if (status != flOK) { DEBUG_PRINT(("Debug: no TL recognized the device, MTL mount aborted.\n")); goto exitMount; }
if (volForCallback) volForCallback->setPowerOnCallback (volForCallback); } /* for (iDev) */
/* Count the total of virtual sectors across all devices */
mvol.virtualSectors = (SectorNo) 0; for (iDev = 0; iDev < SOCKETS; iDev++) { mS(iDev) = (SectorNo) 0; if (iDev >= noOfSockets) continue;
mS(iDev) = mT(iDev).sectorsInVolume (mT(iDev).rec) - FL_MTL_HIDDEN_SECTORS; mvol.virtualSectors += mS(iDev); }
exitMount: if (status != flOK) { /* If one of the devices failed mount dismount all devices */ for (;iDev >=0;iDev--) { if (mT(iDev).dismount != NULL) mT(iDev).dismount(mT(iDev).rec); } DEBUG_PRINT(("Debug: MTL mount failed.\n")); return status; }
/*
* Attach MTL-specific record to 'tl'. This record will be passed * as the first arguement to all TL calls. */
tl->rec = &mvol;
/* Fill in the TL access methods */
tl->mapSector = mtlMapSector; tl->writeSector = mtlWriteSector; tl->deleteSector = mtlDeleteSector;
#if defined(DEFRAGMENT_VOLUME) || defined(SINGLE_BUFFER)
#ifdef ENVIRONMENT_VARS
if (flMTLdefragMode == FL_MTL_DEFRAGMENT_SEQUANTIAL) { tl->defragment = mtlDefragmentAlt; } else #endif /* ENVIRONMENT_VARS */
{ tl->defragment = mtlDefragment; } #endif
tl->sectorsInVolume = mtlSectorsInVolume; tl->getTLInfo = mtlInfo; tl->tlSetBusy = mtlSetBusy; tl->dismount = mtlUnmount; tl->readBBT = NULL /*mtlReadBBT*/;
/*
* The following methods are not supported by NFTL, and have already * been set to NULL by flMount(). We just confirm this here. */
tl->writeMultiSector = NULL; tl->readSectors = NULL; tl->recommendedClusterInfo = NULL;
/* Fake the no of volume exported by TrueFFS */ mvol.noOfDrives = noOfDrives; noOfDrives = 1;
DEBUG_PRINT(("Debug: MTL mount succeeded.\n"));
return status; }
#ifdef FORMAT_VOLUME
/* -------------------------------------------------------------------------- *
* * * m t l P r o g r e s s C a l l B a c k * * * * Extends the given format routine to report the full media size. * * * * Parameters : * * * * totalUnitsToFormat : total units needed to format * * totalUnitsFormattedSoFar : unit formated so far. * * * * Notes * * * * 1) arguments 0 and 0 initializes the total unit counter to 0. * * 2) arguments -1 and -1 indicates the ending of the last device. * * * * * Returns : * * * * flOK on success, otherwise respective error code. * * -------------------------------------------------------------------------- */
static FLStatus mtlProgressCallback(word totalUnitsToFormat, word totalUnitsFormattedSoFar) { static int lastTotal; static int lastDevice;
/* Initialize lastTotal counter */ if ((totalUnitsToFormat == 0) && (totalUnitsFormattedSoFar == 0)) { lastTotal = 0; lastDevice = 0; return flOK; }
/* Indicate a new device is being formated */ if ((totalUnitsToFormat == 0) && (totalUnitsFormattedSoFar == 0xffff)) { lastTotal += lastDevice; return flOK; }
/* Call original call back routine */ lastDevice = totalUnitsToFormat; if (globalProgressCallback == NULL) { return flOK; } else { return globalProgressCallback((word)(lastTotal + totalUnitsToFormat), (word)(lastTotal + totalUnitsFormattedSoFar)); } }
/* -------------------------------------------------------------------------- *
* * * m t l F o r m a t * * * * TL's standard volume mount routine. * * * * Parameters : * * * * volNo : volume #, must be zero * * formatParams : pointer to the structure containing format * * parameters * * flash : MTD attached to the 1st underlaying physical * * device * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- * * * * NOTE. Binary area has 2 possible options: * * * * - TL_LEAVE_BINARY_AREA is set - binary area is left for all devices * * - TL_LEAVE_BINARY_AREA is off - binary area is placed only on the * * device #0 * * * * Handling of 'formatParams.progressCallback' should be improved. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlFormat (unsigned volNo, TLFormatParams* formatParams, FLFlash *flash) { FLFlash tmpFlash; FLSocket *socket; FLStatus status = flUnknownMedia; int iTL, iDev;
/* arg sanity check */
if (volNo != ((unsigned) 0)) { DEBUG_PRINT(("Debug: can't format, MTL socket # is not zero.\n")); return flBadParameter; } if (formatParams->noOfBDTLPartitions > 1){ DEBUG_PRINT(("Debug: can't format, MTL with more then 1 BDTL volume.\n")); return flBadParameter; }
if (formatParams->flags & TL_SINGLE_FLOOR_FORMATTING){ DEBUG_PRINT(("Debug: can't format, MTL does not support single floor formatting.\n")); return flBadParameter; }
/* Initialize the progress call back routine to indicate the agregated
* size. The actual routine is saved and mtl routine is used. */
globalProgressCallback = formatParams->progressCallback; formatParams->progressCallback = mtlProgressCallback; /* Set new routine */ mtlProgressCallback(0,0); /* Initialize new format operation */
/*
* Format device #0. Routine flIdentifyFlash() has already been called * for this device (see arguement 'flash'). Try all TLs registered * in tlTable[]. Assume MTL is in tlTable[0], so skip it. Skip all the * TL filters as well. */
for (iTL = 1; (iTL < mvol.noOfTLs) && (status == flUnknownMedia); iTL++) { if (tlTable[iTL].formatRoutine == NULL) /* TL filter */ continue; status = tlTable[iTL].formatRoutine(0, formatParams, flash); } if (status != flOK) { DEBUG_PRINT(("Debug: no TL recognized device #0, MTL format aborted.\n")); return status; }
/*
* Put all 'bootImageLen' and 'exbLen' to the 1st physical device unless * TL_LEAVE_BINARY_AREA is specified (which means to keep bootimage area * size as is. */
if (!(formatParams->flags & TL_LEAVE_BINARY_AREA)) { formatParams->bootImageLen = (long) 0; #ifdef WRITE_EXB_IMAGE
formatParams->exbLen = 0; #endif /* WRITE_EXB_IMAGE */
formatParams->noOfBinaryPartitions = 0; }
/*
* Do flash recognition and format for devices #1 .. (mvol.noOfSockets - 1). * First call flIdentifyFlash() to find MTD, then try all TLs registered * in tlTable[]. Assume MTL is in tlTable[0], so skip it. Skip all the * TL filters as well. */
for (iDev = 1; iDev < noOfSockets; iDev++) {
socket = flSocketOf (iDev);
status = flIdentifyFlash (socket, &tmpFlash); if ((status != flOK) && (status != flUnknownMedia)) { DEBUG_PRINT(("Debug: no MTD recognized the device, MTL format aborted.\n")); return status; } mtlProgressCallback(0,0xffff); /* Initialize new device is being formated */ status = flUnknownMedia; for (iTL = 1; (iTL < mvol.noOfTLs) && (status == flUnknownMedia); iTL++) { if (tlTable[iTL].formatRoutine == NULL) /* TL filter */ continue; status = tlTable[iTL].formatRoutine (iDev, formatParams, &tmpFlash); } if (status != flOK) { DEBUG_PRINT(("Debug: no TL recognized the device, MTL format aborted.\n")); return status; } } /* for(iDev) */
DEBUG_PRINT(("Debug: MTL format succeeded.\n"));
return flOK; }
#endif /* FORMAT_VOLUME */
/* -------------------------------------------------------------------------- *
* * * f l m t l U n i n s t a l l * * * * Removes MTL from the TL table. * * * * Note: Must be called after the medium was dismounted. * * * * Parameters : * * * * none * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
FLStatus flmtlUninstall (void) { int iTL;
if (noOfTLs > 0) { /* search for MTL in tlTable[] */
for (iTL = 0; iTL < mvol.noOfTLs; iTL++) { if (tlTable[iTL].mountRoutine == mtlMount) break; }
if (iTL < mvol.noOfTLs) {
/* MTL is found in tlTable[iTL], so remove it */
for (; iTL < (mvol.noOfTLs - 1); iTL ++) { tlTable[iTL].mountRoutine = tlTable[iTL + 1].mountRoutine; tlTable[iTL].formatRoutine = tlTable[iTL + 1].formatRoutine; }
tlTable[mvol.noOfTLs - 1].mountRoutine = NULL; tlTable[mvol.noOfTLs - 1].formatRoutine = NULL; tlTable[mvol.noOfTLs - 1].preMountRoutine = NULL;
noOfTLs = mvol.noOfTLs - 1; noOfDrives = mvol.noOfDrives; } }
return flOK; }
/* -------------------------------------------------------------------------- *
* * * f l m t l I n s t a l l * * * * If MTL is found in TL table, it is moved into 1st slot (i.e. effectively * * enabled). If MTL isn't found in TL table, it is installed into 1st slot. * * The TL does not increament the number of TL (noOfTLs) global variable, * * but changes it to 1, therfore reporting it as the only registered TL. * * * * Note : The install routine should be the last TL to be regitered. * * * * Parameters : * * * * none * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
FLStatus flmtlInstall (void) { int iTL;
if (noOfTLs > 0) { checkStatus( flmtlUninstall() ); /* Dismount previous MTL if exists */
/* Save number of registered TLs and number of volumes */
mvol.noOfTLs = noOfTLs; mvol.noOfDrives = noOfDrives;
/* search for MTL in tlTable[] */
for (iTL = 0; iTL < noOfTLs; iTL++) { if (tlTable[iTL].mountRoutine == mtlMount) break; }
if (iTL >= noOfTLs) /* MTL is not found in tlTable[iTL] */ { /* MTL isn't in tlTable[], we will be adding it */
if (noOfTLs >= TLS) { DEBUG_PRINT(("Debug: can't install MTL, too many TLs.\n")); return flTooManyComponents; } iTL = noOfTLs; mvol.noOfTLs++; } else { /* MTL is found in tlTable[iTL] */ }
/* free the 1st slot in tlTable[] for MTL */
while (iTL >= 1) { tlTable[iTL].mountRoutine = tlTable[iTL - 1].mountRoutine; tlTable[iTL].formatRoutine = tlTable[iTL - 1].formatRoutine; iTL--; } } else { /* No other TL registered so return error code */
return flMultiDocContrediction; }
/* Make system believe that only MTL is registered */
noOfTLs = 1; noOfDrives = 1;
/* put MTL in the 1st slot in tlTable[] */
tlTable[0].mountRoutine = mtlMount; tlTable[0].preMountRoutine = mtlPreMount; #ifdef FORMAT_VOLUME
tlTable[0].formatRoutine = mtlFormat; #else
tlTable[0].formatRoutine = noFormat; #endif
return flOK; }
/* -------------------------------------------------------------------------- *
* * * f l R e g i s t e r M T L * * * * Standard TL's component registration routine. * * * * Parameters : * * * * none * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
FLStatus flRegisterMTL (void) { checkStatus( flmtlInstall() );
return flOK; }
/* Physical routines are not a part of TrueFFS code */
#if 0
/* -------------------------------------------------------------------------- *
* * * m t l R e a d B B T * * * * TL's standard 'read bad blocks table' routine. * * * * Parameters : * * * * pvol : Pointer identifying drive * * buf : Pointer to user buffer to read BB info to * * * * Returns : * * * * flOK on success, otherwise respective error code. * * mediaSize : Size of the formated media * * noOfBB : Total number of bad blocks read * * * * -------------------------------------------------------------------------- */
static FLStatus mtlReadBBT (MTL *pvol, byte FAR1 * buf, long FAR2 * mediaSize, unsigned FAR2 * noOfBB)
{ CardAddress addressShift=0; long bufOffset = 0; unsigned tmpCounter; long tmpMediaSize; byte iDev;
/* check 'pvol' for sanity */
if (pvol != &mvol) return flBadDriveHandle;
/* Read bbt of each device while incrementing the address simulating a
* big physical device */
*mediaSize = 0; *noOfBB = 0; for (iDev = 0; iDev < noOfSockets; iDev++) { checkStatus(mpT(pvol,iDev).readBBT(mpT(pvol,iDev).rec, (byte FAR1 *)flAddLongToFarPointer(buf,bufOffset), &tmpMediaSize,&tmpCounter)); *noOfBB += tmpCounter; /* Global BB counter */ for (;tmpCounter>0;tmpCounter--,bufOffset+=sizeof(CardAddress)) { *((CardAddress *)(buf + bufOffset)) += addressShift; } addressShift += mP(iDev); *mediaSize += tmpMediaSize; } return flOK; }
/* -------------------------------------------------------------------------- *
* * * m t l W r i t e B B T * * * * TL's write Bad Blocks Table routine. * * * * Parameters : * * * * ioreq : pointer to the structure containing i\o fields * * * * Returns : * * * * flOK on success, otherwise respective error code. * * * * -------------------------------------------------------------------------- */
static FLStatus mtlWriteBBT(IOreq FAR2* ioreq) { FLSocket *socket; FLStatus status; FLFlash tmpFlash; CardAddress endUnit; CardAddress lastDriveAddress; CardAddress nextDriveAddress = 0; CardAddress iUnit; CardAddress bUnit; CardAddress endAddress; byte iDev; word badBlockNo=0; byte zeroes[2] = {0,0};
/* Initlize last erase address according to argument */
tffsset(&endAddress,0xff,sizeof(CardAddress)); if (ioreq->irLength == 0) { tffsset(&endAddress,0xff,sizeof(CardAddress)); } else { endAddress = ioreq->irLength; }
/*
* Do flash recognition while storing physical size of devices * #0 .. (mvol.noOfSockets - 1). First call flIdentifyFlash() to find * MTD, then erase the media while marking bad blocks. Note that the * addresses are physical addresses of the virtual multi-doc. The address * should be subtructed by the physical size of the previous devices. */
for (iDev = 0; iDev < noOfSockets; iDev++) { socket = flSocketOf (iDev);
/* Identify */ status = flIdentifyFlash (socket, &tmpFlash); if ((status != flOK) && (status != flUnknownMedia)) { DEBUG_PRINT(("Debug: no MTD recognized the device, MTL writeBBT aborted.\n")); return status; }
/* Initialize new drive boundry variables */
mP(iDev) = (dword)(tmpFlash.chipSize * tmpFlash.noOfChips); lastDriveAddress = nextDriveAddress; nextDriveAddress += mP(iDev); endUnit = mP(iDev) >> tmpFlash.erasableBlockSizeBits; bUnit = ((*((CardAddress FAR1 *)flAddLongToFarPointer (ioreq->irData,badBlockNo*sizeof(CardAddress)))) - lastDriveAddress) >> tmpFlash.erasableBlockSizeBits;
/* Erase entire media */
for (iUnit = 0 ,badBlockNo = 0; iUnit < endUnit ; iUnit++) { if ((iUnit << tmpFlash.erasableBlockSizeBits) + lastDriveAddress >= endAddress) return flOK; tmpFlash.erase(&tmpFlash,iUnit,1);
if (ioreq->irFlags > badBlockNo) { if (bUnit == iUnit) { tmpFlash.write(&tmpFlash,bUnit << tmpFlash.erasableBlockSizeBits,zeroes,2,0); badBlockNo++; bUnit = ((*((CardAddress FAR1 *)flAddLongToFarPointer (ioreq->irData,badBlockNo*sizeof(CardAddress)))) - lastDriveAddress) >> tmpFlash.erasableBlockSizeBits; } } } } return flOK; } #endif /* 0 */
|