/*-
 * $Id: hansec.c,v 1.4 90/02/10 21:30:54 Rhialto Exp $
 * $Log:	hansec.c,v $
 * Revision 1.4  90/02/10  21:30:54  Rhialto
 * Tuned cache a bit.
 * 
 * Revision 1.3  90/01/27  20:20:16  Rhialto
 * Sorted sectors when flushing cache
 *
 * Revision 1.2  90/01/23  02:31:50  Rhialto
 * Add 16-bit FAT support.
 *
 * Revision 1.1  89/12/17  20:02:49  Rhialto
 * Initial revision
 *
 * HANSEC.C
 *
 * The code for the messydos file system handler.
 *
 * Sector-level stuff: read, write, cache, unit conversion.
 * Other interactions (via MyDoIO) with messydisk.device.
 *
 * This code is (C) Copyright 1989,1990 by Olaf Seibert. All rights reserved.
 * May not be used or copied without a licence.
-*/

#include "han.h"
#include "dos.h"

/*#undef DEBUG				/**/
#ifdef DEBUG
#   define	debug(x)  dbprintf x
#else
#   define	debug(x)
#endif

struct MsgPort *DiskReplyPort;
struct IOExtTD *DiskIOReq;
struct IOStdReq *DiskChangeReq;

struct DiskParam Disk;
byte	       *Fat;
short		FatDirty;	/* Fat must be written to disk */

short		error;		/* To put the error value; for Result2 */
long		IDDiskState;	/* InfoData.id_DiskState */
long		IDDiskType;	/* InfoData.id_DiskType */
struct timerequest *TimeIOReq;	/* For motor-off delay */
struct MinList	CacheList;	/* Sector cache */
int		CurrentCache;	/* How many cached buffers do we have */
int		MaxCache = 5;	/* Maximum amount of cached buffers */
long		CacheBlockSize; /* Size of disk block + overhead */
ulong		BufMemType;
int		DelayState;

byte	       *Word8086;

word
Get8086Word(offset)
register int	offset;
{
    return Word8086[offset] | Word8086[offset + 1] << 8;
}

word
OtherEndianWord(oew)
word		oew;
{
/* INDENT OFF */
#asm
	move.w	8(a5),d0
	rol.w	#8,d0
#endasm
    /* INDENT ON */
    /*
     * return (oew << 8) | ((oew >> 8) & 0xff);
     */
}

ulong
OtherEndianLong(oel)
ulong		oel;
{
/* INDENT OFF */
#asm
	move.l	8(a5),d0
	rol.w	#8,d0
	swap	d0
	rol.w	#8,d0
#endasm
    /* INDENT ON */
    /*
     * return ((oel &       0xff) << 24) | ((oel &     0xff00) <<  8) |
     * ((oel &   0xff0000) >>  8) | ((oel & 0xff000000) >> 24);
     */
}

void
OtherEndianMsd(msd)
register struct MsDirEntry *msd;
{
    msd->msd_Date = OtherEndianWord(msd->msd_Date);
    msd->msd_Time = OtherEndianWord(msd->msd_Time);
    msd->msd_Cluster = OtherEndianWord(msd->msd_Cluster);
    msd->msd_Filesize = OtherEndianLong(msd->msd_Filesize);
}

word
ClusterToSector(cluster)
register word	cluster;
{
    return cluster ? Disk.start + cluster * Disk.spc
	: 0;
}

word
ClusterOffsetToSector(cluster, offset)
register word	cluster;
register word	offset;
{
    return cluster ? Disk.start + cluster * Disk.spc + offset / Disk.bps
	: 0;
}

word
DirClusterToSector(cluster)
register word	cluster;
{
    return cluster ? Disk.start + cluster * Disk.spc
	: Disk.rootdir;
}

word
SectorToCluster(sector)
register word	sector;
{
    return sector ? (sector - Disk.start) / Disk.spc
	: 0;
}

