xref: /inferno-os/appl/cmd/disk/ftl.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth#
2*37da2899SCharles.Forsyth# basic Flash Translation Layer driver
3*37da2899SCharles.Forsyth#	see for instance the Intel technical paper
4*37da2899SCharles.Forsyth#	``Understanding the Flash Translation Layer (FTL) Specification''
5*37da2899SCharles.Forsyth#	Order number 297816-001 (online at www.intel.com)
6*37da2899SCharles.Forsyth#
7*37da2899SCharles.Forsyth# a public driver by David Hinds, dhinds@allegro.stanford.edu
8*37da2899SCharles.Forsyth# further helps with some details.
9*37da2899SCharles.Forsyth#
10*37da2899SCharles.Forsyth# this driver uses the common simplification of never storing
11*37da2899SCharles.Forsyth# the VBM on the medium (a waste of precious flash!) but
12*37da2899SCharles.Forsyth# rather building it on the fly as the block maps are read.
13*37da2899SCharles.Forsyth#
14*37da2899SCharles.Forsyth# Plan 9 driver (c) 1997 by C H Forsyth (forsyth@caldo.demon.co.uk)
15*37da2899SCharles.Forsyth#	This driver may be used or adapted by anyone for any non-commercial purpose.
16*37da2899SCharles.Forsyth#
17*37da2899SCharles.Forsyth# adapted for Inferno 1998 by C H Forsyth, Vita Nuova Limited, York, England (byteles@vitanuova.com)
18*37da2899SCharles.Forsyth#
19*37da2899SCharles.Forsyth# C H Forsyth and Vita Nuova Limited expressly allow Lucent Technologies
20*37da2899SCharles.Forsyth# to use this driver freely for any Inferno-related purposes whatever,
21*37da2899SCharles.Forsyth# including commercial applications.
22*37da2899SCharles.Forsyth#
23*37da2899SCharles.Forsyth# TO DO:
24*37da2899SCharles.Forsyth#	check error handling details for get/put flash
25*37da2899SCharles.Forsyth#	bad block handling
26*37da2899SCharles.Forsyth#	reserved space in formatted size
27*37da2899SCharles.Forsyth#	possibly block size as parameter
28*37da2899SCharles.Forsyth#	fetch parameters from header on init
29*37da2899SCharles.Forsyth#
30*37da2899SCharles.Forsyth# Adapted to a ftl formatter for Inferno 2000 by J R Firth, Vita Nuova Limited
31*37da2899SCharles.Forsyth#	usage : ftl flashsize secsize inputfile outputfile
32*37da2899SCharles.Forsyth# outputfile will then be a ftl image of inputfile
33*37da2899SCharles.Forsyth# nb assumes the base address is zero
34*37da2899SCharles.Forsyth#
35*37da2899SCharles.Forsyth# Converted to limbo for Inferno 2000 by JR Firth, Vita Nuova Holdings Limited
36*37da2899SCharles.Forsyth#
37*37da2899SCharles.Forsyth
38*37da2899SCharles.Forsythimplement Ftlimage;
39*37da2899SCharles.Forsyth
40*37da2899SCharles.Forsythinclude "sys.m";
41*37da2899SCharles.Forsythinclude "draw.m";
42*37da2899SCharles.Forsyth
43*37da2899SCharles.Forsythsys : Sys;
44*37da2899SCharles.Forsyth	OREAD, OWRITE, FD, open, create, read, write, print, fprint : import sys;
45*37da2899SCharles.Forsyth
46*37da2899SCharles.ForsythFtlimage : module
47*37da2899SCharles.Forsyth{
48*37da2899SCharles.Forsyth	init : fn(nil : ref Draw->Context, argv : list of string);
49*37da2899SCharles.Forsyth};
50*37da2899SCharles.Forsyth
51*37da2899SCharles.Forsythstderr : ref FD;
52*37da2899SCharles.Forsyth
53*37da2899SCharles.Forsythflashsize, secsize : int;
54*37da2899SCharles.Forsythflashm : array of byte;
55*37da2899SCharles.Forsythtrace : int = 0;
56*37da2899SCharles.Forsyth
57*37da2899SCharles.ForsythEshift : con 18;			# 2^18=256k; log2(eraseunit)
58*37da2899SCharles.ForsythFlashseg : con 1<<Eshift;
59*37da2899SCharles.ForsythBshift : con 9;			# 2^9=512
60*37da2899SCharles.ForsythBsize : con 1<<Bshift;
61*37da2899SCharles.ForsythBAMoffset : con 16r100;
62*37da2899SCharles.ForsythNolimit : con ~0;
63*37da2899SCharles.ForsythUSABLEPCT : con 95;	# release only this % to client
64*37da2899SCharles.Forsyth
65*37da2899SCharles.ForsythFTLDEBUG : con 0;
66*37da2899SCharles.Forsyth
67*37da2899SCharles.Forsyth# erase unit header (defined by FTL specification)
68*37da2899SCharles.Forsyth# offsets into Merase
69*37da2899SCharles.ForsythO_LINKTUPLE : con 0;
70*37da2899SCharles.ForsythO_ORGTUPLE : con 5;
71*37da2899SCharles.ForsythO_NXFER : con 15;
72*37da2899SCharles.ForsythO_NERASE : con 16;
73*37da2899SCharles.ForsythO_ID : con 20;
74*37da2899SCharles.ForsythO_BSHIFT : con 22;
75*37da2899SCharles.ForsythO_ESHIFT : con 23;
76*37da2899SCharles.ForsythO_PSTART : con 24;
77*37da2899SCharles.ForsythO_NUNITS : con 26;
78*37da2899SCharles.ForsythO_PSIZE : con 28;
79*37da2899SCharles.ForsythO_VBMBASE : con 32;
80*37da2899SCharles.ForsythO_NVBM : con 36;
81*37da2899SCharles.ForsythO_FLAGS : con 38;
82*37da2899SCharles.ForsythO_CODE : con 39;
83*37da2899SCharles.ForsythO_SERIAL : con 40;
84*37da2899SCharles.ForsythO_ALTOFFSET : con 44;
85*37da2899SCharles.ForsythO_BAMOFFSET : con 48;
86*37da2899SCharles.ForsythO_RSV2 : con 52;
87*37da2899SCharles.Forsyth
88*37da2899SCharles.ForsythERASEHDRLEN : con	64;
89*37da2899SCharles.Forsyth
90*37da2899SCharles.Forsyth# special unit IDs
91*37da2899SCharles.ForsythXferID : con 16rffff;
92*37da2899SCharles.ForsythXferBusy : con 16r7fff;
93*37da2899SCharles.Forsyth
94*37da2899SCharles.Forsyth# special BAM addresses
95*37da2899SCharles.ForsythBfree : con -1;	#16rffffffff
96*37da2899SCharles.ForsythBwriting : con -2; #16rfffffffe
97*37da2899SCharles.ForsythBdeleted : con 0;
98*37da2899SCharles.Forsyth
99*37da2899SCharles.Forsyth# block types
100*37da2899SCharles.ForsythTypeShift : con 7;
101*37da2899SCharles.ForsythBlockType : con (1<<TypeShift)-1;
102*37da2899SCharles.ForsythControlBlock : con 16r30;
103*37da2899SCharles.ForsythDataBlock : con 16r40;
104*37da2899SCharles.ForsythReplacePage : con 16r60;
105*37da2899SCharles.ForsythBadBlock : con 16r70;
106*37da2899SCharles.Forsyth
107*37da2899SCharles.ForsythBNO(va : int) : int
108*37da2899SCharles.Forsyth{
109*37da2899SCharles.Forsyth	return va>>Bshift;
110*37da2899SCharles.Forsyth}
111*37da2899SCharles.ForsythMKBAM(b : int,t : int) : int
112*37da2899SCharles.Forsyth{
113*37da2899SCharles.Forsyth	return (b<<Bshift)|t;
114*37da2899SCharles.Forsyth}
115*37da2899SCharles.Forsyth
116*37da2899SCharles.ForsythTerase : adt {
117*37da2899SCharles.Forsyth	x : int;
118*37da2899SCharles.Forsyth	id : int;
119*37da2899SCharles.Forsyth	offset : int;
120*37da2899SCharles.Forsyth	bamoffset : int;
121*37da2899SCharles.Forsyth	nbam : int;
122*37da2899SCharles.Forsyth	bam : array of byte;
123*37da2899SCharles.Forsyth	bamx : int;
124*37da2899SCharles.Forsyth	nfree : int;
125*37da2899SCharles.Forsyth	nused : int;
126*37da2899SCharles.Forsyth	ndead : int;
127*37da2899SCharles.Forsyth	nbad : int;
128*37da2899SCharles.Forsyth	nerase : int;
129*37da2899SCharles.Forsyth};
130*37da2899SCharles.Forsyth
131*37da2899SCharles.ForsythFtl : adt {
132*37da2899SCharles.Forsyth	base : int;		# base of flash region
133*37da2899SCharles.Forsyth	size : int;		# size of flash region
134*37da2899SCharles.Forsyth	segsize : int;	# size of flash segment (erase unit)
135*37da2899SCharles.Forsyth	eshift : int;	# log2(erase-unit-size)
136*37da2899SCharles.Forsyth	bshift : int;	# log2(bsize)
137*37da2899SCharles.Forsyth	bsize : int;
138*37da2899SCharles.Forsyth	nunit : int;		# number of segments (erase units)
139*37da2899SCharles.Forsyth	unit : array of ref Terase;
140*37da2899SCharles.Forsyth	lastx : int;		# index in unit of last allocation
141*37da2899SCharles.Forsyth	xfer : int;		# index in unit of current transfer unit (-1 if none)
142*37da2899SCharles.Forsyth	nfree : int;		# total free space in blocks
143*37da2899SCharles.Forsyth	nblock : int;	# total space in blocks
144*37da2899SCharles.Forsyth	rwlimit : int;	# user-visible block limit (`formatted size')
145*37da2899SCharles.Forsyth	vbm : array of int;		# virtual block map
146*37da2899SCharles.Forsyth	fstart : int;		# address of first block of data in a segment
147*37da2899SCharles.Forsyth	trace : int;		# (debugging) trace of read/write actions
148*37da2899SCharles.Forsyth	detach : int;	# free Ftl on last close
149*37da2899SCharles.Forsyth
150*37da2899SCharles.Forsyth	# scavenging variables
151*37da2899SCharles.Forsyth	needspace : int;
152*37da2899SCharles.Forsyth	hasproc : int;
153*37da2899SCharles.Forsyth};
154*37da2899SCharles.Forsyth
155*37da2899SCharles.Forsyth# Ftl.detach
156*37da2899SCharles.ForsythDetached : con 1;	# detach on close
157*37da2899SCharles.ForsythDeferred : con 2;	# scavenger must free it
158*37da2899SCharles.Forsyth
159*37da2899SCharles.Forsythftls : ref Ftl;
160*37da2899SCharles.Forsyth
161*37da2899SCharles.Forsythftlstat(sz : int)
162*37da2899SCharles.Forsyth{
163*37da2899SCharles.Forsyth	print("16r%x:16r%x:16r%x\n", ftls.rwlimit*Bsize, sz, flashsize);
164*37da2899SCharles.Forsyth	print("%d:%d:%d in 512b blocks\n", ftls.rwlimit, sz>>Bshift, flashsize>>Bshift);
165*37da2899SCharles.Forsyth}
166*37da2899SCharles.Forsyth
167*37da2899SCharles.Forsythftlread(buf : array of byte, n : int, offset : int) : int
168*37da2899SCharles.Forsyth{
169*37da2899SCharles.Forsyth	ftl : ref Ftl;
170*37da2899SCharles.Forsyth	e : ref Terase;
171*37da2899SCharles.Forsyth	nb : int;
172*37da2899SCharles.Forsyth	a : int;
173*37da2899SCharles.Forsyth	pb : int;
174*37da2899SCharles.Forsyth	mapb : int;
175*37da2899SCharles.Forsyth
176*37da2899SCharles.Forsyth	if(n <= 0 || n%Bsize || offset%Bsize) {
177*37da2899SCharles.Forsyth		fprint(stderr, "ftl: bad read\n");
178*37da2899SCharles.Forsyth		exit;
179*37da2899SCharles.Forsyth	}
180*37da2899SCharles.Forsyth	ftl = ftls;
181*37da2899SCharles.Forsyth	nb = n/Bsize;
182*37da2899SCharles.Forsyth	offset /= Bsize;
183*37da2899SCharles.Forsyth	if(offset >= ftl.rwlimit)
184*37da2899SCharles.Forsyth		return 0;
185*37da2899SCharles.Forsyth	if(offset+nb > ftl.rwlimit)
186*37da2899SCharles.Forsyth		nb = ftl.rwlimit - offset;
187*37da2899SCharles.Forsyth	a = 0;
188*37da2899SCharles.Forsyth	for(n = 0; n < nb; n++){
189*37da2899SCharles.Forsyth		(mapb, e, pb) = mapblk(ftl, offset+n);
190*37da2899SCharles.Forsyth		if(mapb)
191*37da2899SCharles.Forsyth			getflash(ftl, buf[a:], e.offset + pb*Bsize, Bsize);
192*37da2899SCharles.Forsyth		else
193*37da2899SCharles.Forsyth			memset(buf[a:], 0, Bsize);
194*37da2899SCharles.Forsyth		a += Bsize;
195*37da2899SCharles.Forsyth	}
196*37da2899SCharles.Forsyth	return a;
197*37da2899SCharles.Forsyth}
198*37da2899SCharles.Forsyth
199*37da2899SCharles.Forsythftlwrite(buf : array of byte, n : int, offset : int) : int
200*37da2899SCharles.Forsyth{
201*37da2899SCharles.Forsyth	ns, nb : int;
202*37da2899SCharles.Forsyth	a : int;
203*37da2899SCharles.Forsyth	e, oe : ref Terase;
204*37da2899SCharles.Forsyth	ob, v : int;
205*37da2899SCharles.Forsyth	ftl : ref Ftl;
206*37da2899SCharles.Forsyth	mapb : int;
207*37da2899SCharles.Forsyth
208*37da2899SCharles.Forsyth	if(n <= 0)
209*37da2899SCharles.Forsyth		return 0;
210*37da2899SCharles.Forsyth	ftl = ftls;
211*37da2899SCharles.Forsyth	if(n <= 0 || n%Bsize || offset%Bsize) {
212*37da2899SCharles.Forsyth		fprint(stderr, "ftl: bad write\n");
213*37da2899SCharles.Forsyth		exit;
214*37da2899SCharles.Forsyth	}
215*37da2899SCharles.Forsyth	nb = n/Bsize;
216*37da2899SCharles.Forsyth	offset /= Bsize;
217*37da2899SCharles.Forsyth	if(offset >= ftl.rwlimit)
218*37da2899SCharles.Forsyth		return 0;
219*37da2899SCharles.Forsyth	if(offset+nb > ftl.rwlimit)
220*37da2899SCharles.Forsyth		nb = ftl.rwlimit - offset;
221*37da2899SCharles.Forsyth	a = 0;
222*37da2899SCharles.Forsyth	for(n = 0; n < nb; n++){
223*37da2899SCharles.Forsyth		ns = 0;
224*37da2899SCharles.Forsyth		while((v = allocblk(ftl)) == 0)
225*37da2899SCharles.Forsyth			if(!scavenge(ftl) || ++ns > 3){
226*37da2899SCharles.Forsyth				fprint(stderr, "ftl: flash memory full\n");
227*37da2899SCharles.Forsyth			}
228*37da2899SCharles.Forsyth		(mapb, oe, ob) = mapblk(ftl, offset+n);
229*37da2899SCharles.Forsyth		if(!mapb)
230*37da2899SCharles.Forsyth			oe = nil;
231*37da2899SCharles.Forsyth		e = ftl.unit[v>>16];
232*37da2899SCharles.Forsyth		v &= 16rffff;
233*37da2899SCharles.Forsyth		putflash(ftl, e.offset + v*Bsize, buf[a:], Bsize);
234*37da2899SCharles.Forsyth		putbam(ftl, e, v, MKBAM(offset+n, DataBlock));
235*37da2899SCharles.Forsyth		# both old and new block references exist in this window (can't be closed?)
236*37da2899SCharles.Forsyth		ftl.vbm[offset+n] = (e.x<<16) | v;
237*37da2899SCharles.Forsyth		if(oe != nil){
238*37da2899SCharles.Forsyth			putbam(ftl, oe, ob, Bdeleted);
239*37da2899SCharles.Forsyth			oe.ndead++;
240*37da2899SCharles.Forsyth		}
241*37da2899SCharles.Forsyth		a += Bsize;
242*37da2899SCharles.Forsyth	}
243*37da2899SCharles.Forsyth	return a;
244*37da2899SCharles.Forsyth}
245*37da2899SCharles.Forsyth
246*37da2899SCharles.Forsythmkftl(fname : string, base : int, size : int, eshift : int, op : string) : ref Ftl
247*37da2899SCharles.Forsyth{
248*37da2899SCharles.Forsyth	i, j, nov, segblocks : int;
249*37da2899SCharles.Forsyth	limit : int;
250*37da2899SCharles.Forsyth	e : ref Terase;
251*37da2899SCharles.Forsyth
252*37da2899SCharles.Forsyth	ftl := ref Ftl;
253*37da2899SCharles.Forsyth	ftl.lastx = 0;
254*37da2899SCharles.Forsyth	ftl.detach = 0;
255*37da2899SCharles.Forsyth	ftl.needspace = 0;
256*37da2899SCharles.Forsyth	ftl.hasproc = 0;
257*37da2899SCharles.Forsyth	ftl.trace = 0;
258*37da2899SCharles.Forsyth	limit = flashsize;
259*37da2899SCharles.Forsyth	if(size == Nolimit)
260*37da2899SCharles.Forsyth		size = limit-base;
261*37da2899SCharles.Forsyth	if(base >= limit || size > limit || base+size > limit || eshift < 8 || (1<<eshift) > size) {
262*37da2899SCharles.Forsyth		fprint(stderr, "bad flash space parameters");
263*37da2899SCharles.Forsyth		exit;
264*37da2899SCharles.Forsyth	}
265*37da2899SCharles.Forsyth	if(FTLDEBUG || ftl.trace || trace)
266*37da2899SCharles.Forsyth		print("%s flash %s #%x:#%x limit #%x\n", op, fname, base, size, limit);
267*37da2899SCharles.Forsyth	ftl.base = base;
268*37da2899SCharles.Forsyth	ftl.size = size;
269*37da2899SCharles.Forsyth	ftl.bshift = Bshift;
270*37da2899SCharles.Forsyth	ftl.bsize = Bsize;
271*37da2899SCharles.Forsyth	ftl.eshift = eshift;
272*37da2899SCharles.Forsyth	ftl.segsize = 1<<eshift;
273*37da2899SCharles.Forsyth	ftl.nunit = size>>eshift;
274*37da2899SCharles.Forsyth	nov = ((ftl.segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize;	# number of overhead blocks per segment (header, and BAM itself)
275*37da2899SCharles.Forsyth	ftl.fstart = nov;
276*37da2899SCharles.Forsyth	segblocks = ftl.segsize/Bsize - nov;
277*37da2899SCharles.Forsyth	ftl.nblock = ftl.nunit*segblocks;
278*37da2899SCharles.Forsyth	if(ftl.nblock >= 16r10000)
279*37da2899SCharles.Forsyth		ftl.nblock = 16r10000;
280*37da2899SCharles.Forsyth	ftl.vbm = array[ftl.nblock] of int;
281*37da2899SCharles.Forsyth	ftl.unit = array[ftl.nunit] of ref Terase;
282*37da2899SCharles.Forsyth	if(ftl.vbm == nil || ftl.unit == nil) {
283*37da2899SCharles.Forsyth		fprint(stderr, "out of mem");
284*37da2899SCharles.Forsyth		exit;
285*37da2899SCharles.Forsyth	}
286*37da2899SCharles.Forsyth	for(i=0; i<ftl.nblock; i++)
287*37da2899SCharles.Forsyth		ftl.vbm[i] = 0;
288*37da2899SCharles.Forsyth	if(op == "format"){
289*37da2899SCharles.Forsyth		for(i=0; i<ftl.nunit-1; i++)
290*37da2899SCharles.Forsyth			eraseinit(ftl, i*ftl.segsize, i, 1);
291*37da2899SCharles.Forsyth		eraseinit(ftl, i*ftl.segsize, XferID, 1);
292*37da2899SCharles.Forsyth	}
293*37da2899SCharles.Forsyth	ftl.xfer = -1;
294*37da2899SCharles.Forsyth	for(i=0; i<ftl.nunit; i++){
295*37da2899SCharles.Forsyth		e = eraseload(ftl, i, i*ftl.segsize);
296*37da2899SCharles.Forsyth		if(e == nil){
297*37da2899SCharles.Forsyth			fprint(stderr, "ftl: logical segment %d: bad format\n", i);
298*37da2899SCharles.Forsyth			continue;
299*37da2899SCharles.Forsyth		}
300*37da2899SCharles.Forsyth		if(e.id == XferBusy){
301*37da2899SCharles.Forsyth			e.nerase++;
302*37da2899SCharles.Forsyth			eraseinit(ftl, e.offset, XferID, e.nerase);
303*37da2899SCharles.Forsyth			e.id = XferID;
304*37da2899SCharles.Forsyth		}
305*37da2899SCharles.Forsyth		for(j=0; j<ftl.nunit; j++)
306*37da2899SCharles.Forsyth			if(ftl.unit[j] != nil && ftl.unit[j].id == e.id){
307*37da2899SCharles.Forsyth				fprint(stderr, "ftl: duplicate erase unit #%x\n", e.id);
308*37da2899SCharles.Forsyth				erasefree(e);
309*37da2899SCharles.Forsyth				e = nil;
310*37da2899SCharles.Forsyth				break;
311*37da2899SCharles.Forsyth			}
312*37da2899SCharles.Forsyth		if(e != nil){
313*37da2899SCharles.Forsyth			ftl.unit[e.x] = e;
314*37da2899SCharles.Forsyth			if(e.id == XferID)
315*37da2899SCharles.Forsyth				ftl.xfer = e.x;
316*37da2899SCharles.Forsyth			if (FTLDEBUG || ftl.trace || trace)
317*37da2899SCharles.Forsyth				fprint(stderr, "ftl: unit %d:#%x used %d free %d dead %d bad %d nerase %d\n",
318*37da2899SCharles.Forsyth					e.x, e.id, e.nused, e.nfree, e.ndead, e.nbad, e.nerase);
319*37da2899SCharles.Forsyth		}
320*37da2899SCharles.Forsyth	}
321*37da2899SCharles.Forsyth	if(ftl.xfer < 0 && ftl.nunit <= 0 || ftl.xfer >= 0 && ftl.nunit <= 1) {
322*37da2899SCharles.Forsyth		fprint(stderr, "ftl: no valid flash data units");
323*37da2899SCharles.Forsyth		exit;
324*37da2899SCharles.Forsyth	}
325*37da2899SCharles.Forsyth	if(ftl.xfer < 0)
326*37da2899SCharles.Forsyth		fprint(stderr, "ftl: no transfer unit: device is WORM\n");
327*37da2899SCharles.Forsyth	else
328*37da2899SCharles.Forsyth		ftl.nblock -= segblocks;	# discount transfer segment
329*37da2899SCharles.Forsyth	if(ftl.nblock >= 1000)
330*37da2899SCharles.Forsyth		ftl.rwlimit = ftl.nblock-100;	# TO DO: variable reserve
331*37da2899SCharles.Forsyth	else
332*37da2899SCharles.Forsyth		ftl.rwlimit = ftl.nblock*USABLEPCT/100;
333*37da2899SCharles.Forsyth	return ftl;
334*37da2899SCharles.Forsyth}
335*37da2899SCharles.Forsyth
336*37da2899SCharles.Forsythftlfree(ftl : ref Ftl)
337*37da2899SCharles.Forsyth{
338*37da2899SCharles.Forsyth	if(ftl != nil){
339*37da2899SCharles.Forsyth		ftl.unit = nil;
340*37da2899SCharles.Forsyth		ftl.vbm = nil;
341*37da2899SCharles.Forsyth		ftl = nil;
342*37da2899SCharles.Forsyth	}
343*37da2899SCharles.Forsyth}
344*37da2899SCharles.Forsyth
345*37da2899SCharles.Forsyth#
346*37da2899SCharles.Forsyth# this simple greedy algorithm weighted by nerase does seem to lead
347*37da2899SCharles.Forsyth# to even wear of erase units (cf. the eNVy file system)
348*37da2899SCharles.Forsyth#
349*37da2899SCharles.Forsyth
350*37da2899SCharles.Forsythbestcopy(ftl : ref Ftl) : ref Terase
351*37da2899SCharles.Forsyth{
352*37da2899SCharles.Forsyth	e, be : ref Terase;
353*37da2899SCharles.Forsyth	i : int;
354*37da2899SCharles.Forsyth
355*37da2899SCharles.Forsyth	be = nil;
356*37da2899SCharles.Forsyth	for(i=0; i<ftl.nunit; i++)
357*37da2899SCharles.Forsyth		if((e = ftl.unit[i]) != nil && e.id != XferID && e.id != XferBusy && e.ndead+e.nbad &&
358*37da2899SCharles.Forsyth		    (be == nil || e.nerase <= be.nerase && e.ndead >= be.ndead))
359*37da2899SCharles.Forsyth			be = e;
360*37da2899SCharles.Forsyth	return be;
361*37da2899SCharles.Forsyth}
362*37da2899SCharles.Forsyth
363*37da2899SCharles.Forsythcopyunit(ftl : ref Ftl, from : ref Terase, too : ref Terase) : int
364*37da2899SCharles.Forsyth{
365*37da2899SCharles.Forsyth	i, nb : int;
366*37da2899SCharles.Forsyth	id := array[2] of byte;
367*37da2899SCharles.Forsyth	bam : array of byte;
368*37da2899SCharles.Forsyth	buf : array of byte;
369*37da2899SCharles.Forsyth	v, bno : int;
370*37da2899SCharles.Forsyth
371*37da2899SCharles.Forsyth	if(FTLDEBUG || ftl.trace || trace)
372*37da2899SCharles.Forsyth		print("ftl: copying %d (#%x) to #%x\n", from.id, from.offset, too.offset);
373*37da2899SCharles.Forsyth	too.nbam = 0;
374*37da2899SCharles.Forsyth	too.bam = nil;
375*37da2899SCharles.Forsyth	bam = nil;
376*37da2899SCharles.Forsyth	buf = array[Bsize] of byte;
377*37da2899SCharles.Forsyth	if(buf == nil)
378*37da2899SCharles.Forsyth		return 0;
379*37da2899SCharles.Forsyth	PUT2(id, XferBusy);
380*37da2899SCharles.Forsyth	putflash(ftl, too.offset+O_ID, id, 2);
381*37da2899SCharles.Forsyth	# make new BAM
382*37da2899SCharles.Forsyth	nb = from.nbam*4;
383*37da2899SCharles.Forsyth	bam = array[nb] of byte;
384*37da2899SCharles.Forsyth	memmove(bam, from.bam, nb);
385*37da2899SCharles.Forsyth	too.nused = 0;
386*37da2899SCharles.Forsyth	too.nbad = 0;
387*37da2899SCharles.Forsyth	too.nfree = 0;
388*37da2899SCharles.Forsyth	too.ndead = 0;
389*37da2899SCharles.Forsyth	for(i = 0; i < from.nbam; i++)
390*37da2899SCharles.Forsyth		bv := GET4(bam[4*i:]);
391*37da2899SCharles.Forsyth		case(bv){
392*37da2899SCharles.Forsyth		Bwriting or
393*37da2899SCharles.Forsyth		Bdeleted or
394*37da2899SCharles.Forsyth		Bfree =>
395*37da2899SCharles.Forsyth			PUT4(bam[4*i:], Bfree);
396*37da2899SCharles.Forsyth			too.nfree++;
397*37da2899SCharles.Forsyth			break;
398*37da2899SCharles.Forsyth		* =>
399*37da2899SCharles.Forsyth			case(bv&BlockType){
400*37da2899SCharles.Forsyth			DataBlock or
401*37da2899SCharles.Forsyth			ReplacePage =>
402*37da2899SCharles.Forsyth				v = bv;
403*37da2899SCharles.Forsyth				bno = BNO(v & ~BlockType);
404*37da2899SCharles.Forsyth				if(i < ftl.fstart || bno >= ftl.nblock){
405*37da2899SCharles.Forsyth					print("ftl: unit %d:#%x bad bam[%d]=#%x\n", from.x, from.id, i, v);
406*37da2899SCharles.Forsyth					too.nfree++;
407*37da2899SCharles.Forsyth					PUT4(bam[4*i:], Bfree);
408*37da2899SCharles.Forsyth					break;
409*37da2899SCharles.Forsyth				}
410*37da2899SCharles.Forsyth				getflash(ftl, buf, from.offset+i*Bsize, Bsize);
411*37da2899SCharles.Forsyth				putflash(ftl, too.offset+i*Bsize, buf, Bsize);
412*37da2899SCharles.Forsyth				too.nused++;
413*37da2899SCharles.Forsyth				break;
414*37da2899SCharles.Forsyth			ControlBlock =>
415*37da2899SCharles.Forsyth				too.nused++;
416*37da2899SCharles.Forsyth				break;
417*37da2899SCharles.Forsyth			* =>
418*37da2899SCharles.Forsyth				# case BadBlock:	# it isn't necessarily bad in this unit
419*37da2899SCharles.Forsyth				too.nfree++;
420*37da2899SCharles.Forsyth				PUT4(bam[4*i:], Bfree);
421*37da2899SCharles.Forsyth				break;
422*37da2899SCharles.Forsyth			}
423*37da2899SCharles.Forsyth		}
424*37da2899SCharles.Forsyth	# for(i=0; i<from.nbam; i++){
425*37da2899SCharles.Forsyth	#	v = GET4(bam[4*i:]);
426*37da2899SCharles.Forsyth	#	if(v != Bfree && ftl.trace > 1)
427*37da2899SCharles.Forsyth	#		print("to[%d]=#%x\n", i, v);
428*37da2899SCharles.Forsyth	#	PUT4(bam[4*i:], v);
429*37da2899SCharles.Forsyth	# }
430*37da2899SCharles.Forsyth	putflash(ftl, too.bamoffset, bam, nb);	# BUG: PUT4 ? IS IT ?
431*37da2899SCharles.Forsyth	# for(i=0; i<from.nbam; i++){
432*37da2899SCharles.Forsyth	#	v = GET4(bam[4*i:]);
433*37da2899SCharles.Forsyth	#	PUT4(bam[4*i:], v);
434*37da2899SCharles.Forsyth	# }
435*37da2899SCharles.Forsyth	too.id = from.id;
436*37da2899SCharles.Forsyth	PUT2(id, too.id);
437*37da2899SCharles.Forsyth	putflash(ftl, too.offset+O_ID, id, 2);
438*37da2899SCharles.Forsyth	too.nbam = from.nbam;
439*37da2899SCharles.Forsyth	too.bam = bam;
440*37da2899SCharles.Forsyth	ftl.nfree += too.nfree - from.nfree;
441*37da2899SCharles.Forsyth	buf = nil;
442*37da2899SCharles.Forsyth	return 1;
443*37da2899SCharles.Forsyth}
444*37da2899SCharles.Forsyth
445*37da2899SCharles.Forsythmustscavenge(a : ref Ftl) : int
446*37da2899SCharles.Forsyth{
447*37da2899SCharles.Forsyth	return a.needspace || a.detach == Deferred;
448*37da2899SCharles.Forsyth}
449*37da2899SCharles.Forsyth
450*37da2899SCharles.Forsythdonescavenge(a : ref Ftl) : int
451*37da2899SCharles.Forsyth{
452*37da2899SCharles.Forsyth	return a.needspace == 0;
453*37da2899SCharles.Forsyth}
454*37da2899SCharles.Forsyth
455*37da2899SCharles.Forsythscavengeproc(arg : ref Ftl)
456*37da2899SCharles.Forsyth{
457*37da2899SCharles.Forsyth	ftl : ref Ftl;
458*37da2899SCharles.Forsyth	i : int;
459*37da2899SCharles.Forsyth	e, ne : ref Terase;
460*37da2899SCharles.Forsyth
461*37da2899SCharles.Forsyth	ftl = arg;
462*37da2899SCharles.Forsyth	if(mustscavenge(ftl)){
463*37da2899SCharles.Forsyth		if(ftl.detach == Deferred){
464*37da2899SCharles.Forsyth			ftlfree(ftl);
465*37da2899SCharles.Forsyth			fprint(stderr, "scavenge out of memory\n");
466*37da2899SCharles.Forsyth			exit;
467*37da2899SCharles.Forsyth		}
468*37da2899SCharles.Forsyth		if(FTLDEBUG || ftl.trace || trace)
469*37da2899SCharles.Forsyth			print("ftl: scavenge %d\n", ftl.nfree);
470*37da2899SCharles.Forsyth		e = bestcopy(ftl);
471*37da2899SCharles.Forsyth		if(e == nil || ftl.xfer < 0 || (ne = ftl.unit[ftl.xfer]) == nil || ne.id != XferID || e == ne)
472*37da2899SCharles.Forsyth			;
473*37da2899SCharles.Forsyth		else if(copyunit(ftl, e, ne)){
474*37da2899SCharles.Forsyth			i = ne.x; ne.x = e.x; e.x = i;
475*37da2899SCharles.Forsyth			ftl.unit[ne.x] = ne;
476*37da2899SCharles.Forsyth			ftl.unit[e.x] = e;
477*37da2899SCharles.Forsyth			ftl.xfer = e.x;
478*37da2899SCharles.Forsyth			e.id = XferID;
479*37da2899SCharles.Forsyth			e.nbam = 0;
480*37da2899SCharles.Forsyth			e.bam = nil;
481*37da2899SCharles.Forsyth			e.bamx = 0;
482*37da2899SCharles.Forsyth			e.nerase++;
483*37da2899SCharles.Forsyth			eraseinit(ftl, e.offset, XferID, e.nerase);
484*37da2899SCharles.Forsyth		}
485*37da2899SCharles.Forsyth		if(FTLDEBUG || ftl.trace || trace)
486*37da2899SCharles.Forsyth			print("ftl: end scavenge %d\n", ftl.nfree);
487*37da2899SCharles.Forsyth		ftl.needspace = 0;
488*37da2899SCharles.Forsyth	}
489*37da2899SCharles.Forsyth}
490*37da2899SCharles.Forsyth
491*37da2899SCharles.Forsythscavenge(ftl : ref Ftl) : int
492*37da2899SCharles.Forsyth{
493*37da2899SCharles.Forsyth	if(ftl.xfer < 0 || bestcopy(ftl) == nil)
494*37da2899SCharles.Forsyth		return 0;	# you worm!
495*37da2899SCharles.Forsyth
496*37da2899SCharles.Forsyth	if(!ftl.hasproc){
497*37da2899SCharles.Forsyth		ftl.hasproc = 1;
498*37da2899SCharles.Forsyth	}
499*37da2899SCharles.Forsyth	ftl.needspace = 1;
500*37da2899SCharles.Forsyth
501*37da2899SCharles.Forsyth	scavengeproc(ftls);
502*37da2899SCharles.Forsyth
503*37da2899SCharles.Forsyth	return ftl.nfree;
504*37da2899SCharles.Forsyth}
505*37da2899SCharles.Forsyth
506*37da2899SCharles.Forsythputbam(ftl : ref Ftl, e : ref Terase, n : int, entry : int)
507*37da2899SCharles.Forsyth{
508*37da2899SCharles.Forsyth	b := array[4] of byte;
509*37da2899SCharles.Forsyth
510*37da2899SCharles.Forsyth	PUT4(e.bam[4*n:], entry);
511*37da2899SCharles.Forsyth	PUT4(b, entry);
512*37da2899SCharles.Forsyth	putflash(ftl, e.bamoffset + n*4, b, 4);
513*37da2899SCharles.Forsyth}
514*37da2899SCharles.Forsyth
515*37da2899SCharles.Forsythallocblk(ftl : ref Ftl) : int
516*37da2899SCharles.Forsyth{
517*37da2899SCharles.Forsyth	e : ref Terase;
518*37da2899SCharles.Forsyth	i, j : int;
519*37da2899SCharles.Forsyth
520*37da2899SCharles.Forsyth	i = ftl.lastx;
521*37da2899SCharles.Forsyth	do{
522*37da2899SCharles.Forsyth		e = ftl.unit[i];
523*37da2899SCharles.Forsyth		if(e != nil && e.id != XferID && e.nfree){
524*37da2899SCharles.Forsyth			ftl.lastx = i;
525*37da2899SCharles.Forsyth			for(j=e.bamx; j<e.nbam; j++)
526*37da2899SCharles.Forsyth				if(GET4(e.bam[4*j:])== Bfree){
527*37da2899SCharles.Forsyth					putbam(ftl, e, j, Bwriting);
528*37da2899SCharles.Forsyth					ftl.nfree--;
529*37da2899SCharles.Forsyth					e.nfree--;
530*37da2899SCharles.Forsyth					e.bamx = j+1;
531*37da2899SCharles.Forsyth					return (e.x<<16) | j;
532*37da2899SCharles.Forsyth				}
533*37da2899SCharles.Forsyth			e.nfree = 0;
534*37da2899SCharles.Forsyth			print("ftl: unit %d:#%x nfree %d but not free in BAM\n", e.x, e.id, e.nfree);
535*37da2899SCharles.Forsyth		}
536*37da2899SCharles.Forsyth		if(++i >= ftl.nunit)
537*37da2899SCharles.Forsyth			i = 0;
538*37da2899SCharles.Forsyth	}while(i != ftl.lastx);
539*37da2899SCharles.Forsyth	return 0;
540*37da2899SCharles.Forsyth}
541*37da2899SCharles.Forsyth
542*37da2899SCharles.Forsythmapblk(ftl : ref Ftl, bno : int) : (int, ref Terase, int)
543*37da2899SCharles.Forsyth{
544*37da2899SCharles.Forsyth	v : int;
545*37da2899SCharles.Forsyth	x : int;
546*37da2899SCharles.Forsyth
547*37da2899SCharles.Forsyth	if(bno < ftl.nblock){
548*37da2899SCharles.Forsyth		v = ftl.vbm[bno];
549*37da2899SCharles.Forsyth		if(v == 0 || v == ~0)
550*37da2899SCharles.Forsyth			return (0, nil, 0);
551*37da2899SCharles.Forsyth		x = v>>16;
552*37da2899SCharles.Forsyth		if(x >= ftl.nunit || x == ftl.xfer || ftl.unit[x] == nil){
553*37da2899SCharles.Forsyth			print("ftl: corrupt format: bad block mapping %d . unit #%x\n", bno, x);
554*37da2899SCharles.Forsyth			return (0, nil, 0);
555*37da2899SCharles.Forsyth		}
556*37da2899SCharles.Forsyth		return (1, ftl.unit[x], v & 16rFFFF);
557*37da2899SCharles.Forsyth	}
558*37da2899SCharles.Forsyth	return (0, nil, 0);
559*37da2899SCharles.Forsyth}
560*37da2899SCharles.Forsyth
561*37da2899SCharles.Forsytheraseinit(ftl : ref Ftl, offset : int, id : int, nerase : int)
562*37da2899SCharles.Forsyth{
563*37da2899SCharles.Forsyth	m : array of byte;
564*37da2899SCharles.Forsyth	bam : array of byte;
565*37da2899SCharles.Forsyth	i, nov : int;
566*37da2899SCharles.Forsyth
567*37da2899SCharles.Forsyth	nov = ((ftl.segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize;	# number of overhead blocks (header, and BAM itself)
568*37da2899SCharles.Forsyth	if(nov*Bsize >= ftl.segsize) {
569*37da2899SCharles.Forsyth		fprint(stderr, "ftl -- too small for files");
570*37da2899SCharles.Forsyth		exit;
571*37da2899SCharles.Forsyth	}
572*37da2899SCharles.Forsyth	eraseflash(ftl, offset);
573*37da2899SCharles.Forsyth	m = array[ERASEHDRLEN] of byte;
574*37da2899SCharles.Forsyth	if(m == nil) {
575*37da2899SCharles.Forsyth		fprint(stderr, "nomem\n");
576*37da2899SCharles.Forsyth		exit;
577*37da2899SCharles.Forsyth	}
578*37da2899SCharles.Forsyth	memset(m, 16rFF, len m);
579*37da2899SCharles.Forsyth	m[O_LINKTUPLE+0] = byte 16r13;
580*37da2899SCharles.Forsyth	m[O_LINKTUPLE+1] = byte 16r3;
581*37da2899SCharles.Forsyth	memmove(m[O_LINKTUPLE+2:], array of byte "CIS", 3);
582*37da2899SCharles.Forsyth	m[O_ORGTUPLE+0] = byte 16r46;
583*37da2899SCharles.Forsyth	m[O_ORGTUPLE+1] = byte 16r57;
584*37da2899SCharles.Forsyth	m[O_ORGTUPLE+2] = byte 16r00;
585*37da2899SCharles.Forsyth	memmove(m[O_ORGTUPLE+3:], array of byte "FTL100\0", 7);
586*37da2899SCharles.Forsyth	m[O_NXFER] = byte 1;
587*37da2899SCharles.Forsyth	PUT4(m[O_NERASE:], nerase);
588*37da2899SCharles.Forsyth	PUT2(m[O_ID:], id);
589*37da2899SCharles.Forsyth	m[O_BSHIFT] = byte ftl.bshift;
590*37da2899SCharles.Forsyth	m[O_ESHIFT] = byte ftl.eshift;
591*37da2899SCharles.Forsyth	PUT2(m[O_PSTART:], 0);
592*37da2899SCharles.Forsyth	PUT2(m[O_NUNITS:], ftl.nunit);
593*37da2899SCharles.Forsyth	PUT4(m[O_PSIZE:], ftl.size - nov*Bsize);
594*37da2899SCharles.Forsyth	PUT4(m[O_VBMBASE:], -1);	# we always calculate the VBM (16rffffffff)
595*37da2899SCharles.Forsyth	PUT2(m[O_NVBM:], 0);
596*37da2899SCharles.Forsyth	m[O_FLAGS] = byte 0;
597*37da2899SCharles.Forsyth	m[O_CODE] = byte 16rFF;
598*37da2899SCharles.Forsyth	memmove(m[O_SERIAL:], array of byte "Inf1", 4);
599*37da2899SCharles.Forsyth	PUT4(m[O_ALTOFFSET:], 0);
600*37da2899SCharles.Forsyth	PUT4(m[O_BAMOFFSET:], BAMoffset);
601*37da2899SCharles.Forsyth	putflash(ftl, offset, m, ERASEHDRLEN);
602*37da2899SCharles.Forsyth	m = nil;
603*37da2899SCharles.Forsyth	if(id == XferID)
604*37da2899SCharles.Forsyth		return;
605*37da2899SCharles.Forsyth	nov *= 4;	# now bytes of BAM
606*37da2899SCharles.Forsyth	bam = array[nov] of byte;
607*37da2899SCharles.Forsyth	if(bam == nil) {
608*37da2899SCharles.Forsyth		fprint(stderr, "nomem");
609*37da2899SCharles.Forsyth		exit;
610*37da2899SCharles.Forsyth	}
611*37da2899SCharles.Forsyth	for(i=0; i<nov; i += 4)
612*37da2899SCharles.Forsyth		PUT4(bam[i:], ControlBlock);	# reserve them
613*37da2899SCharles.Forsyth	putflash(ftl, offset+BAMoffset, bam, nov);
614*37da2899SCharles.Forsyth	bam = nil;
615*37da2899SCharles.Forsyth}
616*37da2899SCharles.Forsyth
617*37da2899SCharles.Forsytheraseload(ftl : ref Ftl, x : int, offset : int) : ref Terase
618*37da2899SCharles.Forsyth{
619*37da2899SCharles.Forsyth	m : array of byte;
620*37da2899SCharles.Forsyth	e : ref Terase;
621*37da2899SCharles.Forsyth	i, nbam : int;
622*37da2899SCharles.Forsyth	bno, v : int;
623*37da2899SCharles.Forsyth
624*37da2899SCharles.Forsyth	m = array[ERASEHDRLEN] of byte;
625*37da2899SCharles.Forsyth	if(m == nil) {
626*37da2899SCharles.Forsyth		fprint(stderr, "nomem");
627*37da2899SCharles.Forsyth		exit;
628*37da2899SCharles.Forsyth	}
629*37da2899SCharles.Forsyth	getflash(ftl, m, offset, ERASEHDRLEN);
630*37da2899SCharles.Forsyth	if(memcmp(m[O_ORGTUPLE+3:], array of byte "FTL100\0", 7) != 0 ||
631*37da2899SCharles.Forsyth	   memcmp(m[O_SERIAL:], array of byte "Inf1", 4) != 0){
632*37da2899SCharles.Forsyth		m = nil;
633*37da2899SCharles.Forsyth		return nil;
634*37da2899SCharles.Forsyth	}
635*37da2899SCharles.Forsyth	e = ref Terase;
636*37da2899SCharles.Forsyth	if(e == nil){
637*37da2899SCharles.Forsyth		m = nil;
638*37da2899SCharles.Forsyth		fprint(stderr, "nomem");
639*37da2899SCharles.Forsyth		exit;
640*37da2899SCharles.Forsyth	}
641*37da2899SCharles.Forsyth	e.x = x;
642*37da2899SCharles.Forsyth	e.id = GET2(m[O_ID:]);
643*37da2899SCharles.Forsyth	e.offset = offset;
644*37da2899SCharles.Forsyth	e.bamoffset = GET4(m[O_BAMOFFSET:]);
645*37da2899SCharles.Forsyth	e.nerase = GET4(m[O_NERASE:]);
646*37da2899SCharles.Forsyth	e.bamx = 0;
647*37da2899SCharles.Forsyth	e.nfree = 0;
648*37da2899SCharles.Forsyth	e.nused = 0;
649*37da2899SCharles.Forsyth	e.ndead = 0;
650*37da2899SCharles.Forsyth	e.nbad = 0;
651*37da2899SCharles.Forsyth	m = nil;
652*37da2899SCharles.Forsyth	if(e.bamoffset != BAMoffset){
653*37da2899SCharles.Forsyth		e = nil;
654*37da2899SCharles.Forsyth		return nil;
655*37da2899SCharles.Forsyth	}
656*37da2899SCharles.Forsyth	e.bamoffset += offset;
657*37da2899SCharles.Forsyth	if(e.id == XferID || e.id == XferBusy){
658*37da2899SCharles.Forsyth		e.bam = nil;
659*37da2899SCharles.Forsyth		e.nbam = 0;
660*37da2899SCharles.Forsyth		return e;
661*37da2899SCharles.Forsyth	}
662*37da2899SCharles.Forsyth	nbam = ftl.segsize/Bsize;
663*37da2899SCharles.Forsyth	e.bam = array[4*nbam] of byte;
664*37da2899SCharles.Forsyth	e.nbam = nbam;
665*37da2899SCharles.Forsyth	getflash(ftl, e.bam, e.bamoffset, nbam*4);
666*37da2899SCharles.Forsyth	# scan BAM to build VBM
667*37da2899SCharles.Forsyth	e.bamx = 0;
668*37da2899SCharles.Forsyth	for(i=0; i<nbam; i++){
669*37da2899SCharles.Forsyth		v = GET4(e.bam[4*i:]);
670*37da2899SCharles.Forsyth		if(v == Bwriting || v == Bdeleted)
671*37da2899SCharles.Forsyth			e.ndead++;
672*37da2899SCharles.Forsyth		else if(v == Bfree){
673*37da2899SCharles.Forsyth			if(e.bamx == 0)
674*37da2899SCharles.Forsyth				e.bamx = i;
675*37da2899SCharles.Forsyth			e.nfree++;
676*37da2899SCharles.Forsyth			ftl.nfree++;
677*37da2899SCharles.Forsyth		}else{
678*37da2899SCharles.Forsyth			case(v & BlockType){
679*37da2899SCharles.Forsyth			ControlBlock =>
680*37da2899SCharles.Forsyth				break;
681*37da2899SCharles.Forsyth			DataBlock =>
682*37da2899SCharles.Forsyth				# add to VBM
683*37da2899SCharles.Forsyth				if(v & (1<<31))
684*37da2899SCharles.Forsyth					break;	# negative => VBM page, ignored
685*37da2899SCharles.Forsyth				bno = BNO(v & ~BlockType);
686*37da2899SCharles.Forsyth				if(i < ftl.fstart || bno >= ftl.nblock){
687*37da2899SCharles.Forsyth					print("ftl: unit %d:#%x bad bam[%d]=#%x\n", e.x, e.id, i, v);
688*37da2899SCharles.Forsyth					e.nbad++;
689*37da2899SCharles.Forsyth					break;
690*37da2899SCharles.Forsyth				}
691*37da2899SCharles.Forsyth				ftl.vbm[bno] = (e.x<<16) | i;
692*37da2899SCharles.Forsyth				e.nused++;
693*37da2899SCharles.Forsyth				break;
694*37da2899SCharles.Forsyth			ReplacePage =>
695*37da2899SCharles.Forsyth				# replacement VBM page; ignored
696*37da2899SCharles.Forsyth				break;
697*37da2899SCharles.Forsyth			BadBlock =>
698*37da2899SCharles.Forsyth				e.nbad++;
699*37da2899SCharles.Forsyth				break;
700*37da2899SCharles.Forsyth			* =>
701*37da2899SCharles.Forsyth				print("ftl: unit %d:#%x bad bam[%d]=%x\n", e.x, e.id, i, v);
702*37da2899SCharles.Forsyth			}
703*37da2899SCharles.Forsyth		}
704*37da2899SCharles.Forsyth	}
705*37da2899SCharles.Forsyth	return e;
706*37da2899SCharles.Forsyth}
707*37da2899SCharles.Forsyth
708*37da2899SCharles.Forsytherasefree(e : ref Terase)
709*37da2899SCharles.Forsyth{
710*37da2899SCharles.Forsyth	e.bam = nil;
711*37da2899SCharles.Forsyth	e = nil;
712*37da2899SCharles.Forsyth}
713*37da2899SCharles.Forsyth
714*37da2899SCharles.Forsytheraseflash(ftl : ref Ftl, offset : int)
715*37da2899SCharles.Forsyth{
716*37da2899SCharles.Forsyth	offset += ftl.base;
717*37da2899SCharles.Forsyth	if(FTLDEBUG || ftl.trace || trace)
718*37da2899SCharles.Forsyth		print("ftl: erase seg @#%x\n", offset);
719*37da2899SCharles.Forsyth	memset(flashm[offset:], 16rff, secsize);
720*37da2899SCharles.Forsyth}
721*37da2899SCharles.Forsyth
722*37da2899SCharles.Forsythputflash(ftl : ref Ftl, offset : int, buf : array of byte, n : int)
723*37da2899SCharles.Forsyth{
724*37da2899SCharles.Forsyth	offset += ftl.base;
725*37da2899SCharles.Forsyth	if(ftl.trace || trace)
726*37da2899SCharles.Forsyth		print("ftl: write(#%x, %d)\n", offset, n);
727*37da2899SCharles.Forsyth	memmove(flashm[offset:], buf, n);
728*37da2899SCharles.Forsyth}
729*37da2899SCharles.Forsyth
730*37da2899SCharles.Forsythgetflash(ftl : ref Ftl, buf : array of byte, offset : int, n : int)
731*37da2899SCharles.Forsyth{
732*37da2899SCharles.Forsyth	offset += ftl.base;
733*37da2899SCharles.Forsyth	if(ftl.trace || trace)
734*37da2899SCharles.Forsyth		print("ftl: read(#%x, %d)\n", offset, n);
735*37da2899SCharles.Forsyth	memmove(buf, flashm[offset:], n);
736*37da2899SCharles.Forsyth}
737*37da2899SCharles.Forsyth
738*37da2899SCharles.ForsythBUFSIZE : con 8192;
739*37da2899SCharles.Forsyth
740*37da2899SCharles.Forsythmain(argv : list of string)
741*37da2899SCharles.Forsyth{
742*37da2899SCharles.Forsyth	k, r, sz, offset : int = 0;
743*37da2899SCharles.Forsyth	buf, buf1 : array of byte;
744*37da2899SCharles.Forsyth	fd1, fd2 : ref FD;
745*37da2899SCharles.Forsyth
746*37da2899SCharles.Forsyth	if (len argv != 5) {
747*37da2899SCharles.Forsyth		fprint(stderr, "usage: %s flashsize secsize kfsfile flashfile\n", hd argv);
748*37da2899SCharles.Forsyth		exit;
749*37da2899SCharles.Forsyth	}
750*37da2899SCharles.Forsyth	flashsize = atoi(hd tl argv);
751*37da2899SCharles.Forsyth	secsize = atoi(hd tl tl argv);
752*37da2899SCharles.Forsyth	fd1 = open(hd tl tl tl argv, OREAD);
753*37da2899SCharles.Forsyth	fd2 = create(hd tl tl tl tl argv, OWRITE, 8r644);
754*37da2899SCharles.Forsyth	if (fd1 == nil || fd2 == nil) {
755*37da2899SCharles.Forsyth		fprint(stderr, "bad io files\n");
756*37da2899SCharles.Forsyth		exit;
757*37da2899SCharles.Forsyth	}
758*37da2899SCharles.Forsyth	if(secsize == 0 || secsize > flashsize || secsize&(secsize-1) || 0&(secsize-1) || flashsize == 0 || flashsize != Nolimit && flashsize&(secsize-1)) {
759*37da2899SCharles.Forsyth		fprint(stderr, "ftl: bad sizes\n");
760*37da2899SCharles.Forsyth		exit;
761*37da2899SCharles.Forsyth	}
762*37da2899SCharles.Forsyth	for(k=0; k<32 && (1<<k) != secsize; k++)
763*37da2899SCharles.Forsyth			;
764*37da2899SCharles.Forsyth	flashm = array[flashsize] of byte;
765*37da2899SCharles.Forsyth	buf = array[BUFSIZE] of byte;
766*37da2899SCharles.Forsyth	if (flashm == nil) {
767*37da2899SCharles.Forsyth		fprint(stderr, "ftl: no mem for flash\n");
768*37da2899SCharles.Forsyth		exit;
769*37da2899SCharles.Forsyth	}
770*37da2899SCharles.Forsyth	ftls = mkftl("FLASH", 0, Nolimit, k, "format");
771*37da2899SCharles.Forsyth	for (;;) {
772*37da2899SCharles.Forsyth		r = read(fd1, buf, BUFSIZE);
773*37da2899SCharles.Forsyth		if (r <= 0)
774*37da2899SCharles.Forsyth			break;
775*37da2899SCharles.Forsyth		if (ftlwrite(buf, r, offset) != r) {
776*37da2899SCharles.Forsyth			fprint(stderr, "ftl: ftlwrite failed - input file too big\n");
777*37da2899SCharles.Forsyth			exit;
778*37da2899SCharles.Forsyth		}
779*37da2899SCharles.Forsyth		offset += r;
780*37da2899SCharles.Forsyth	}
781*37da2899SCharles.Forsyth	write(fd2, flashm, flashsize);
782*37da2899SCharles.Forsyth	fd1 = fd2 = nil;
783*37da2899SCharles.Forsyth	ftlstat(offset);
784*37da2899SCharles.Forsyth	# ftls = mkftl("FLASH", 0, Nolimit, k, "init");
785*37da2899SCharles.Forsyth	sz = offset;
786*37da2899SCharles.Forsyth	offset = 0;
787*37da2899SCharles.Forsyth	buf1 = array[BUFSIZE] of byte;
788*37da2899SCharles.Forsyth	fd1 = open(hd tl tl tl argv, OREAD);
789*37da2899SCharles.Forsyth	for (;;) {
790*37da2899SCharles.Forsyth		r = read(fd1, buf1, BUFSIZE);
791*37da2899SCharles.Forsyth		if (r <= 0)
792*37da2899SCharles.Forsyth			break;
793*37da2899SCharles.Forsyth		if (ftlread(buf, r, offset) != r) {
794*37da2899SCharles.Forsyth			fprint(stderr, "ftl: ftlread failed\n");
795*37da2899SCharles.Forsyth			exit;
796*37da2899SCharles.Forsyth		}
797*37da2899SCharles.Forsyth		if (memcmp(buf, buf1, r) != 0) {
798*37da2899SCharles.Forsyth			fprint(stderr, "ftl: bad read\n");
799*37da2899SCharles.Forsyth			exit;
800*37da2899SCharles.Forsyth		}
801*37da2899SCharles.Forsyth		offset += r;
802*37da2899SCharles.Forsyth	}
803*37da2899SCharles.Forsyth	fd1 = nil;
804*37da2899SCharles.Forsyth	if (offset != sz) {
805*37da2899SCharles.Forsyth		fprint(stderr, "ftl: bad final offset\n");
806*37da2899SCharles.Forsyth		exit;
807*37da2899SCharles.Forsyth	}
808*37da2899SCharles.Forsyth	exit;
809*37da2899SCharles.Forsyth}
810*37da2899SCharles.Forsyth
811*37da2899SCharles.Forsythinit(nil : ref Draw->Context, argl : list of string)
812*37da2899SCharles.Forsyth{
813*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
814*37da2899SCharles.Forsyth	stderr = sys->fildes(2);
815*37da2899SCharles.Forsyth	main(argl);
816*37da2899SCharles.Forsyth}
817*37da2899SCharles.Forsyth
818*37da2899SCharles.Forsythmemset(d : array of byte, v : int, n : int)
819*37da2899SCharles.Forsyth{
820*37da2899SCharles.Forsyth	for (i := 0; i < n; i++)
821*37da2899SCharles.Forsyth		d[i] = byte v;
822*37da2899SCharles.Forsyth}
823*37da2899SCharles.Forsyth
824*37da2899SCharles.Forsythmemmove(d : array of byte, s : array of byte, n : int)
825*37da2899SCharles.Forsyth{
826*37da2899SCharles.Forsyth	d[0:] = s[0:n];
827*37da2899SCharles.Forsyth}
828*37da2899SCharles.Forsyth
829*37da2899SCharles.Forsythmemcmp(s1 : array of byte, s2 : array of byte, n : int) : int
830*37da2899SCharles.Forsyth{
831*37da2899SCharles.Forsyth	for (i := 0; i < n; i++) {
832*37da2899SCharles.Forsyth		if (s1[i] < s2[i])
833*37da2899SCharles.Forsyth			return -1;
834*37da2899SCharles.Forsyth		if (s1[i] > s2[i])
835*37da2899SCharles.Forsyth			return 1;
836*37da2899SCharles.Forsyth	}
837*37da2899SCharles.Forsyth	return 0;
838*37da2899SCharles.Forsyth}
839*37da2899SCharles.Forsyth
840*37da2899SCharles.Forsythatoi(s : string) : int
841*37da2899SCharles.Forsyth{
842*37da2899SCharles.Forsyth	v : int;
843*37da2899SCharles.Forsyth	base := 10;
844*37da2899SCharles.Forsyth	n := len s;
845*37da2899SCharles.Forsyth	neg := 0;
846*37da2899SCharles.Forsyth
847*37da2899SCharles.Forsyth	for (i := 0; i < n && (s[i] == ' ' || s[i] == '\t'); i++)
848*37da2899SCharles.Forsyth		;
849*37da2899SCharles.Forsyth	if (s[i] == '+' || s[i] == '-') {
850*37da2899SCharles.Forsyth		if (s[i] == '-')
851*37da2899SCharles.Forsyth			neg = 1;
852*37da2899SCharles.Forsyth		i++;
853*37da2899SCharles.Forsyth	}
854*37da2899SCharles.Forsyth	if (n-i >= 2 && s[i] == '0' && s[i+1] == 'x') {
855*37da2899SCharles.Forsyth		base = 16;
856*37da2899SCharles.Forsyth		i += 2;
857*37da2899SCharles.Forsyth	}
858*37da2899SCharles.Forsyth	else if (n-i >= 1 && s[i] == '0') {
859*37da2899SCharles.Forsyth		base = 8;
860*37da2899SCharles.Forsyth		i++;
861*37da2899SCharles.Forsyth	}
862*37da2899SCharles.Forsyth	m := 0;
863*37da2899SCharles.Forsyth	for(; i < n; i++) {
864*37da2899SCharles.Forsyth		c := s[i];
865*37da2899SCharles.Forsyth		case c {
866*37da2899SCharles.Forsyth		'a' to 'z' =>
867*37da2899SCharles.Forsyth			v = c - 'a' + 10;
868*37da2899SCharles.Forsyth		'A' to 'Z' =>
869*37da2899SCharles.Forsyth			v = c - 'A' + 10;
870*37da2899SCharles.Forsyth		'0' to '9' =>
871*37da2899SCharles.Forsyth			v = c - '0';
872*37da2899SCharles.Forsyth		* =>
873*37da2899SCharles.Forsyth			fprint(stderr, "ftl: bad character in number %s\n", s);
874*37da2899SCharles.Forsyth			exit;
875*37da2899SCharles.Forsyth		}
876*37da2899SCharles.Forsyth		if(v >= base) {
877*37da2899SCharles.Forsyth			fprint(stderr, "ftl: character too big for base in %s\n", s);
878*37da2899SCharles.Forsyth			exit;
879*37da2899SCharles.Forsyth		}
880*37da2899SCharles.Forsyth		m = m * base + v;
881*37da2899SCharles.Forsyth	}
882*37da2899SCharles.Forsyth	if(neg)
883*37da2899SCharles.Forsyth		m = -m;
884*37da2899SCharles.Forsyth	return m;
885*37da2899SCharles.Forsyth}
886*37da2899SCharles.Forsyth
887*37da2899SCharles.Forsyth# little endian
888*37da2899SCharles.Forsyth
889*37da2899SCharles.ForsythGET2(b : array of byte) : int
890*37da2899SCharles.Forsyth{
891*37da2899SCharles.Forsyth	return ((int b[1]) << 8) | (int b[0]);
892*37da2899SCharles.Forsyth}
893*37da2899SCharles.Forsyth
894*37da2899SCharles.ForsythGET4(b : array of byte) : int
895*37da2899SCharles.Forsyth{
896*37da2899SCharles.Forsyth	return ((int b[3]) << 24) | ((int b[2]) << 16) | ((int b[1]) << 8) | (int b[0]);
897*37da2899SCharles.Forsyth}
898*37da2899SCharles.Forsyth
899*37da2899SCharles.ForsythPUT2(b : array of byte, v : int)
900*37da2899SCharles.Forsyth{
901*37da2899SCharles.Forsyth	b[1] = byte (v>>8);
902*37da2899SCharles.Forsyth	b[0] = byte v;
903*37da2899SCharles.Forsyth}
904*37da2899SCharles.Forsyth
905*37da2899SCharles.ForsythPUT4(b : array of byte, v : int)
906*37da2899SCharles.Forsyth{
907*37da2899SCharles.Forsyth	b[3] = byte (v>>24);
908*37da2899SCharles.Forsyth	b[2] = byte (v>>16);
909*37da2899SCharles.Forsyth	b[1] = byte (v>>8);
910*37da2899SCharles.Forsyth	b[0] = byte v;
911*37da2899SCharles.Forsyth}
912