// BFS.D -- Basic File System for Diablo disk controller
// 	Origial design by Butler Lampson
// 	Elaborated by Bob Sproull, David Boggs, and Ed Taft
// Copyright Xerox Corporation 1979
// Last modified September 12, 1979  2:43 AM by Boggs

// Must be preceded by:
// get "AltoFileSys.d"
// get "Disks.d"

manifest
[
// Shape of a Diablo disk
BFSmNDisks = 1
BFS31NTracks = 203
BFS44NTracks = 406
BFSmNHeads = 2
BFSmNSectors = 12

BFSlnWordsPerPage = 8
BFSwordsPerPage = 256
BFSmaxDDPage = 17	// 1 for the KDH + 16 for the bit table

// Defined in AltoDefs.d:
// diskCommand = 521b
// diskStatus = 522b
// diskAddress = 523b
]

// used by Assign/ReleaseDiskPage to compute bit locations
//----------------------------------------------------------------------------
structure VDA:
//----------------------------------------------------------------------------
[
wordNum bit 12 =	// word index in whole file
   [
   pageNum bit 12-BFSlnWordsPerPage
   wordNumInPage bit BFSlnWordsPerPage
   ]
bitNum bit 4		// bit index
]

// Operations on a Disk Descriptor Manager (DDMgr) object.
// See BFSDDMgr.bcpl for details.
//----------------------------------------------------------------------------
structure DDMgrOperations:
//----------------------------------------------------------------------------
[
OpenDD word		// Call0
LockDD word		// Call1
ReadDDPage word		// Call2
UnlockDD word		// Call3
FlushDD word		// Call4
CloseDD word		// Call5
DestroyDDMgr word	// Call6
]

//----------------------------------------------------------------------------
structure DST:		// Disk Status.  See Alto Hardware Manual
//----------------------------------------------------------------------------
[
sector bit 4
done bit 4
seekFail bit
seeking bit
notReady bit
dataLate bit
noTransfer bit
checksumError bit
finalStatus bit 2
]

manifest
[
// disk status bits
done = 7400B
seekFail = 200B
seeking = 100B
notReady = 40B
dataLate = 20B
noTransfer = 10B
checksumError = 4

// final status values
badSector = 3
checkError = 2
hardwareError = 1
// goodStatus = 0

DSTdoneBits = done
DSTerrorBits = seekFail + notReady + dataLate + checksumError + badSector
DSTgoodStatusMask = DSTerrorBits % DSTdoneBits
DSTgoodStatus = done
DSTfreeStatus = 400B
DSTfakeError = done + dataLate
]

// Header, Label, and Data formats on disk

//----------------------------------------------------------------------------
structure DA:		// Disk Address (real)
//----------------------------------------------------------------------------
[
sector bit 4
track bit 9		// misnamed.  really cylinder address
head bit 1
disk bit 1
restore bit 1
]

//----------------------------------------------------------------------------
structure DH:		// Disk Header
//----------------------------------------------------------------------------
[
packID word		// must be 0
diskAddress @DA
]

//----------------------------------------------------------------------------
structure FID:		// File Identifier (used only on a disk label)
//----------------------------------------------------------------------------
[
version word
serialNumber @SN
]
manifest lFID = size FID/16

//----------------------------------------------------------------------------
structure DL:		// Disk Label. *=set by DoDiskCommand
//----------------------------------------------------------------------------
[
next word		// disk address of next file page, or eofDA
previous word		// disk address of previous file page, or eofDA
blank word
numChars word		// between 0 and charsPerPage inclusive.
			// ne charsPerPage only on last page
pageNumber word		// * leader is page 0, first data page is page 1
fileId @FID		// *
]
manifest lDL = size DL/16

// Note: the big disks on D0 and Dorado are partitioned into a number
// of simulated Diablo disks.  The partitions are numbered 1 through 7;
// partition 0 refers to the current "default" partition known about
// by the microcode.  A BFSDSK object for a particular partition may
// be constructed by passing the partition number embedded in the
// driveNumber argument of BFSInit or BFSNewDisk.  The partition is
// passed to the microcode embedded in the command block seal.

//----------------------------------------------------------------------------
structure DriveNumber:	// interpretation of BFSDSK.driveNumber cell
//----------------------------------------------------------------------------
[
blank bit 12
partition bit 3
drive bit 1
]

