*-----------------------------------------------------------
Title[DiskBootTransfer.mc...June 29, 1982  1:41 PM...Taft];
* Simple disk driver for transfers between Pilot boot files and memory,
* using the PilotDisk microcode.
*-----------------------------------------------------------

* Microcode and germ files are kept in Pilot boot files.
* These are standard Pilot files, with the addition that wherever there
* is a break in the run of pages, the bootChainLink of the last page
* of the run points to the first page of the next run.  Additionally,
* the file ends with a bootChainLink of [-1, -1].


Set[XTask, IP[EMU]];
KnowRBase[AEmRegs];

*-----------------------------------------------------------
BootTransfer:	* Transfer page(s) to or from disk boot file
* Enter: IOCB points to I/O command block, which must be at an odd address
*	and have the following fields already set up as desired:
*	   drive, pageCount, command, diskAddress, dataPtr, diskLabel
*	The remainder of the IOCB must be zeroed.
* Call by SCall[BootTransfer]
* Returns +1: unrecoverable error occurred
*	+2: transfer completed successfully:
*	   if IOCB.count = 0 then all pages have been transferred.
*	   if #0, end-of-file was reached before the end of the transfer.
* The command block is updated in the standard manner by the disk microcode;
* specifically, the diskAddress and diskLabel.filePageLo are updated
* to describe the first page not (successfully) transferred, as is
* the dataPtr if incrementDataPtr was specified in the command.
* If the label was checked, the diskLabel.bootChainLink contains the
* corresponding data from the last label successfully checked.
* Clobbers T, Q, BTemp0, BTemp1
*-----------------------------------------------------------
Subroutine;

	T← (IOCB)+(IOCB.headerPtr);
	BTemp0← T-(Sub[IOCB.headerPtr!, IOCB.diskHeader!]C);
	Store← T, DBuf← BTemp0;		* iocb.headerPtr ← @iocb.diskHeader
	T← (IOCB)+(IOCB.labelPtr);
	BTemp0← T+(Sub[IOCB.diskLabel!, IOCB.labelPtr!]C);
	Store← T, DBuf← BTemp0;		* iocb.labelPtr ← @iocb.diskLabel
	BTemp1← 17C;			* Max number of retries

* BootTransfer (cont'd)

BootTransferLp:
	T← IOCB, RBase← RBase[RTC430];
	EventTemp1← T← (Store← T)+1, DBuf← 0C; * iocb.next ← 0
	EventTemp0← (Store← T)-1, DBuf← IOCBSealValue; * iocb.seal ← IOCBSealValue
	Fetch← EventTemp1, T← CSB.next;	* MD← 0 for first iteration of wait loop
	PD← Store← T, DBuf← EventTemp0;	* csb.next ← iocb -- start the command.
					* ALU<0 for first iteration of wait loop

* Wait up to 2 seconds for the command to execute (sufficient time for transferring
* ~3500 pages, minus time lost to seeks).
	T← (RTC430)+1, FreezeBC;	* Now + 65536 32-us ticks = ~ 2 seconds
	Fetch← EventTemp1, PD← MD,	* Wait for iocb.seal to become zero
		Branch[BootTransferTimeout, ALU>=0];
	PD← (RTC430)-T-1, Branch[.-1, ALU#0];
	RBase← RBase[AEmRegs];

* Command finished.  iocb.pageCount=0 means completed OK, #0 means an error occurred
	T← (IOCB)+(IOCB.pageCount);
	T← (Fetch← T)+(Sub[IOCB.labelStatus!, IOCB.pageCount!]C); * Carry← 0
	Fetch← T, PD← MD;
	BTemp0← A0, Branch[BootTransferDone, ALU=0];

* Error occurred.  See if it was a label check error.
	T← DPF[BTemp0, 2, 4, MD];	* Mask out readOnly and cylOffset from status
	PD← T XOR (DS.checkErr);	* Label check error and no others?
	T← (IOCB)+(Add[IOCB.diskLabel!, Lab.bootChainLink!]C),
		Branch[BootOtherError, ALU#0];

* Label check error.  If the bootChainLink of the last successfully-read label
* is nonzero, it is the disk address of a new run of pages (-1 => end of file).
	T← (Fetch← T)+1;
	T← (Fetch← T)-1, BTemp0← MD, Q← MD;
	PD← (BTemp0) OR MD;
	BTemp0← (BTemp0)+1, Branch[BootLabelError, ALU=0];

* Start new run of pages; and zero the bootChainLink so that if it was wrong
* the ensuing label check error won't cause us to come back here.
* iocb.diskAddress ← iocb.diskLabel.bootChainLink; iocb.diskLabel.bootChainLink ← [0, 0]
	T← (Store← T)+1, DBuf← 0C, Branch[BootEOF, ALU=0]; * Carry← 0
	Store← T, DBuf← 0C;
	T← (IOCB)+(IOCB.diskAddress);
	T← (Store← T)+1, DBuf← Q, BTemp0← MD;
	Store← T, DBuf← BTemp0, Branch[BootTransferLp];

* Other error, retry.
BootOtherError:
	PD← (BTemp1) AND (7C), Branch[BootDiskError, R<0];
	BTemp1← (BTemp1)-1, Branch[BootTransferLp, ALU#0];
	T← CSB.cylinder;		* Every 8 retries, do a restore
	Store← T, DBuf← -1C, Branch[BootTransferLp];

BootTransferTimeout:
	RBase← RBase[AEmRegs];		* Timed out (disk probably not on-line)
BootDiskError:
	BTemp0← T-T, Branch[BootEOF];	* Too many retries; Carry← 1
BootLabelError:
	BTemp0← T-T, Branch[BootEOF];	* Label error not due to hitting end of run

* On exit, failure is indicated by carry=1, success by carry=0.
* BTemp0 = 0; T = @CSB.next (or pointer to some place that's harmless to store 0 into).
BootEOF:
	T← CSB.next;
BootTransferDone:
	Store← T, DBuf← BTemp0,		* Zap command chain
		Return[Carry'];		* Return +1 if carry=1, +2 if carry=0