/***********************************************************************************/ /* 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 = info@m-sys.com */ /***********************************************************************************/ /* * $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 */