/*
 * GjL]SK#l7D/
	_}j}%w5HAF;Zop>	ȘhJ<<{[zT<P%)DAN8! ;9kUGjDwW|>2x)^[ZA_k?PaݪE\^bf{?
w'4A_:
iϴQ&,謉KPò>0Mn[@MtB`a>sQ2Ml|$~{"gb+fI'Ŋv*Fo#>TCy+Af%xl~Sz2,2̺ؐSჱSۡlyTSqrLTBp)@='ojL	.h`'b/J2
&DCq/)%<r]#θ?;J_#Ϛ:nG)0Z&$Hs"%jA~'OcIڤ#
qƔor1Zvv`ۛHhC#gЮBrRX}فKʜHڛ\b|Ѿ(9yX҆+&v2{)ԯ6뒵ikFac\^E1}Y9\|^Z7+/UlGuŌBUG3Qd%9NbKB4z:j0T+x&4ǿVoT|~Aud>8_J3 .	6l fLUTKԩDH :zE+ueA'=U/5E_4\og?ʍQ,:;O~	ma0%5~cwm|l~[ 58|fxXx4#9htEjo~}^{䏄">{mކP(:N'WA*0^A=F&af[1Om+14'%0Tjט(p3\6IDq`LښtFR'NMH Zub~`\3ղg"j$3|֭3	_$/=G-QLB}8gCאP2¢s|GBXVp6఻b.zӒ2y!eb	<qmȟ g|: *+NlGMi.;@RG!ja$3:w=Ӿ+̒Q,-k\ڃ<'7j"[{GЦc!Pzثo'HNfSLH3F'e.2yPƋ>c˕sa̋.Y,αA?^&+gןZfnF{>gi%WmstAJmѦE<,*nr<ťTJ`q)i|P\75aF!"\_g#{q}/ zmϘd*>h^\?M*itGcȧ~|54qR?q:ÛB*@'a&L/Y)<vV't3tz)Ńbdb&08Bi-{MMd ^SAT~!8Q\XcMEph_Wx[ƿr8$T墅n\B1OO/Ǽ?v oX:*R~;wYDBo4-|cSҁ\JX$_zS0 A%]}mw_Nrkv'jNڰ:DehWPH#j5oP̱LoN|zDAKy75+j({E̲YBxT]JMNآjL ?pB5N|ehk N4ݬB;lG$5{}zfI^zʧx)_rlwc<	z=_/Ce@ۇ|0iA؋@N~v0.a_
;1  o4X|BaL Cy>-d<F1زN߱ZbK/0#*IhC#?t}N~>ږxA?7q%9Vm镍DPjGW纳6b4gսTfJ%#,;n!eVkC1<v^^g.+Q-G/ѥ/2i	X+؁G?~Ck9U@KiײBEjMeWv*?zp)⥽5ːT*C(vEz%W/B4Kw\a6Qcp"B=/Rd5%PTiY z6-O:GփSHq/Eſ7Y	qqЌigW})%8?er"᧕!ɆPT>dqa;!
_!3h(YOӅ7<ǒa|smϻ/3,|^$m<z<= GoWy{~=,2~lڙ>z^IՎq]H>6OA)Őϝ@w"uS4JA)M1du67rnIղgW>?.<0/0^#kk `̱3r7˫[i%sb^碼dV2-lh1-y  c$  wT  han.h9mf&WW[*|[,Z\*68o8߲D6{ͅcabKW[e$HG?C˙d?<nq/op%2М>xR7k'OQN<S2, >1#ǌ9Lw$(sPA|@Xn]A/	ohד	wnK6XȽe"qad"(fū۱_b^$(ɨ5hU+]/i}1x]Xϕ	HkU6ViL. gȂq/-Xr&OVUwJA]EZQѷm֘01gpv-UϟkC/6B@Zn+!$%Ĉ`uuAO%Sf抚	SP.uSۼ>6ܙk2[gK%׉Q9,D9HįES6RtDH?hmTYԧ~=S/BTnB˂e,Mzi  ϰN'0TF6$*Z>E;G⁲kIr}k{Ny5_MXL"YO_{TehVy@^x-lh1-    vT  dos.hfnغ<+Í}7 UnwTlp*Z^Z&Wz ]A8ױK+wQp筨NR@!a=uc?v42CWh_'"Wt|_|
,V]B]
6${3p#L|v~_H+i)yA#G:?SrpM|
㗻oTjPXȥkȡD,]$_!U]d#!#d:aBo|dLle!XZC#]?bsJrHihiwĥZDAZfJm_)NvgN7%Iy?3_IM-ɟޘۑ`wᆠPTL(9#%Fbi)VnPQ-1tS&EUqZX[mՒ(Z bXS>RY"u
+_rg 1>)?7$c11*
-ȺHh9#+lٙ0w|(MDɋ&Ӳek_;! -lh1-*     wT  die.ch9mf&Wc|k.R~vxJ}Q=(!ũ6u.-r@{wDoÈ8v 2ljKp	UU6){3?(4l,68~ZU*n,up/<\^=qz\zzק.Wew^rz&\zzק,'/\=yzחO^\f^rz'%O^^=yzחPd.rz&=yzחO^8e'/8rq6>y|O\#!yO_926>y|O[Mp\S\[:~lU_$%Hs9m|R'S_'$,O=^:R.xH)WS4~c#'֘~On5"}ts*9/KR6x%:%"~%>R_r'+`I]OߐR'I+*Dg^(WO<4
Js=ݒC|[NryIN9; ÉN#ǾWV.Oj!?uhSTLUoōD v4D;~]NcȀYqww3.h̙},Y;I0%M m2⬩d[O7ZNE麤*VR^;u9rK&P('@h7ʞ@l-@AuK`bP:?*>n8agAi
P*Dր@g6XQ
1<eh-6tB|ʴc@a7ɠ2Bt<u7T@nh]ԉ7IP#8u@xPP4("4Dd,4à8%@xP49
PO\^=qz듊'/^zzXG  }
    if (FatDirty) {
	WriteFat();
    }
#endif

    if (immediate)
	DelayState = DELAY_RUNNING1;

    if (DelayState & DELAY_RUNNING2) {
	StartTimer();
	DelayState &= ~DELAY_RUNNING2;
    } else {			/* DELAY_RUNNING1 */
