/*      FILE HANDLER INITIALISATION

        Allocates and initialises the cache.
        Initialises various globals.
*/


SECTION "STARTING"


GET "LIBHDR"

GET "FH2HDR"

GET "MANHDR"

GET "IOHDR"

LET Starting(StartUpPacket) = VALOF
$( LET Succeeded = TRUE
   LET RestartTaskId = ?
   LET N.CacheSlots, RestartSeg = ?, ?
   LET SegList = VEC 3

   // Check that PACKET is a start-up packet
   UNLESS StartUpPacket!Pkt.Type=0 &
          StartUpPacket!Pkt.Arg1=Action.StartUp DO
          $( ReturnPkt(StartUpPacket, 0, Error.ActionNotKnown)
             CoWait(StackBase)
          $)

   || copy console environment
   initio()
   consoletask := rootnode ! rtn.tasktab ! [startuppacket!pkt.id] !
                  tcb.gbase ! [@consoletask-@globsize]

   // Extract info from the start-up packet
   DeviceId := StartUpPacket!Pkt.Arg2
   UnitNo   := StartUpPacket!Pkt.Arg3
   N.CacheSlots := StartUpPacket!Pkt.Arg4
   initialise.environment(startuppacket!pkt.arg5)
   writeprotect := startuppacket!pkt.arg6

   // Check for a valid no. of cache slots
   UNLESS 2<=N.CacheSlots<=20 DO N.CacheSlots := 10

   // Allocate the cache vector
   Cache := GetVec(N.CacheSlots)
   IF Cache=0 DO
   $( ReturnPkt(StartUpPacket, 0, Result2)
      Stop(Result2)
   $)
   !Cache := N.CacheSlots

   // Allocate cache slots
   FOR i = 1 TO N.CacheSlots DO
   $( Cache!i := GetVec(Size.Block+Size.CachePrefix)+
              Size.CachePrefix
      IF Cache!i=Size.CachePrefix DO Succeeded := FALSE
   $)

   // Check allocation of cache slots was successful
   UNLESS Succeeded DO
   $( FOR i = 1 TO N.CacheSlots DO
           FreeVec(Cache!i-Size.CachePrefix)
      FreeVec(Cache)
      ReturnPkt(StartUpPacket, 0, Error.GetVecFailure)
      Stop(Error.GetVecFailure)
   $)

   /***********************/
   // Initialise the cache
   FOR i = 1 TO N.CacheSlots DO Set.Vec(Cache!i-3, 3, 0, 0, 0)

   // Load the restart segment
   RestartTaskId := 5
   UNLESS TaskId=Task.FileHandler | writeprotect DO
   $( RestartSeg := LoadSeg("SYS:L.FILE-HANDLER-RESTART")
      IF RestartSeg=0 DO
           Abort(Abort.LoadSegFailure)

      SegList!0 := 3       // Seglist length
      SegList!1 := RootNode!Rtn.TaskTab!Task.FileHandler!Tcb.SegList!1
      SegList!2 := RootNode!Rtn.TaskTab!Task.FileHandler!Tcb.SegList!2
      SegList!3 := RestartSeg

      FOR Priority = 500 TO 1000 DO
      $( RestartTaskId := CreateTask(SegList, 300, Priority)
         UNLESS RestartTaskId=0 BREAK
      $)
      IF RestartTaskId=0 DO
           Abort(Abort.CreateTaskFailure)
   $)

   || tickle drive
   seek(2)
   seek(-80)

   || output "mounting" message
   device(act.read, rootkey, cache!1)
        || read root
   selectoutput(findoutput["**"])
   writef("****** Mounting *"%S*" for %S on unit %N*N",
          cache!1+b.file.filename,
          writeprotect -> "reading", "updating",
          unitno)
   endwrite()

   // conditionally initiate restart
   UNLESS writeprotect DO SendPkt(-1, RestartTaskId, ?, ?, ?,
           DeviceId, UnitNo, TaskId, ?, startuppacket!pkt.arg5)

   // Return the start up packet as all dynamic
   // allocation has been done successfully
   ReturnPkt(StartUpPacket, TRUE)

   /***********************/
   // Initialise the cache
   || FOR i = 1 TO N.CacheSlots DO Set.Vec(Cache!i-3, 3, 0, 0, 0)

   // Initialise various globals
   Packet.Queue := 0
   Lock.Queue := 0
   Map := 0
   bitmap.checked := FALSE
   Access.Idle := TRUE
   Work.Idle   := TRUE
   $( LET fh.tcb = rootnode!rtn.tasktab!task.filehandler
      LET fh.code = fh.tcb!tcb.seglist!3
      LET this.code = tcb!tcb.seglist!3
      handler.segment := fh.code=this.code -> 0,
                                              this.code
   $)

   // Create coroutines:
   Main.Co   := CreateCo(Main, 100)
   Work.Co   := CreateCo(Work, 200)
   Access.Co := CreateCo(Access, 100)
   Access.Action := Action.Nil

   // Make SENDPKT multi-event
   OldPktWait := PktWait
   PktWait := FHPktWait

   // Start the MAIN coroutine
   result2 := tcb!tcb.seglist!4
   ResumeCo(Main.Co, StackBase)
$)