//----------------------------------------------------------------------------
structure DC:		// disk command
//----------------------------------------------------------------------------
[
seal bit 8 =		// must be 110B on an Alto
   [			// for simulated multiple disks on D0 and Dorado:
   shortSeal bit 5	// must be 11B
   partition bit 3	// 0: default; 1-7: specific partition number
   ]
action bit 8 =
   [
   headerAction bit 2
   labelAction bit 2
   dataAction bit 2
   seekOnly bit 1
   exchangeDisks bit 1	// controller inverts KCB.diskAddress if set
   ]
]

manifest
[
// disk commands as full-word constants
commandSeal = 44000B

readHLD = 44000B	// Read  Header, Read  Label, Read  Data
readLD = 44100B		// Check Header, Read  Label, Read  Data
readD = 44120B		// Check Header, Check Label, Read  Data
writeHLD = 44250B	// Write Header, Write Label, Write Data
writeLD = 44150B	// Check Header, Write Label, Write Data
writeD = 44130B		// Check Header, Check Label, Write Data
seekOnly = 44002B	// no transfer
]

// disk command block.
//	*=set by DoDiskCommand,
//	$=defaulted by DoDiskCommand if 0
//----------------------------------------------------------------------------
structure KCB:
//----------------------------------------------------------------------------
[
link word		// * -> next KCB or 0 if end of chain
status @DST		// set when command is completed
command @DC		// *
headerAddress word	// * memory addresses for header record
labelAddress word	// $ memory addresses for header record
dataAddress word	// * memory addresses for header record
normalWakeups word	// $
errorWakeups word	// $
header @DH =
   [
   blank word
   diskAddress @DA	// * if DA argument ne fillInDA
   ]
]
manifest lKCB = size KCB/16

// BFS specialization of the Disk CBZ
//----------------------------------------------------------------------------
structure BFSCBZ:
//----------------------------------------------------------------------------
[
@CBZ			// standard part
CBs word 0		// * as many CBs as will fit start here
]
manifest lBFSCBZ = size BFSCBZ/16	// fixed part of CBZ

// each CBZ contains a CB for each possible transfer enqueued
// the KCB must come first followed by the label (for chaining)
// a free CB must have status = DSTfreeStatus (initialization does that)
// *=initialized by InitializeCbStorage; everything else is zeroed
//----------------------------------------------------------------------------
structure CB:
//----------------------------------------------------------------------------
[
// The KCB must come first
@KCB			// * free CB must have status = DSTgoodStatus
label @DL
truePageNumber word
// remaining words are not zeroed by BfsGetCb
cbz word		// * -> CBZ which owns this cb
nextCB word		// * -> next CB on CBZ queue
]
manifest
[
lCB = size CB/16
lVarCB = offset CB.cbz/16
CBzoneLength = lBFSCBZ+3*lCB	//3 CBs required to run disk at full speed
]

//---------------------------------------------------------------------------
structure BFSDSK:	// Extended version of the DSK structure
//---------------------------------------------------------------------------
[
@DSK			// standard -- see Disks.d
@KDH			// standard -- see AltoFileSys.d
initmode word		// nonzero if permitted to create/delete files
zone word		// zone from which this DSK was allocated
ddMgr word		// -> disk descriptor manager
lastPageAlloc word	// last VDA allocated -- for biasing search
fpBFSSysDirblk word lFP	// storage for FP
fpBFSDDblk word lFP	// storage for FP
fpBFSWDblk word lFP	// storage for FP
WDNameblk word maxLengthFnInWords  // storage for workingDir name
VDAdiskDD↑1,BFSmaxDDPage word	// VDAs of the data part of DD
]
manifest lBFSDSK = size BFSDSK/16

// 'DiskDescriptor' contains a KDH (16 words) followed by a variable
// number of pages containing the bit table.  The number of valid
// words in the bit table is given in KDH.diskBTsize.

manifest
[
// Used by Assign/ReleaseDiskPage to skip over the KDH which
// comes before the bit table in the DiskDescriptor file.
bitTableBias = lKDHeader lshift 4

// Error codes registered in Sys.errors:
ecUnRecovDiskError = 1101
ecDiskFull = 1102
ecBadAction = 1103
ecBfsQueue = 1104
ecNoCreationAbility = 1105
ecEssentialFile = 1106
ecBadAssignPage = 1107
ecBadBtPage = 1108
]