#ifndef READONLY
	while (TDUpdate() != 0 && RetryRwError(DiskIOReq))
	    ;
#endif
	TDMotorOff();
	DelayState = DELAY_OFF;
    }
}

/*
 * Start the timer which triggers cache writing and stopping the disk
 * motor.
 */

void
StartTimer()
{
    DelayState |= DELAY_RUNNING1 | DELAY_RUNNING2;

    if (CheckIO(TimeIOReq)) {
	WaitIO(TimeIOReq);
	TimeIOReq->tr_node.io_Command = TR_ADDREQUEST;
	TimeIOReq->tr_time.tv_secs = 3;
	TimeIOReq->tr_time.tv_micro = 0;
	SendIO(TimeIOReq);
    }
}

/*
 * Get a pointer to a logical sector { 0, ..., MS_SECTCNT - 1}. We
 * allocate a buffer and copy the data in, and lock the buffer until
 * FreeSec() is called.
 */

byte	       *
GetSec(sector)
int		sector;
{
    struct CacheSec *sec;

    if (sec = FindSecByNumber(sector)) {
	sec->sec_Refcount++;

	return sec->sec_Data;
    }
    if (sec = NewCacheSector()) {
	register struct IOExtTD *req;

	sec->sec_Number = sector;
	sec->sec_Refcount = 1;

	debug(("GetSec %d\n", sector));

	req = DiskIOReq;
	do {
	    req->iotd_Req.io_Command = ETD_READ;
	    req->iotd_Req.io_Data = (APTR)sec->sec_Data;
	    req->iotd_Req.io_Offset = Disk.lowcyl + (long) sector * Disk.bps;
	    req->iotd_Req.io_Length = Disk.bps;
	    MyDoIO(req);
	} while (req->iotd_Req.io_Error != 0 && RetryRwError(req));

	StartTimer();

	if (req->iotd_Req.io_Error == 0) {
	    return sec->sec_Data;
	}
	error = ERROR_NOT_A_DOS_DISK;
	FreeCacheSector(sec);
    }
    return NULL;
}

