//tspdos.bcpl Tape Server Do* command procedures // g. krasner November 19, 1979 // Last modified by Tim Diebert, October 10, 1980 11:00 AM // get "Tapes.d" get "PUP.decl" get "TSP.decl" //--------------------------------------------------------------- external //--------------------------------------------------------------- [ //Imports //From Tapes OpenTape; CloseTape; TapeRewind; TapeUnload; TapeEOF TapeStatus; ActOnTape; PerformVTCB FileSkipFwd; FileSkipRev; RecSkipFwd; RecSkipRev; EraseInches //From 'System' Ws; Wo; Endofs; keys; Block; Gets; CallSwat //From BSP BSPWriteBlock; BSPForceOutput //Imported Globals rwBlock; rwKey; kbdKey; usedidnos; useddrives; ctxQ currentVersionString //Exports (to TSPServer) ReplyNo; ReplyYes DoOpenDrive; DoCloseDrive; DoReadRecord; DoWriteRecord DoFwdSpaceRecord; DoBackSpaceRecord; DoFwdSpaceFile DoBackSpaceFile; DoWriteEOF; DoWriteBlankTape DoRewind; DoUnload; DoGetStatus; DoSetStatus DoSendText; DoGetText ] // Command Processors: Do*() //These routines handle the processing for a received command. Most //verify that there is a drive open (Service.drives = -1). //Error recovery and Replying are all done at this level. //--------------------------------------------------------------- let DoOpenDrive(ser) be //--------------------------------------------------------------- [ let blk = ser>>Service.blk // process the OpenDrive command, opening the given drive if allowed. test ser>>Service.drive ge 0 ifso //this Server has a drive open already ReplyNo(ser,openAlready) ifnot [ let dr = blk>>OpenDrive.driveNumber test dr ls maxDrives ifnot ReplyNo(ser,badDriveNo) ifso test useddrives!dr ifso ReplyNo(ser,driveInUse) ifnot [ let tape = OpenTape(dr,ser>>Service.speed,DoErrorProc) test tape ifnot ReplyNo(ser,badDrive) ifso [ //All went well!! ser>>Service.tape = tape ser>>Service.drive = dr useddrives!dr = true ReplyYes(ser,cmdOpenDrive) ] ] ] ] //--------------------------------------------------------------- and DoCloseDrive(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then //drive is open, close it [ let dr = ser>>Service.drive useddrives!dr = false CloseTape(ser>>Service.tape) ser>>Service.tape = false ser>>Service.drive = -1 ReplyYes(ser,cmdCloseDrive) ] ] //--------------------------------------------------------------- and DoReadRecord(ser) be //--------------------------------------------------------------- [ //Read a record from tape if VerifyOpen(ser) then [ //Do read, and return status as well let blk = ser>>Service.blk //get command block let count = ActOnTape(ser>>Service.tape,ReadTape,lv blk>>HereIsRecord.record,rwBlockLength,0,0,ser>>Service.retries) if count le 0 then count = 0 if count gr rwBlockLength-24 then count = rwBlockLength-24 //truncate to fit blk>>HereIsRecord.recordLength = count blk>>HereIsRecord.endingStatus = (ser>>Service.tape)>>TCB.Flags blk>>HereIsRecord.type = cmdHereIsRecord blk>>HereIsRecord.length = 4+(count+1)/2 count = 2 * blk>>HereIsRecord.length BSPWriteBlock(ser>>Service.bspStr,blk,0,count) BSPForceOutput(ser>>Service.bspSoc) ] ] //--------------------------------------------------------------- and DoWriteRecord(ser) be //--------------------------------------------------------------- [ //Write a record to tape if VerifyOpen(ser) then if OkToWrite(ser) then [ let blk = ser>>Service.blk if blk>>WriteRecord.recordLength gr rwBlockLength-24 then blk>>WriteRecord.recordLength = rwBlockLength-24 ActOnTape(ser>>Service.tape,WriteTape,0,0,lv blk>>WriteRecord.record,blk>>WriteRecord.recordLength,ser>>Service.retries) ReplyStatus(ser,cmdWriteRecord) ] ] //--------------------------------------------------------------- and DoFwdSpaceRecord(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ RecSkipFwd(ser>>Service.tape) //Space Forward ReplyStatus(ser,cmdFwdSpaceRecord) //reply with ending status ] ] //--------------------------------------------------------------- and DoBackSpaceRecord(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ RecSkipRev(ser>>Service.tape) //Space Back ReplyStatus(ser,cmdBackSpaceRecord) //reply with ending status ] ] //--------------------------------------------------------------- and DoFwdSpaceFile(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ FileSkipFwd(ser>>Service.tape) //Skip File Forward ReplyStatus(ser,cmdFwdSpaceFile) //reply with ending status ] ] //--------------------------------------------------------------- and DoBackSpaceFile(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ FileSkipRev(ser>>Service.tape) //Skip File Backward ReplyStatus(ser,cmdBackSpaceFile) //reply with ending status ] ] //--------------------------------------------------------------- and DoWriteEOF(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then if OkToWrite(ser) then [ TapeEOF(ser>>Service.tape) //Write an EOF ReplyStatus(ser,cmdWriteEOF) //reply with ending status ] ] //--------------------------------------------------------------- and DoWriteBlankTape(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then if OkToWrite(ser) then [ let blk = ser>>Service.blk let inches = blk>>WriteBlankTape.gap //get gap size EraseInches(ser>>Service.tape,inches) //Write inches of blank tape ReplyStatus(ser,cmdWriteBlankTape) //reply with ending status ] ] //--------------------------------------------------------------- and DoRewind(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ PerformVTCB(ser>>Service.tape, Rewind) //initiate rewind ReplyYes(ser,cmdRewind) //reply before rewind complete ] ] //--------------------------------------------------------------- and DoUnload(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ PerformVTCB(ser>>Service.tape, Unload) //initiate Unload ReplyYes(ser,cmdUnload) //reply before rewind complete ] ] //--------------------------------------------------------------- and DoGetStatus(ser) be //--------------------------------------------------------------- [ let blk = ser>>Service.blk let tape = ser>>Service.tape blk>>HereIsStatus.length = 6 blk>>HereIsStatus.type = cmdHereIsStatus blk>>HereIsStatus.drive = ser>>Service.drive blk>>HereIsStatus.retries = ser>>Service.retries blk>>HereIsStatus.speed = ser>>Service.speed if ser>>Service.drive ge 0 then //open tape [ blk>>HereIsStatus.tstatus = TapeStatus(tape) ] //Send message BSPWriteBlock(ser>>Service.bspStr,blk,0,12) BSPForceOutput(ser>>Service.bspSoc) ] //--------------------------------------------------------------- and DoSetStatus(ser) be //--------------------------------------------------------------- [ let blk = ser>>Service.blk let which = blk>>SetStatus.selector //get selector let set = blk>>SetStatus.newsetting switchon which into [ case setRetries: [ test (set ge 0 & set le 8) ifso [ ser>>Service.retries = set ReplyYes(ser,cmdSetStatus) ] ifnot ReplyNo(ser,badRetrySetting) endcase ] case setSpeed: [ test ser>>Service.drive ls 0 //only set speed if not open ifso [ switchon set into [ case 0: ser>>Service.speed = IPS45; ReplyYes(ser,cmdSetStatus); endcase case 1: ser>>Service.speed = IPS125; ReplyYes(ser,cmdSetStatus); endcase default: ReplyNo(ser,badSpeedSetting); endcase ] ] ifnot ReplyNo(ser,openAlready) endcase ] default: ReplyNo(ser,badStatusSelector); endcase ] ] //--------------------------------------------------------------- and DoSendText(ser) be //--------------------------------------------------------------- [ //display text string to operator let blk = ser>>Service.blk Ws(lv blk>>SendText.text) ReplyYes(ser,cmdSendText) ] //--------------------------------------------------------------- and DoGetText(ser) be //--------------------------------------------------------------- [ //Get a line of Text from operator (terminated by cr) while kbdKey ge 0 do Block() //wait for keyboard kbdKey = ser>>Service.idnumber //take keyboard Ws("*nReply? ") //prompt let blk = ser>>Service.blk blk>>HereIsText.type = cmdHereIsText let str = lv blk>>HereIsText.text let echo = "x"; let i = 1; let chr = 0 until chr eq 13 do //until cr [ while Endofs(keys) do Block() //wait for key chr = Gets(keys) if chr eq 8 then [ if i gr 1 then [ //backspace, echo \<lastchar> and backup i i = i-1 echo>>String.char↑1 = $\;Ws(echo) echo>>String.char↑1 = str>>String.char↑i;Ws(echo) ] loop ] if i ls (cmdBlockLength-2)/2 then [ str>>String.char↑i = chr; i = i+1 echo>>String.char↑1 = chr;Ws(echo) ] ] str>>String.length = i-1 blk>>HereIsText.length = 2+(i+1)/2 //full words plus header BSPWriteBlock(ser>>Service.bspStr,blk,0,blk>>HereIsText.length*2) BSPForceOutput(ser>>Service.bspSoc) Ws("sent") kbdKey = -1 //release beyboard ] //--------------------------------------------------------------- and VerifyOpen(ser) = valof //--------------------------------------------------------------- [ if ser>>Service.drive ge 0 then resultis true ReplyNo(ser,driveNotOpened) resultis false ] //--------------------------------------------------------------- and OkToWrite(ser) = valof //--------------------------------------------------------------- [ let stat = TapeStatus(ser>>Service.tape) //tape must be open!! unless stat<<Status.FPT then resultis true ReplyNo(ser,writeProtected) resultis false ] //--------------------------------------------------------------- and ReplyYes(ser,code) be //--------------------------------------------------------------- [ //Sends back Yes reply, not switchon code for string yet let blk = ser>>Service.blk //get command block blk>>YesNo.type = cmdYes blk>>YesNo.cause = doneOperation let stat = (ser>>Service.tape)>>TCB.Flags //get tape status blk>>YesNo.code = stat let str = "Good Command" YesNoMessage(blk,str,ser) //set up string and send out ] //--------------------------------------------------------------- and ReplyNo(ser,code) be //--------------------------------------------------------------- [ //Sends back No block, with correct string let str = " " switchon code into [ case noVersion: str = "Version Check Unmade"; endcase case noGoodMessage: str = "Illegal Command"; endcase case openAlready: str = "Drive Already Open"; endcase case driveInUse: str = "Drive In Use"; endcase case badDrive: str = "Drive Bad"; endcase case badDriveNo: str = "Bad Drive Number"; endcase case driveNotOpened: str = "Drive Not Open"; endcase case badStatusSelector: str = "Cannot set that Status"; endcase case badRetrySetting: str = "Bad Setting for Retries"; endcase case writeProtected: str = "Tape Write Protected"; endcase case badSpeedSetting: str = "Illegal Speed Setting"; endcase default: str = "Illegal Command"; endcase ] let blk = ser>>Service.blk //get command block blk>>YesNo.type = cmdNo blk>>YesNo.cause = code let stat = (ser>>Service.tape)>>TCB.Flags //get tape status blk>>YesNo.code = stat YesNoMessage(blk,str,ser) //set up string and send out ] //--------------------------------------------------------------- and ReplyStatus(ser,cmd) be //--------------------------------------------------------------- [ //Send back the ending status of the tape drive // used by most action commands let blk = ser>>Service.blk let stat = (ser>>Service.tape)>>TCB.Flags //get tape status blk>>YesNo.cause = doneOperation blk>>YesNo.code = stat //return status bits blk>>YesNo.type = cmdYes //assume Yes // always no if not online or not ready or error unless stat<<Status.RDY then blk>>YesNo.type = cmdNo unless stat<<Status.ONL then blk>>YesNo.type = cmdNo let error = stat & TapeErr if error then blk>>YesNo.type = cmdNo switchon cmd into //other changes to No depend on command [ case cmdWriteRecord: [ //No if write protected if stat<<Status.FPT then blk>>YesNo.type = cmdNo endcase ] case cmdFwdSpaceRecord: [ //No special no endcase ] case cmdBackSpaceRecord: [ //No special no endcase ] case cmdFwdSpaceFile: [ //No special no endcase ] case cmdBackSpaceFile: [ //No special no endcase ] case cmdWriteEOF: [ //No if not EOF unless stat<<Status.EOF then blk>>YesNo.type = cmdNo endcase ] case cmdWriteBlankTape: [ //No special no endcase ] ] //put in string of good or bad operation let str = "Good Operation" if blk>>YesNo.type eq cmdNo then str = "Bad Ending Status" YesNoMessage(blk,str,ser) //set up string and send out ] //--------------------------------------------------------------- and YesNoMessage(blk,str,ser) be //--------------------------------------------------------------- [ let i = 0 blk>>YesNo.length = 5 + ((str>>String.length + 2) / 2) for i = 0 to blk>>YesNo.length - 4 do [ (lv blk>>YesNo.str)!i = str!i //copy string ] // and send block out BSPWriteBlock(ser>>Service.bspStr,blk,0,2*blk>>YesNo.length) BSPForceOutput(ser>>Service.bspSoc) ] //--------------------------------------------------------------- and DoErrorProc(str) be //--------------------------------------------------------------- [ Ws(str) ]