// DDTapeServerDOs.bcpl Tape Server Do* command procedures // Last modified by Tim Diebert, June 22, 1981 4:01 PM // get "DDTapes.d" get "PUP.decl" get "DDTapeServer.decl" //--------------------------------------------------------------- external //--------------------------------------------------------------- [ //Imports //From DDTapeServerDispUtil InitDisplay; DWs; DWo; MonitorKeys //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 = OpenDDTape(dr, DoErrorProc, DoErrorProc) test tape ifnot ReplyNo(ser, badDrive) ifso [ //All went well!! ser>>Service.tape = tape ser>>Service.drive = dr useddrives!dr = true ser>>Service.density = PE if tape>>VDDTCB.opDensity eq NRZI then ser>>Service.density = NRZI ReplyYes(ser, cmdOpenDrive) ] ] ] ] //--------------------------------------------------------------- and DoCloseDrive(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then //drive is open, close it [ let dr = ser>>Service.drive useddrives!dr = false CloseDDTape(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 ActOnDDTape(ser>>Service.tape, ReadFwd, lv blk>>HereIsRecord.record, rwBlockLength, 0, 0, ser>>Service.retries) let count = (ser>>Service.tape)>>DDTCB.ByteCount if count gr rwBlockLength then count = rwBlockLength //truncate to fit blk>>HereIsRecord.recordLength = (ser>>Service.tape)>>DDTCB.ByteCount blk>>HereIsRecord.endingStatus = (ser>>Service.tape)>>DDTCB.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 then blk>>WriteRecord.recordLength = rwBlockLength ActOnDDTape(ser>>Service.tape, Write, 0, 0, lv blk>>WriteRecord.record, blk>>WriteRecord.recordLength, ser>>Service.retries) ReplyStatus(ser, cmdWriteRecord) ] ] //--------------------------------------------------------------- and DoFwdSpaceRecord(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ ActOnDDTape(ser>>Service.tape, FwdSpaceRecord) ReplyStatus(ser, cmdFwdSpaceRecord) //reply with ending status ] ] //--------------------------------------------------------------- and DoBackSpaceRecord(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ ActOnDDTape(ser>>Service.tape, BackSpaceRecord) ReplyStatus(ser, cmdBackSpaceRecord) //reply with ending status ] ] //--------------------------------------------------------------- and DoFwdSpaceFile(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ ActOnDDTape(ser>>Service.tape, FwdSpaceFile) ReplyStatus(ser, cmdFwdSpaceFile) //reply with ending status ] ] //--------------------------------------------------------------- and DoBackSpaceFile(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ ActOnDDTape(ser>>Service.tape, BackSpaceFile) ReplyStatus(ser, cmdBackSpaceFile) //reply with ending status ] ] //--------------------------------------------------------------- and DoWriteEOF(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then if OkToWrite(ser) then [ ActOnDDTape(ser>>Service.tape, WriteEOF) //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 let vtape = ser>>Service.tape //get ptr to TCB let gapsize = 960 //number of bytes in PE gap. if vtape>>VDDTCB.opDensity eq NRZI then gapsize = 480 //number of bytes in NRZI gap. let bytes = (inches * vtape>>VDDTCB.opDensity) - gapsize //get gap size if bytes le 0 then bytes = 1 ActOnDDTape(vtape, EraseVar, bytes) //Write inches of blank tape ReplyStatus(ser, cmdWriteBlankTape) //reply with ending status ] ] //--------------------------------------------------------------- and DoRewind(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ PerformVDDTCB(ser>>Service.tape, Rewind) //initiate rewind ReplyYes(ser, cmdRewind) //reply before rewind complete ] ] //--------------------------------------------------------------- and DoUnload(ser) be //--------------------------------------------------------------- [ if VerifyOpen(ser) then [ PerformVDDTCB(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.density = ser>>Service.density if ser>>Service.drive ge 0 then //open tape [ blk>>HereIsStatus.tstatus = PerformVDDTCB(tape, NoOp) ] //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 setDensity: [ test (set eq PE % set eq NRZI) ifso [ ser>>Service.density = set let ok = SetDensity(ser>>Service.tape, set) test ok ifso [ ReplyYes(ser, cmdSetStatus) ser>>Service.density = set ] ifnot ReplyNo(ser, DensitySetNotatBOT) ] ifnot ReplyNo(ser, badDensitySetting) endcase ] default: ReplyNo(ser, badStatusSelector); endcase ] ] //--------------------------------------------------------------- and DoSendText(ser) be //--------------------------------------------------------------- [ //display text string to operator let blk = ser>>Service.blk DWs(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 DWs("*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 = $\ DWs(echo) echo>>String.char↑1 = str>>String.char↑i DWs(echo) ] loop ] if i ls (cmdBlockLength-2)/2 then [ str>>String.char↑i = chr i = i+1 echo>>String.char↑1 = chr DWs(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) DWs("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 = PerformVDDTCB(ser>>Service.tape, NoOp) unless stat<<DDStatus.FPT then resultis true (ser>>Service.tape)>>VDDTCB.WFP = 1 // fake write error 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)>>DDTCB.Flags //get tape status blk>>YesNo.stat = 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 badDensitySetting: str = "Illegal Density Setting"; endcase case DensitySetNotatBOT: str = "Density set at place other than BOT"; 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)>>DDTCB.Flags //get tape status blk>>YesNo.stat = 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)>>DDTCB.Flags //get tape status blk>>YesNo.cause = doneOperation blk>>YesNo.stat = stat //return status bits blk>>YesNo.type = cmdYes //assume Yes // always no if not online or not ready or error unless stat<<DDStatus.RDY then blk>>YesNo.type = cmdNo unless stat<<DDStatus.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<<DDStatus.FPT then blk>>YesNo.type = cmdNo if stat<<DDStatus.HE % stat<<DDStatus.SE % stat<<DDStatus.HDWERR % stat<<DDStatus.RDP % stat<<DDStatus.DL 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<<DDStatus.FMK 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 //--------------------------------------------------------------- [ DWs(str) ]