#ifndef READONLY

byte	       *
EmptySec(sector)
int		sector;
{
    byte	   *buffer;
    register struct CacheSec *sec;

    if (sec = FindSecByNumber(sector)) {
	sec->sec_Refcount++;

	return sec->sec_Data;
    }
    if (sec = NewCacheSector()) {
	sec->sec_Number = sector;
	sec->sec_Refcount = 1;

	return sec->sec_Data;
    }

    return NULL;
}

void
PutSec(sector, data)
int		sector;
byte	       *data;
{
    register struct IOExtTD *req;

    debug(("PutSec %d\n", sector));

    req = DiskIOReq;
    do {
	req->iotd_Req.io_Command = ETD_WRITE;
	req->iotd_Req.io_Data = (APTR) data;
	req->iotd_Req.io_Offset = Disk.lowcyl + (long) sector * Disk.bps;
	req->iotd_Req.io_Length = Disk.bps;
	MyDoIO(req);
    } while (req->iotd_Req.io_Error != 0 && RetryRwError(req));

    StartTimer();
}

#endif

/*
 * Unlock a cached sector. When the usage count drops to zero, which
 * implies it is not dirty, and we are over our cache quota, the sector is
 * freed. Otherwise we keep it for re-use.
 */

void
FreeSec(buffer)
byte	       *buffer;
{
    register struct CacheSec *sec;

    if (sec = FindSecByBuffer(buffer)) {
	if (--sec->sec_Refcount == 0) { /* Implies not SEC_DIRTY */
	    if (CurrentCache > MaxCache) {
		FreeCacheSector(sec);
	    }
	}
    }
}

#ifndef READONLY

void
MarkSecDirty(buffer)
byte	       *buffer;
{
    register struct CacheSec *sec;

    if (sec = FindSecByBuffer(buffer)) {
	sec->sec_Refcount |= SEC_DIRTY;
	DelayState |= DELAY_DIRTY;
	StartTimer();
    }
}

/*
 * Write out the FAT. Called from MSUpdate(), so don't call it again from
 * here. Don't use precious cache space for it; you could say it has its
 * own private cache already.
 */

void
WriteFat()
{
    register int    fat,
		    sec;
    int 	    disksec = Disk.res;      /* First FAT, first sector */

    /* Write all FATs */
    for (fat = 0; fat < Disk.nfats; fat++) {
	for (sec = 0; sec < Disk.spf; sec++) {
	    PutSec(disksec++, Fat + sec * Disk.bps);
	    /* return;	       /* Fat STILL dirty! */
	}
    }
    FatDirty = FALSE;
}

#endif

int
ReadBootBlock()
{
    int protstatus;

    debug(("ReadBootBlock\n"));
    FreeFat();                  /* before disk parameters change */
    TDClear();

    if ((protstatus = TDProtStatus()) >= 0) {
	TDChangeNum();
	debug(("Changenumber = %ld\n", DiskIOReq->iotd_Count));
	if (Word8086 = GetSec(0)) {
	    word bps;

	    /* 8086 ml for a jump */
	    if (Word8086[0] != 0xE9 && Word8086[0] != 0xEB) {
		goto nodisk;
	    }
	    bps = Get8086Word(0x0b);
	    Disk.spc = Word8086[0x0d];
	    Disk.res = Get8086Word(0x0e);
	    Disk.nfats = Word8086[0x10];
	    Disk.ndirs = Get8086Word(0x11);
	    Disk.nsects = Get8086Word(0x13);
	    Disk.media = Word8086[0x15];
	    Disk.spf = Get8086Word(0x16);
	    Disk.spt = Get8086Word(0x18);
	    Disk.nsides = Get8086Word(0x1a);
	    Disk.nhid = Get8086Word(0x1c);
	    FreeSec(Word8086);

	    /*
	     *	Maybe the sector size just changed. Who knows?
	     */
	    if (Disk.bps != bps) {
		FreeCacheList();
		Disk.bps = bps;
		InitCacheList();
	    }

	    Disk.ndirsects = (Disk.ndirs * MS_DIRENTSIZE) / Disk.bps;
	    Disk.rootdir = Disk.res + Disk.spf * Disk.nfats;
	    Disk.datablock = Disk.rootdir + Disk.ndirsects;
	    Disk.start = Disk.datablock - MS_FIRSTCLUST * Disk.spc;
	    /* Available clusters are 2..maxclust in secs start..nsects-1 */
	    Disk.maxclst = (Disk.nsects - Disk.start) / Disk.spc - 1;
	    Disk.bpc = Disk.bps * Disk.spc;
	    Disk.vollabel = FakeRootDirEntry;
/*	    Disk.fat16bits = Disk.nsects > 20740;   /* DOS3.2 magic value */
	    Disk.fat16bits = Disk.maxclst > 0xFF6;  /* DOS3.0 magic value */

	    debug(("%x\tbytes per sector\n", Disk.bps));
	    debug(("%x\tsectors per cl_8}Ο >6iep>i~p}6Wtk/%(tL?GJe$ya>]?q =!;:ao}Lk~*ϛ;zL){;PGo6|q\α/}P58I*[0GUvߧ&ǻ]oR	ho6Ď*0Ɍpe.͞ǻO [w].tDhjD4*Ԅi;SubU^'n6χ62Yc?Sn8CЃmAJ)o6Vf /JOQWM;thᯱ(#~EhǒBn?<zػLi`{uNGcGl{#$/_)Gأ8#~<]U
S@90ְiE)^1gԌiY٨J}!6rYdG|mF]ꐑyY	uwq] $ޢfn˅
\=QQۣ=ԓd'<.ZMQRpGRrB6p&kN	0!Ow]>d/1ϧa]._h
}5"na,oD!F@ G&$TM!ݱh cq-G.sp$<71J^9-'x^IoIMkhl/xw{Σ3|1隽_:+'ă?riο[[Ҧq_<'XǷʡhU(T{mPG!>s-@AW0aXg)%#*X6a䰮fJvAzo{gcG*GCL~7bJ*ڑs+si46i!C212w`I|4O{J5|Bv6V ߜat5z,@uK&+jNR:*
.h	$8beи1O)o|/i@\/eSh6;#~f?Rdk%vW
ՑvjX8Z<7^0ϙL(b4*ޙtoS6U:yUωFo3ZwuFuߓkhJi<뚺gcY{q/3yά5N:~*ŸucoiC#uudz<JRedi汱<
jM7i@t-aΑ^w|ϺZ[
W
تW^(-Lb2#*VUm]=սŲ|QyGYa$zg;m~DoPЫίD-BA)MreGxK{ko[@x^Ŀ%ᵘ9#3˴{ )hcBIDS@<@Q PHnM I`⤺]/Ub#*!+fHIL6TԦH'M"zx^G7NLƛ'w^Nו}~/@N'AneIBGƓÁ.{6?>A26V}ҹA8sn
- BI-2p/4_S=03o&\(Irpf@9J|Wwoj{!f%ge"ԲKVPs+jzʤ&YV iִPOq\p=bc3I46L[h[# Ni;x, P*9;?*)CB?4%}	sYMM#s8YŮEWN᠉7}#[ZXFI4>h'@u -lh1-  uG  wT  	hanlock.c# 9mf&ë^{_߿ﺵ^khpS̗ğu ob'ΖV9Cqk!dDAo"E޽,B~mcJvvn[666533%!N`AQ Nfq	
 fJXw_g"LS?h}:e*`ȿ_fЦ7}Tk	1)<®]=C?]v N;#2umg~%Л{wWv^]isO׍wtI(_r(hRv(H%]8Drnk}	6T)0Z#5^xЖaeU
éz'ۄEɪcσ~H5 DJ*vXyIcXIec+65eӣb? 7@?`RROdURxrqΟ؟yvc#ʆF.@z&8=qxg]
@&-t~)L/C3q}ڙ=*}ɾ7ޗ2wOksKW7!#C>>~KO]ff;bU\^[b'e1ޢ6|Y~}Kme!uWWsV98>ajH-C~v2ՉvҐ+Y.񠤗*l2n92ԠJq#~~kv'E/#{|^:mtWK}dRY5liOixD޺-to{}{<:o_2o((^ŕ,>aꩃ-{YaKYKTIr쾈 3fI[cc|"QݾDŰ!),KƣMHPzNb빮6"n5N%ߑMr4+6b^_-G'fQ^NJV=..mKܑ*,:&x|6Oh!!rUpJot2Re`~&&K[Y.j`ӾŁ7AaZ[fu>X2*׫Gӑ{G<wNw$xTcE>mDP]LH\2Fijd
]0i|0uo CF'ݿph݇]pݣ]gҲk2oe}-N'ʽbs	a'횔{`ajǄd٧*^"?'g9*7K־1{\/qp3
|l=	H#ݮ2dAx%NksUCzVmP9ޗ/C~"杵N?LOҳ8Gz;eF7㣢.1ёnp	kMN
}ĺק-:KobGig}WTC[ ;8/&CTQ>>^A	/ZOMx.ghXADLj5ݗj
>2/=M([
=xHJ'jST
8\^HbD7zI=kd좏ZVR#X	{f4Pr=2}H2nF2D-fSKaغ.:v lv2eVN̙>)fftg9)AaߏSr=.ٵ_yFi'oc~QLWr3Aׄ1Og38swAxjNk*2ӷlj"~owWtw:^Df!\+1C$2;Р(hP<Vq׵`]h_{<~ӯj0/q6} 7-x)+xKꥭDLOJ7NHI1:eUkW7C%r]fo5Q!GV',}xs)0&\wZn2~]%bg^{YZEߦ?	׃;E=wf:}" 1&rD׏O71!,wqu]G\ͥJEEO|w(~W7>F/Z[wt=X'CΖa8a}l{9.4/NHem',!˖cVQx6{^n2[[;ҢeYm cQMnc^wO&+ԋOΓRIzYUڬ3>ǨY1 HPX?8~1?Ψ氿E*y)A&LG҈UH4U/]xq-4ytX
bx+ɲbK#GvKZ Z+w慱NURDSʗRm4z6Z?r{^D[@tXD*)ȝ\c#l8e|+!eO5~4??쵣S*	J70=9:	~ϐйz۴ޠz+1TF^+pGz.&pU?'qsrN]vߑ0
X14?w3B"\(##_%ol7m%qJ-~x(+Z-\Iթ!Sh#;|rsBnskО^sw$^g'i}gaؔELZkSJ̽Zb.}'
2Zekf-OqnW)@q%<0`x:Ҡ!c^aEӓ>XVg1c},1?]#/hW;2Ab~$LwA簶GpXX&x>!f^/7-|}@Cs#?醳aި"_D&jzBubڶ`DVєjQEok؋ {r KuZw)Zۏ׮gƬ-IHe!-na3#D-^qd.+DeV=bw[NiNRmq6Û+x;z\UՍX%բ^Tsx-,"|zF5ȉAÐاGBReq.io_Command = ETD_UPDATE;

    return MyDoIO(req);
}
#endif

int
MyDoIO(ioreq)
register struct IOStdReq *ioreq;
{
    ioreq->io_Flags |= IOF_QUICK;	/* Preserve IOMDF_40TRACKS */
    BeginIO(ioreq);
    return WaitIO(ioreq);
}
