.Title DUC - Internally-Queueing DU Handler for RT/TSX .enabl lc .dsabl gbl .nlist bex .mcall .module,.drdef,.br,.assume,.addr,.fork,.mtps,.mfps,.print,.inten,.ttyou .module du,release=V05,version=111,audit=yes .psect dudvr .psect junk .psect duboot .psect program .psect mesage con Vermes: .asciz /DU.SYS Internally-Queueing Multi-Unit V2 23-Sep-86/ du.ver=200 ;Version number accessible from status table. Change when ; format of SPFUN's alters. ;Author: Chester Wilson, 71 Galatea Street, Charleville 4470 ;For documentation, see DUCM.DOC .Sbttl Check for Attempted Multi-Port Assembly .if df DU$PORTS .iif ne du$ports-1, .error; DUCM provides Single-Port DU Handler Only .endc .Sbttl Variables Which the User may Re-define ; TSX$P ; ***** .iif ndf TSX$P, TSX$P=0 ;This handler runs under TSX+, as a handler mapped into high memory, if ; the variable ; TSX$P ; is defined. .if ne TSX$P .iif eq mmg$t, .error ;Must have extended memory for TSX! .endc ; $XLINK ; ****** .if eq tsx$p ;If $XLINK defined, allows cross-linking $xlink=0 ; of requests from the XX handler across .iff ; to the DU handler, using the Q$UMRX element .if ndf $xlink ; (MUST BE ON A Q-BUS SYSTEM!!!) as .byte $xlink=1 ; , ignoring tables within .endc ; the DU handler. .endc ; TS$JOB ; ****** .iif ndf ts$job, ts$job=50. ;For TSX-plus later than 6.01, may have >31 jobs. Define the maximum ; allowable, and prang him if he tries to use more. ; CSR & VECTOR ; ************ .iif ndf ducsr, ducsr=172150 .iif ndf duvec, duvec=154 ; RETRY ; ***** .iif ndf retry, retry=3 ;Who should need more with MSCP drives? .Sbttl .Sbttl UPDATE HISTORY .Sbttl -------------- .Sbttl V2 22-Sep-86 ; Put in SPFUNs 376 & 377 for RT version 5.4 or DUP dies. ; (This necessitated using q$link as a data word in active queue ; elements) .Sbttl - - - - - - - - - .Sbttl V1j 28-Jun-86 ; Use q$job as a byte not a word (my misunderstanding!) ; - wonder what they'll use the high order byte for? .Sbttl V1h 15-Jun-86 ; Code tidying ; Fixes in programme portion .Sbttl V1g 27-Apr-86 ; Change check on interrupt to check MRING+2 rather than RSPINT, ; as Peter will probably never get round to fixing that ; one, and 40 instructions delay gives me diarrhoea. ; Add hook for WA handler if DU not mapped under TSX ; Add /S to get device size by partitions .Sbttl V1f 7-Apr-86 ; Alter format of Programme section to normal CSI .Sbttl V1e 2-Apr-86 ; Add support for # jobs > 31. (add TS$JOB) .Sbttl V1d 25-Mar-86 ; Repair bug in PSZ code where returned OK on non-extant units .Sbttl V1c 16-Mar-86 ; Clear q$umrx before calling @$mpphy .Sbttl V1b 7-Mar-86 ; Fix nasty bug fix which pranged on 11/73 with odd address trap! .Sbttl V1a 1-Mar-86 ; Tidy GETPRT code ; Check partition numbers in programme portion .Sbttl X10 18-Feb-86 ; Tidy up SET area so .module can AUDIT at least once. ; Add support for TSX-plus handler cross-linkage ($XLINK) ; Tidy up serious error code (still not quite right ...) .Sbttl X9 20-Oct-85 ; Don't put SP into IP as if low byte = 250 get Wombat! .Sbttl X8 5-Oct-85 ; Bug fixes; add bad error support .Sbttl X7 28-Sep-85 ; First Multi-unit version .Sbttl .Sbttl DOCUMENTATION .Sbttl ------------- .Sbttl Use of the Q$FUNC Byte & Q$LINK Word .If eq 1 The Q$FUNC byte is set with a code representing the type of request: ****** (x.io) 0 Normal I/O (x.pio) 1 Physical I/O (not restricted to only 1 partition) (x.sio) 2 Special I/O, returning a status word as the first word in the buffer with the following values: (si.ok) 100000 success (si.bbr) 100200 bad block found (BBR set) (si.rty) 100002 error recovered after retry (si.err) 1774xx error which did not recover (x.psz) 3 Partition size SPFUN (x.usz) 4 Unit size SPFUN The Low-Order byte of Q$LINK is used for the retry count ****** The High-Order byte of Q$LINK is used for flags: ****** (x.done) 200 Message received for this element (x.error) 100 Message indicated an error occurred (x.avail) 40 Error was AVAILABLE (x.bbr) 20 Error was BBR (x.ondone) 2 An ONLINE has been performed for thie element (x.online) 1 Action required is/was an ONLINE Other words in the queue elements are used as data words for the Size SPFUNs: the unit size is placed in Q$BLKN (high-order) and Q$WCNT (low-order) for calculations to be done back at the .FORK level. .endc .Sbttl TSX-Plus Considerations .if eq 1 No SET operations may be performed under TSX-plus. These must be done under RT-11. The problem here is that TSX rewrites the first block of the handler, and this destroys internal queueing information, killing the system. Cacheing and larger discs: If a device is set to be cacheable (in TSGEN), all units of that device may be mounted and cached. For a disc which has a maximum of 8 partitions (ie up to 240 Meg) this presents no problems - indeed there should be no need to provide the ability to alter partition table values apart from using the monitor SET commands (though no doubt someone will dream up some perfectly valid reason!). If a disc has more then 8 partitions, then it is possible that two people will access the same named unit (eg DU6) but it is actually a different partition which each job is trying to access. Thus is is imperative that these units NOT be cacheable. Solution: use the companion WA handler. [You require a Q-bus system for use of this.] .endc .Sbttl Aborts .if eq 1 The ABORT entry, using the HNDLR$ bit, is not used. Even with very long queues of DU requests, the speed of the DU should be sufficient to provide clearing of requests upon abort within sufficient time to be acceptable. .endc .Sbttl SPFUNs .if eq 1 The DEC DU SPFUN's have not been implemented in the same way: - SPFUN (373) to return partition size continues unchanged. - SPFUN (371) to allow bypassing of the DU handler for directly issuing an MSCP request has NOT been implemented, for safety in a multi-user environment. [I may put this one back, as it appears as though DEC are actually going to use it, for such things as formatting. It may be reasonable to limit this to RT-11 use rather than TSX, but with removeable cartridge disc units becoming available, it may be handy under TSX.] {Looked at in more detail: bloody impossible!} - SPFUN (372) to read/write the partition table has been modified/augmented. As there was a table format change upon RT-11 vesion 5.4, the handler checks whih version of RT is being used (or which one TSX-plus appears to be) and returns or uses the relevant format of partition table. [The version from 5.4 on has an additional two words at the start: (^rDU and 8).] Under TSX-plus only units 6 and 7 may be altered by this SPFUN. Other units must be set up with SET commands under RT-11. Units 6 & 7 are different for each job number. The PORT value is always zero on a read, and is ignored on writing the table. Deleted SPFUNs: -------------- The DUCM V1 SPFUNs 361 and 362 have been removed, returning to the DEC standard 372 for partition table reading & writing. This restricts partition numbers to 8 bits. When discs get bigger I may re-think this ... Additional SPFUNs: ----------------- SP.USZ (300) returns unit size (rather than partition size) in two words in a manner analogous to SP.PSZ (373). The first word receives the high-order value of the size. SP.STS (363) has been included as a primitive form of error logging. This returns a table in the form: 1 word (du.ver) Version Number 1 word No. of init's performed successfully 1 word No. of retries performed in init'ing 1 word No. of bloody disasters (SA negative) 1 word No. of AVAIL errors 1 word No. or IO retries 1 word No. or IO errors This is included mainly for debugging, but I may leave it in. SP.PIO (301) is for physical rather than logical I/O. It allows a 24-bit block number, but only allows reading or writing whole blocks. This is done by using the Word Count word of the queue element as follows: High-order byte: number of blocks to transfer (negative if write, positive if read, zero seek [useless]); Low-order byte: high order eight bits of block address. [This byte does NOT change sign in a write!] .endc .Sbttl .Sbttl DEFINITIONS .Sbttl ----------- .Sbttl TSX Queue Element Definitions ; For use within monitor q.link ==: 0 ;Link to next queue entry q.csw ==: 2 ;Address of CSW for channel making request q.blkn ==: 4 ;Physical block number of request q.func ==: 6 ;Special function code q.unit ==: 7 ;Device unit number (bits 0 through 2) q.jnum ==: 7 ;Job number issuing request (bits 3 through 7) q.buff ==: 10 ;User buffer address relative to Q.PAR q.wcnt ==: 12 ;Word count (+ = read, 0 = seek, - = write) q.comp ==: 14 ;Address of completion routine for request q.par ==: 16 ;PAR relocation bias for buffer address q.pa5 ==: 20 ;Mapping value for kernel PAR 5 q.umrx ==: 22 ;Address of UMR block assigned for I/O q.chan ==: 24 ;User channel # associated with I/O request q.devx ==: 26 ;Device index number q.flag ==: 27 ;Device control flags q.job ==: 30 ;Number of job that is making request q.umvb ==: 31 ;Unibus UMR base register number q.umpb ==: 32 ;Original value of Q.BUFF when I/O was initiated q.umpp ==: 34 ;Original value of Q.PAR when I/O was initiated q.pa6 ==: 36 ;Mapping value for kernel PAR 6 q.ucsw ==: 40 ;Virtual address of user's channel block q.icsw ==: 42 ;Copy of user's channel block (12 bytes) ;For use within handlers q$link ==: -4 ;Link to next queue entry q$csw ==: -2 ;Address of CSW for channel making request q$blkn ==: 0 ;Physical block number of request q$func ==: 2 ;Special function code q$unit ==: 3 ;Device unit number (bits 0 through 2) q$jnum ==: 3 ;Job number issuing request (bits 3 through 7) q$buff ==: 4 ;User buffer address relative to Q$PAR q$wcnt ==: 6 ;Word count (+ = read, 0 = seek, - = write) q$comp ==: 10 ;Address of completion routine for request q$par ==: 12 ;PAR relocation bias for buffer address q$pa5 ==: 14 ;Mapping value for kernel PAR 5 q$umrx ==: 16 ;Address of UMR block assigned for I/O q$chan ==: 20 ;User channel # associated with I/O request q$devx ==: 22 ;Device index number q$flag ==: 23 ;Device control flags q$job ==: 24 ;Number of job that is making request q$umvb ==: 25 ;Unibus UMR base register number q$umpb ==: 26 ;Original value of Q$BUFF when I/O was initiated q$umpp ==: 30 ;Original value of Q$PAR when I/O was initiated q$pa6 ==: 32 ;Mapping value for kernel PAR 6 q$ucsw ==: 34 ;Virtual address of user's channel block q$icsw ==: 36 ;Copy of user's channel block (12 bytes) .Sbttl Priority Setting/Clearing Macros psw=177776 ;All good XM processors have one. .macro nointerrupts all machines .if ne MMG$T bis #340,@#psw .iff .if nb all .mtps #340 .endc .endc .endm .macro interrupts all machines .if ne MMG$T bic #340,@#psw .iff .if nb all .mtps #0 .endc .endc .endm .Sbttl Other Macros .macro jmpne loc,?label beq label jmp loc label: .endm jmpne .macro jmpeq loc,?label bne label jmp loc label: .endm jmpeq .Sbttl SPFUN Definitions ;Standard DEC DU SPFUNs SP.RIO=:377 ;Read, returning status word SP.WIO=:376 ;Write, returning status word SP.PSZ=:373 ;Return partition size SP.DAT=:372 ;Return RT-type partition table SP.BYP=:371 ;* ;Bypass handler for MSCP access - NOT IMPLEMENTED ;Additional SPFUNs SP.USZ=:300 ;Return unit size (2 words, high-order first) SP.PIO=:301 ;Physical I/O SP.RPT=:361 ;* ;Return job's partition table (16 words) - REMOVED SP.WPT=:362 ;* ;Write job's partition table - REMOVED SP.STS=:363 ;Return statistics table (8 words) .Sbttl Special I/O Flag Values si.ok=: 100000 ;Error-free return si.bbr=:100200 ;Bad block replacement flag found set on I/O si.rty=:100002 ;Error but recovered on retry si.err=:177777 ;Error which did not recover .Sbttl Definitions of Q$LINK bits x.done=: 200 ;Set after message returned for this element x.error=: 100 ;Set if error occurred x.avail=: 40 ;Set if the error was AVAILABLE x.bbr=: 20 ;Set if error was BBR x.ondone=:2 ;Set if an ONLINE has already been performed for this x.online=:1 ;Set if an ONLINE command required .Sbttl Definitions of Q$FUNC byte values x.io=:0 ;Normal I/O x.pio=:1 ;Physical I/O (spfun 301) x.sio=:2 ;Special I/O (spfuns 376,377) x.psz=:3 ;Partition Size (spfun 373) x.usz=:4 ;Unit Size (spfun 300) .assume x.io lt x.pio .assume x.pio lt x.sio .assume x.sio lt x.psz .assume x.psz lt x.usz .Sbttl Other Definitions SYSPTR=:54 ;Pointer to start of RMON DRFIN$=:270 ;Offset from start of RMON to queue element returning ; subroutine. SYSVER=:276 ;Monitor version SYSUPD=:277 ;Monitor release SYSGEN=:372 ;Sysgen features word TSX$=:100000 ;Set if running under TSX-plus P.CSIZ==:60 ;Minimum size for command buffer. P.MSIZ==:60 ;ibid, message buffer. (Global to check against ; value in MSCP.STB) .Sbttl .Sbttl SET & INSTALLATION CODE .Sbttl ----------------------- .Sbttl EMT Area for SET Code .asect .=4 barea: .byte 17,11 ;Channel 17; code for WRITE .blkw 2 .word 256. ;Word count .word 0 ;Wait for I/O completion. .Sbttl Installation Code .drdef du,50,filst$!spfun$!varsz$,0,ducsr,duvec .drins du nop tst @inscsr return noport: .asciz /?DU-E-Single Port Only/ notsx: .asciz /?DU-E-No SETs under TSX/ .even .iif gt <.-376>, .error .Sbttl Read & Write SET Blocks .asect .=70 ;These routines expect the block number in T1, and ; return R2 pointing to the second block in the USR buffer. ; Readb1 & Writb1 put 1 into R1. Otherwise registers are preserved. .Enabl lsb Readb1: mov #1,r1 Readb: movb #10,barea+1 ;Make it a READ br 10$ .=116 Writb1: mov #1,r1 Writb: movb #11,barea+1 ;Make it a WRITE 10$: mov r0,-(sp) .addr #1000,r2 .addr #barea+4,r0 mov r2,(r0) ;Buffer Address mov r1,-(r0) ;Block Number tst -(r0) ;Point R0 to start of area emt 375 ;Read or write bcc 20$ mov (sp)+,r0 ;Scrub r0, as actually want to scrub return 20$: mov (sp)+,r0 ; address [only call this 1 layer down!!!] return .Dsabl lsb .iif gt <.-170>, .error .Sbttl SET Code .drset VECTOR,1,o.vec,oct .drset CSR,1,o.csr,oct .drset PART,1,o.part,num .drset UNIT,1,o.unit,num .drset PORT,1,o.port,num o.unit: call gettab ;Get address of part/unit table mov r0,(r1) ;Put into unit word call writb1 ;Write out this block mov #bpartb/1000,r1 ;and get boot block with partition table call readb add r3,r2 ;Offset within partition table mov r0,(r2) ;Insert unit br o.w o.part: call gettab ;Get address of part/unit table mov r0,2(r1) ;Put into partition word call writb1 ;Write out this block mov #bpartb/1000,r1 ;and get boot block with partition table call readb add r3,r2 ;Offset within partition table mov r0,+2(r2) ;Insert partition br o.w o.port: .addr #noport,r0 .print br o.bad ;Give error return (in case in command file) gettab: ;Get address of partition table offset. mov @#sysptr,r3 ;First check as TSX use of SET illegal .assume tsx$ eq 100000 tst sysgen(r3) bpl 10$ tst (sp)+ ;If under TSX-plus, die. .addr #notsx,r0 .print br o.bad 10$: asl r1 ;Device number (DU0,1,2,3,4,5,6,7) asl r1 ;4 bytes per unit. mov r1,r3 ;Need this value to calculate table offset .addr #partab,r1,add return o.csr: call gettab ;(only to check for TSX use) cmp r0,#160000 blo o.bad bit #3,r0 bne o.bad mov r0,inscsr mov r0,ip mov r0,r1 inc r1 inc r1 mov r1,sa call writb1 mov #bducsr/1000,r1 call readb mov r0,(r2) o.w: call writb call readb1 br o.good o.vec: call gettab ;(only to check for TSX use) cmp r0,#400 bhis o.bad bit #3,r0 bne o.bad mov r0,dustrt asr r0 ;Set up in form required for init list asr r0 add #,r0 mov r0,vec o.good: tst (pc)+ o.bad: sec return .iif gt <.-1000>, .error .Sbttl .Sbttl HANDLER PROPER .Sbttl -------------- .Sbttl Entry Point of Handler .drbeg du jmp begin ;Put data area here for SETs if needed .Sbttl DATA AREA .Sbttl . MCSP Buffers ;Word needed by TSX+ .if ne TSX$P MPOINT: 0 ;If TSX, need separate word for virtual MBUFF address .iff MPOINT=MRING ;Otherwise MBUFF address is in MRING. .endc ;Headers: CMDINT: 0 ;Zeroed by host; set if interrupt caused by command RSPINT: 0 ;ibid, response. MRING: .blkw 2 ;Pointer to MBUFF, with flags in second word CRING: .blkw 2 ;Pointer to CBUFF, with flags in second word ;Buffers: COMAND: LN.CMD: 0 ;Command length VC.CMD: 0 ;Connection ID, message type, and credits CBUFF: .blkb P.CSIZ ;Actual buffer MESAGE: LN.RSP: 0 ;Response length VC.RSP: 0 ;Connection ID, message type, and credits MBUFF: .blkb P.MSIZ ;Actual buffer .Sbttl . Data Modifiable by SET Commands IP: ducsr ;Initialization/Polling register address SA: ducsr+2 ;Status/Address register VEC: + + step ;Vector as required for init list .Sbttl . Data Settable/Receivable by SPFUNs DUTAB: .rad50 /DU / ;Allow for RT-11 5.4 et seq .word 8. PARTAB: .word 0,0, 0,1, 0,2, 0,3, 0,4, 0,5 ;Unit,partition JOBTAB: .word 0,6, 0,7 ;Alterable units. .if ne TSX$P .rept ts$job .word 0,6, 0,7 .endr .endc STATS: ;STATISTICS TABLE s.ver: du.ver ;Version number, for making sure we know format s.ini: 0 ;# of INITs performed successfully s.inir: 0 ;# of INIT retries s.bldy: 0 ;# of bloody disasters (ie SA negative) s.avl: 0 ;# of AVAIL errors s.ior: 0 ;# of I/O retries s.ioer: 0 ;# of I/O errors ln.st=.-stats ;Length of stats table .Sbttl . Initialization Data iretry: 0 ;Retry count for initialization inmask: 0 ;Receives mask as goes from ISTEP1 to ISTEP4 inpntr: 0 ;Pointer within INILST inilst: 0 ;Values required for initialization (set up later) ringad: 0 ;Receives ring address before init 0 GO .Sbttl . Other Data fblk: .blkw 4 ;Fork block WCQE: 0 ;Headers for WAITING queue WLQE: 0 CREDNM: 0 ;Credit available from this disc CREDIT: 0 ;Credit available and allowed to be used (1 if serious ; error situation being dealt with). CMDCNT: 0 ;Number of commands in progress BLOCKF: -1 ;>=0 if serious error handling in progress QFLAG: 0 ; -1 if not processing queues at fork level ; 0 if checking queues ; >0 if need to re-check queues (eg after interrupt) ;QTAB Table: This contains the elements currently being processed. The ; address of each element is held in QTAB, with the least significant bit ; (=1) set if it is necessary to send an MSCP command for this element. ; The table is terminated by the value -1. ; The QPOINT pointer is used by the MSCP command dispatcher as a pointer to ; the last accessed location in QTAB. This allows progressive dealing with ; elements in QTAB, as otherwise were one to always start at the bottom, some ; queue elements may never get handled! .iif ndf qnum, qnum=32. QTAB: .blkw qnum ;Allow for a maximum of 32 queued elements. .word -1 ;Terminator for list. QPOINT: 0 ;Pointer within QTAB for command dispatching to DU .Sbttl Driver Code Proper .Enabl lsb Begin: mov ducqe,r4 ;(DULQE always zero if take current ; element off queue before returning) .if ne tsx$p call jobnum ;See that job number is legal. bcs duerr .endc movb q$func(r4),r5 ;Check SPFUNs as need this byte beq 10$ ; for coding function of element ; Check for SPFUN's which can be dealt with immediately cmpb r5,#sp.sts ;Read statistics table? jmpeq sp$sts cmpb r5,#sp.dat ;DEC partition table? beq sp$dat ; Check for SPFUN's which will require queueing to the disc cmpb r5,#sp.psz ;Partition size? beq .psz cmpb r5,#sp.usz ;Unit size? beq .usz cmpb r5,#sp.pio ;Physical I/O? beq .pio cmpb r5,#sp.rio ;Special read? beq .rio cmpb r5,#sp.wio ;Special write? bne duerr .br .wio ; Prepare for non-immediate SPFUN's .wio: neg q$wcnt(r4) ;Special write - negate word count .rio: movb #x.sio,q$func(r4) ; and treat as special read. br 15$ ;Still check for partition overflow. .pio: call getprt ;Allow physical I/O only if the tst r5 ; corresponding partition number bne duerr ; is zero. movb #x.pio,q$func(r4) ;Code for physical I/O br 40$ .psz: movb #x.psz,q$func(r4) ;Code for partition size br 40$ .usz: movb #x.usz,q$func(r4) ;Code for unit size br 40$ ; Normal or special I/O: check for extending partition boundaries 10$: .assume x.io eq 0 ;Normal I/O - Q$FUNC code zero 15$: mov q$wcnt(r4),r5 ;See if he's extending partition bpl 20$ ; boundaries. neg r5 20$: add #377,r5 ;Part blocks -> whole blocks bic #377,r5 swab r5 ;Convert to blocks .assume q$blkn eq 0 add (r4),r5 bcc 40$ duerr: bis #hderr$,@q$csw(r4) ;Whoops! (but leave R4->queue element) mov #-1,r0 ;Error code for special I/O call spioex ;If special I/O, return bad vibes br duhome ; Add element to WAITING queue 40$: nointerrupts mov wlqe,r5 ;;;Pointer to last element bne 50$ ;;;There is one - link after it. mov r4,wcqe ;;;If none, then this is first one too br 60$ ;;; 50$: mov r4,q$link(r5) ;;;Link into previous last element 60$: mov r4,wlqe ;;;and this is now the last. clr ducqe ;;;De-queue it from monitor clr dulqe ;;; interrupts bit #isteps,@sa ;Check for bus RESET bne init ;(or can't reboot in RT-11, & SJ dies) tst inmask ;Have we already INITed? beq init ;No. inc qflag ;See if something going at fork level beq 70$ ;No - go to it. return 70$: jmp chkp ;Yes - check queued queue. .Dsabl lsb .Sbttl Immediate SPFUN's ;.................... SP.DAT (372) - DEC's PARTITION TABLE ................... tabsiz=<2*8.>+2 ;Table size in RT-11 V5.4 (words) .if ne tsx$p tabsiz=tabsiz-4 ;Table size less units 6 & 7 for TSX .endc sp$dat: .addr #dutab,r2 ;Address of partition table mov #tabsiz,r1 ;Number of words in partition table mov @#sysptr,r3 ;Check version of RT/TSX add #sysver,r3 cmpb (r3)+,#5 ;If later than version 5 use 5.4 table bhi 20$ ;Later than version 5 blo 10$ ;Earlier than version 5 cmpb (r3),#4 ;Version 5 - see if 5.4 or later bhis 20$ 10$: add #4,r2 ;Earlier than version 5: don't include sub #2,r1 ; ^rDU or count of units. 20$: tst q$wcnt(r4) ;Negative=write, positive=read bpl rpt .if eq TSX$P ;Write partition table - RT-11 30$: call getwrd mov r0,(r2)+ dec r1 bne 30$ br duhome ;Read partition table - RT-11 ;Just head off to DUPUT to send the table .iff ;Write partition table - TSX-plus 30$: call getwrd ;Waste all words except units 6 & 7 dec r1 bne 30$ call jobnum mov r1,r2 ;Address of table for 6 & 7 for this job .addr #jobtab,r2,add mov #4,r1 40$: call getwrd mov r0,(r2)+ dec r1 bne 40$ br duhome ;Read partition table - TSX-plus rpt: call putwrd ;Transfer words up to partitions 6 & 7 call jobnum ;Returns in r1 mov r1,r2 ;Address of this job's 6 & 7 table .addr #jobtab,r2,add mov #4,r1 ;4 words left br duput .endc .Sbttl Discontinued SPFUNs .if eq 1 ;.................... SP.RPT (361) - READ PARTITION TABLE .................... sp$rpt: .if ne TSX$P .addr #partab,r2 ;Transfer from here mov #12.,r1 ;12 words call putwrd add #jobtab-partab,r2 call jobnum ;Returns in r1 add r1,r2 ;Pointer to job table for this job mov #4,r1 ;4 words - 2 for DU6, 2 for DU7 br duput .iff .addr #partab,r2 ;If not TSX, contiguous table. mov #16.,r1 br duput .endc ;.................... SP.WPT (362) - WRITE PARTITION TABLE ................... sp$wpt: mov #12.,r1 10$: call getwrd ;Waste first 12 words dec r1 bne 10$ .addr #jobtab,r2 ;Only change units 6 and 7 .if ne TSX$P call jobnum ;Returns in r1 add r1,r2 ;Address of this job's table .endc mov #4,r1 20$: call getwrd ;Only change units 6 & 7 mov r0,(r2)+ ;(2 words each) dec r1 bne 20$ br duhome .endc ;.................... SP.STS (363) - READ STATISTICS TABLE ................... sp$sts: .addr #stats,r2 mov #ln.st/2,r1 .iif eq tsx$p, rpt: duput: call putwrd duhome: .drfin du .Dsabl lsb .Sbttl Initialization .Enabl lsb INIT:: clr qflag ;Make it appear we're busy in the queue system clr cmdcnt ;No commands running at the moment. .addr #qtab,r0 ;Address of table of elements being processed mov r0,qpoint mov #3,iretry ;3 Initialization Retries allowed. mov vec,inilst ;Set up vector in initialization sequence ini0: mov #0,@IP ;Commence initialization ;(Can't use MOV SP or PC as low order byte may ;invoke boot or Wombat; can't CLR as on LSI-11 ;causes a READ which -> poll first!) .if eq TSX$P .addr #mring,-(sp) ;Ring address in initialization list mov (sp)+,ringad .iff call mapadr .word map-mring ;Get physical ring address mov r5,ringad mov r4,ringad+2 .addr #mbuff,-(sp) ;Get virtual message buffer address mov (sp)+,mpoint .endc .addr #inilst-2,-(sp) ;Pointer within init list mov (sp)+,inpntr mov #istep1,inmask ;Masks go from 4000 to 40000 mov #inint-next-2,next ;Set up for interrupts 10$: mov @sa,r5 ;Get status beq 10$ ;Give it time to get a value (should be quick) br 20$ ININT:: ;Come here on initialization interrupts .fork fblk 20$: mov @sa,r5 bmi inierr ;Whoops - error bic #^c,r5 ;Clear all but STEP bits cmp r5,inmask ; and see that only the one is set bne inierr asl inmask ;For next mask add #2,inpntr ;And next data word mov @inpntr,@sa tst inmask ;If hit the end of the list, bmi ini2 ; go to next exciting episode. return ;Else just continue init .Dsabl lsb Inierr:: inc s.inir ;Counter of INIT retries dec iretry bne ini0 10$: ;In real trouble here: can't init. mov wcqe,r4 ;Get an element from waiting queue beq 20$ ;If none left, fine. nointerrupts ;;; mov q$link(r4),wcqe ;;; bne 11$ ;;; clr wlqe ;;; 11$: ;;; interrupts ;;; mov #si.err,r0 ;Return full-scale error to special I/O call spioex call delinb ;De-link back to monitor, bad one. br 10$ 20$: .addr #qtab,r5 ;De-link all elements currently in list 30$: mov (r5),r4 ; of those undergoing processing. cmp r4,#-1 ;End of table beq 40$ bic #1,r4 ;Clear "to be processed" bit call delinb ;Return them with error clr (r5)+ ;Clear table entry br 30$ 40$: clr inmask ;In case he tries again! return .Sbttl Second Initialization Phase ;The second initialization phase sets up the communications addresses, ; then uses SET CONTROLLER CHARACTERISTICS to ; remove any timeout and get the command credit count. INI2:: .if eq TSX$P .addr #mbuff,-(sp) ;Set up buffer ring addresses mov (sp)+,mring clr mring+2 call mset .addr #cbuff,-(sp) mov (sp)+,cring clr cring+2 .iff call mapadr .word map-mbuff ;Set up buffer ring addresses mov r5,mring mov r4,mring+2 call mset call mapadr .word map-cbuff mov r5,cring mov r4,cring+2 .endc clr credit ;Zero count of credits from controller mov #ini3-next-2,next ;Appropriate interrupt address ini2a: call cset movb #op.scc,p.opcd(r3) ;SET CONTROLLER CHARACTERISTICS .if ne to.min mov #to.min*60.,p.htmo(r3) ;(Be surprised if it's ever non-0) .endc $$own=< & 77777 > / 200 ;Want OWN in low-order byte ; (unsigned divide-by-400) movb #$$own,cring+2+1 ;Command ready, don't interrupt bis #own!flag,mring+2 ;Ready for message, do interrupt tst @ip ;Poll return INI3:: .fork fblk tstb mbuff+p.sts ;Check for errors in OP.SCC use bne inierr movb vc.rsp,r0 bic #^c377,r0 ;"Message" field should be zero, dec r0 ; so if controller returns it all at ble ini3b ini3a: add r0,credit ; once, use it (Websters, bugger 'em). br ini2a ;[Fixed in later firmware] ini3b: cmp credit,#qnum ;See if have table space for available blos 10$ ; credit. mov #qnum,credit ;If not, use our maximum. 10$: tst crednm ;Has allowed credit been set up? bne 20$ ;Yes: may be processing serious error mov credit,crednm ; otherwise set it up (it shouldn't 20$: ; alter between INITs). mov #rwint-next-2,next ;Set up for R/W interrupts call mset ;Set up for message interrupts bis #own!flag,mring+2 inc s.ini ;Counter of successful initializations br chkp ;Initialization Complete. .Sbttl Check the Elements Currently Undergoing Processing (QTAB) .If eq 1 There are two phases to the handling of queue elements: 1) Check the list of those entered in the QTAB table, returning any which have been completed, re-queuing any which have more work to be done, and placing any new ones into any vacant slots in the table. 2) Check the QTAB table for any capable of being sent off as an MSCP command. .endc .Enabl lsb Chkpf:: ;(Here if haven't forked yet) inc qflag ;See if already forked beq 10$ ;No - process queues return ;Yes - he'll test the flag at the end. 10$: .fork fblk Chkp:: ;(Here if forked already) .addr #qtab,r1 ;Link-offset pointer to qcqe mov #qnum,r2 ;Maximum number of elements allowed 20$: mov (r1)+,r4 ;Get next element address bne 60$ ;Not unused table entry ;Here, have an empty table entry. Queue next one from the WAITING queue. 30$: tst blockf ;See if processing bad error bpl 70$ ;Yes - add no more to queue. mov wcqe,r0 ;Address of next waiting element beq 70$ ;None. nointerrupts ;;; mov q$link(r0),wcqe ;;;Remove it from WAITING queue bne 40$ ;;;Another element waiting. clr wlqe ;;;No more - clear LAST element also 40$: mov r0,-(r1) ;;;Insert into table interrupts ; Set its internal parameters ready for action: mov #retry,q$link(r0) ;Retries in link byte. Clear flags. .assume x.io lt x.psz .assume x.pio lt x.psz .assume x.sio lt x.psz .assume x.usz gt x.psz cmpb q$func(r0),#x.psz ;If a size function, need ONLINE blo 50$ bisb #x.online,q$link+1(r0) ; so set relevant bit. 50$: inc (r1)+ ;Set LSB in QTAB so will be sent ; as command. br 70$ ;Check out next table entry ;Table entry non-zero. See if a message has been returned concerning it ; (ie see if q$link+1 has high-order bit set) 60$: bit #1,r4 ;%1b If still requires queueing, bne 70$ ;%1b don't try to return it. .assume x.done eq 200 movb q$link+1(r4),r5 ;See what the flags byte says bmi 80$ ;If positive, still waiting for disc 70$: dec r2 ;Move on to the next queue slot. bgt 20$ jmp chkc ;None left here - try for command ; required. ;Negative status byte in q$link+1. Some action has occurred concerning this ; element. Check whether error or not. 80$: bitb #x.error,r5 bne 110$ ;Error condition occurred. ;No error: either completed I/O or SPFUN, or ONLINE completed. cmpb q$func(r4),#x.psz ;Partition size SPFUN beq sp$psz cmpb q$func(r4),#x.usz ;Unit size SPFUN beq sp$usz bitb #x.online,r5 ;See if ONLINE or actual I/O beq 90$ ;Not ONLINE - must be I/O bicb #x.online,q$link+1(r4) ;Was ONLINE - clear ONLINE bit bisb #x.ondone,q$link+1(r4) ;Remember have done an ONLINE movb #retry,q$link(r4) ;Reset retries for actual I/O br 130$ ; & requeue ;Return after actual I/O 90$: mov #si.ok,r0 ;Hopefully good I/O cmpb q$link(r4),#retry ;See if any retries beq 100$ ;No. mov #si.rty,r0 ;Were. 100$: call spioex ;Set up special first buffer word prn call delink ;Return this element OK br 170$ ;Remove it from table ; and put in another if available. ;ERROR occurred: ; If ONLINE request, prior to V1h, kill this element - do so no longer. ; If I/O request, see if any retries left. If none, kill him. If some, ; then check whether error was AVAILABLE. If so, convert to ONLINE ; request and retry. If not, retry anyway. 110$: tstb q$link(r4) ;Any retries left? beq 150$ ;No - die you dog. decb q$link(r4) ;Decrease his retries. bitb #x.bbr,q$link+1(4) ;Was error BBR? beq 120$ ;No. mov #si.bbr,r0 ;Yes - tell him with no further ado. br 160$ 120$: bitb #x.avail,q$link+1(r4) ;Was it AVAILABLE? beq 130$ ;No. bitb #x.ondone,q$link+1(r4) ;Previous AVAILABLE performed? bne 150$ ;Yes: shoot the piano player. bisb #x.online,q$link+1(r4) ;Try to get unit on line. inc s.avl ;Count of AVAIL errors br 140$ 130$: inc s.ior ;Count of I/O retries 140$: bicb #,q$link+1(r4) ;Clear error bits inc -2(r1) ;Set so command dispatcher sees it. br 70$ 150$: mov #si.err,r0 160$: call spioex ;Return error word for special I/O call delinb 170$: clr -2(r1) ;Clear the table entry br 30$ .Sbttl SPFUNs which require ONLINE command (Size SPFUNs) ;.................... 373 - RETURN PARTITION SIZE ............................ sp$psz: call getprt ;Get partition number in R5 mov q$wcnt(r4),-(sp);If low order volume size 0, reduce size by 1 bne 180$ dec (sp) dec q$blkn(r4) bmi 190$ ;If -> -1, zero size disc. 180$: cmpb r5,q$blkn(r4) ;Check whether this partition exists beq 210$ ;If top partition, use low order size only. blo 200$ 190$: bis #hderr$,@q$csw(r4) ;Error if doesn't exist 200$: mov #177777,(sp) ;If not end partition, 177777 blocks. 210$: .if ne mmg$t call @$ptwrd .iff mov (sp)+,@q$buff(r4) .endc br 90$ ;.................... SP.USZ (360) - RETURN UNIT SIZE (2 WORDS) .............. sp$usz: .if ne mmg$t mov q$blkn(r4),-(sp) ;High order word first call @$ptwrd mov q$wcnt(r4),-(sp) ; then low order. (Put here at call @$ptwrd ; interrupt level). .iff mov q$buff(r4),r5 ;Buffer address mov q$blkn(r4),(r5)+ mov q$wcnt(r4),(r5) .endc br 90$ .Dsabl lsb .Sbttl Check for Elements Requiring an MSCP Command to be Sent chkc: tst cring+2 ;See if command ring busy bmi 80$ ;Yes - don't crowd the controller cmp cmdcnt,credit ;Any credit left? bhis 80$ ;No - patience is a virtue. mov #qnum,r1 ;In case none -> loop 10$: cmp @qpoint,#-1 ;See if pointer points to end of table bne 20$ .addr #qtab,r0 ;If so, reset to start. mov r0,qpoint tst blockf ;If serious error, now completed it. bmi 20$ ;(wasn't) mov crednm,credit ;Set back to normal inc qflag ;(so we queue waiting elements) mov #-1,blockf 20$: mov @qpoint,r4 bit #1,r4 ;See if requires command. bne 35$ 30$: add #2,qpoint dec r1 bne 10$ br 80$ ;End of all we can do here. ;Here, we have something requiring a command to be sent 35$: dec @qpoint ;Clear command queueing bit. dec r4 call getprt ;Get unit in R0, partition in R5 call cset ;Set up the command buffer mov r0,p.unit(r3) ;Always insert unit number. bitb #x.online,q$link+1(r4) ;See if only need an ONLINE beq 40$ ;No. ; ONLINE only required mov #op.onl,p.opcd(r3) ;Yes - nothing further. br 70$ 40$: mov q$wcnt(r4),r2 ;Get word count word ready. mov r5,p.part(r3) ;Insert partition cmpb q$func(r4),#x.pio ;Normal I/O or physical I/O? bne 50$ ;Not physical. ; PHYSICAL I/O movb r2,p.part(r3) ;Use low-order word count for bic #377,r2 ; high order block number. 50$: ; Normal I/O movb #op.rd,p.opcd(r3) ;Assume read till proved otherwise. tst r2 ;Write? bpl 60$ ;No. neg r2 ;Yes - convert word count to positive .assume op.wr eq op.rd+1 incb p.opcd(r3) ; and insert WRITE opcode. 60$: .if eq mmg$t ;Buffer address mov q$buff(r4),p.buff(r3) .iff .if ne $xlink mov q$umrx(r4),-(sp) ;Don't confuse the issue clr q$umrx(r4) ; with unwanted UMR's. .endc mov r4,r5 add #q$buff,r5 call @$mpptr mov (sp)+,p.buff(r3) mov (sp)+,r0 ash #-4,r0 movb r0,p.buff+2(r3) .if ne $xlink mov (sp)+,q$umrx(r4) .endc .endc cmpb q$func(r4),#x.sio ;If special I/O, skip initial status bne 65$ ; word in buffer. add #2,p.buff(r3) .if ne mmg$t adc p.buff+2(r3) .endc 65$: asl r2 mov r2,p.bcnt(r3) ;Byte count .assume q$blkn eq 0 mov (r4),p.lbn(r3) ;Block number 70$: mov r4,p.crf(r3) ;Element address for Message Interrupt inc cmdcnt ;Another ship launched. bis #own!flag,cring+2 tst @ip 80$: bit #100000!isteps,@sa ;Check for any nasty crashes bne urgher dec qflag ;See if due for any re-runs (eg after bmi 90$ ; an interrupt) jmp chkp ;More to do. 90$: return .Sbttl Move Data to & from User Buffer ; PUTWRD expects an address in R2 and a word count in R1. ; R2 is returned unchanged. putwrd: ;Put word into user's buffer mov r2,-(sp) 10$: .if ne mmg$t mov (r2)+,-(sp) call @$ptwrd .iff mov (r2)+,@q$buff(r4) add #2,q$buff(r4) .endc dec r1 bne 10$ mov (sp)+,r2 return ;GETWRD returns a word in R0. getwrd: ;Get word from user's buffer clr r0 .if ne mmg$t call @$gtbyt bisb (sp)+,r0 call @$gtbyt swab (sp) bisb (sp)+,r0 .iff mov @q$buff(r4),r0 add #2,q$buff(r4) .endc return .Sbttl Return Special I/O Word ;Called by mov #value,r0 ; mov
,r4 ; call spioex ;checks for special I/O on this queue element, and if in use puts the ;value in R0 into the first word of the buffer spioex: cmpb q$func(r4),#x.sio bne 10$ ;Not special I/O .if ne mmg$t mov r0,-(sp) call @$ptwrd .iff mov r0,@q$buff(r4) .endc 10$: return .Sbttl Interrupts ;It appears to be essential to get messages cleared from the message buffer ; as fast as possible to avoid a device time-out problem. ;This problem appears to have been overcome with later controllers. Ignore: return ;(Used for ignoring interrupts) .if ne $xlink Hook:: .word .-dulqe+4 ;Hook for WA handler to communicate .endc ; with DU handler in case DU not ; mapped under TSX. .DRAST du,7,ignore ;Abort entry point not used. tst @sa bmi saerr jmp . NEXT = .-2 ;Plugged with relevant offset for ; interrupt (LOC-NEXT-2) saerr: ;If unknown, assume disaster. .fork fblk br urgher ;Disastrous error RWINT:: .assume own eq 100000 tst mring+2 bpl rwmsg ;Message Interrupt .br rwcmd ;If not message, assume command. RWCMD:: ;COMMAND INTERRUPT bit #100000!isteps,@sa bne saerr jmp chkpf ;Check out processing queue prn .Sbttl Message Interrupts .Enabl lsb RWMSG:: ;MESSAGE INTERRUPT mov mpoint,r4 mov p.crf(r4),r5 ;Address of element tst p.sts(r4) ;Check for error bne 10$ ; No error on this element. If SIZE SPFUN need to put size across .assume x.psz lt x.usz cmpb q$func(r5),#x.psz blo 20$ ;Not a size spfun. mov p.unsz+2(r4),q$blkn(r5) ;High order size mov p.unsz+0(r4),q$wcnt(r5) ;Low order size br 20$ ; Error on this element. See whether AVAILABLE or not 10$: bisb #x.error,q$link+1(r5) movb p.sts(r4),-(sp) ;Get error code bic #^c,(sp) ;Remove subcodes cmpb (sp)+,#st.avl ;See if (basically) available bne 15$ ;Not. bisb #x.avail,q$link+1(r5) br 20$ 15$: bit #ef.bbr,p.sts(r4) ;See if BBR error beq 20$ bisb #x.bbr,q$link+1(r5) ;Is BBR - set bit to remember it by ; Final common pathway for message elements 20$: bisb #x.done,q$link+1(r5) ;Set DONE bit dec cmdcnt ;Room for another command bis #own!flag,mring+2 tst @ip ;Poll to return message element bit #100000!isteps,@sa bne saerr jmp chkpf .Dsabl lsb .Sbttl Handling of Extremely Nasty Errors Urgher: inc s.bldy ;Count of bloody errors. mov #ignore-next-2,next ;Ignore any interrupts here clr @ip ;Tell him we need to re-init mov #1,credit ;Allow only a single command at a time clr cmdcnt ;None active currently inc blockf ;Set flag, and see whether already beq 20$ ; handling serious error. ;Here, serious error encountered whilst already handling serious error mov @qpoint,r4 ;Return in error the current command cmp r4,#-1 ; element (the -1 & 0 shouldn't occur, beq 10$ ; but logic ain't the essence ...) bic #1,r1 beq 10$ bic #1,qpoint ;Belt & braces ... clr @qpoint ;Clear table entry mov #si.err,r0 ;Error code if special I/O call spioex call delinb ;Send it home in disgrace 10$: br 50$ ;Here, serious error, first encounter of the close kind 20$: .addr #qtab,r5 ;Address of QUEUED list mov r5,qpoint ;Reset so work sequentially through Q mov #qnum,r2 30$: mov (r5)+,r4 ;Check this slot beq 40$ ;Empty - ignore. bic #1,r4 ;Clear "command" bit .assume x.done eq 200 bic #x.ondone,q$link+1(r4) ;Give him another chance to init. tstb q$link+1(r4) ;See if was already processed. bmi 40$ ;Was - leave to normal channels bis #1,-2(r5) ;Wasn't - reset "command" bit 40$: dec r2 bgt 30$ 50$: jmp init ;No more - re-init .Sbttl .Sbttl Subroutines .Sbttl . DELINK - Return an Element to the Monitor ;Expects: R4 / pointer to element to be delinked ;Returns: R4 & R5 / altered ;(the monitor does not alter r0 - r3) .word 0,0,0 dulqx: .word 0 ducqx: .word 0 Delinb: inc s.ioer ;Count of I/O errors bis #hderr$,@q$csw(r4) ;Bad return - returns an error Delink:: .addr #dulqx,r5 mov r4,(r5)+ mov r4,(r5) clr q$link(r4) ;Clear flags, retries in link word clrb q$func(r4) ;Clear FUNC or monitor can alter error byte .if ne tsx$p .if ne $xlink clr q$umrx(r4) ;Clear this or TSX gets very muddled! .endc .endc mov r5,r4 mov @#sysptr,r5 jmp @drfin$(r5) ;Return the element .Sbttl . GETPRT - Return Partition Number ;Expects R4 / pointer to queue element ;Returns R0 / unit number for this request ; R5 / partition number, ibid Getprt:: .if ne TSX$P .if ne $xlink tst q$umrx(r4) ;Special unit/partition? beq 5$ ;No - normal request. mov r4,r5 add #q$umrx,r5 ;Yes - point to q$umrx clr r0 bisb (r5)+,r0 ;Get unit number movb (r5),r5 ; and partition number bic #^c<377>,r5 return 5$: .endc movb q$unit(r4),r5 bic #^c<7>,r5 ;Unit number only asl r5 ;Unit * 2 asl r5 ;Unit * 4 (2 words per table entry) cmp r5,#6*4 ;6 or 7? blo 10$ ;No - simple mapping from partab mov r1,-(sp) call jobnum ;Returns in r1 add r1,r5 mov (sp)+,r1 .iff movb q$unit(r4),r5 bic #^c<7>,r5 asl r5 asl r5 ;Unit number * 4 .endc 10$: .addr #partab,r5,add ;Add table base address mov (r5)+,r0 ;Unit number mov (r5),r5 ;Partition return .Sbttl . TSX High Memory Mapping .If eq 1 Called by call mapadr .word map-address returns r4 / high order physical address r5 / low order physical address .Endc .if ne TSX$P Mapadr: clr r4 ;Clear high order physical address mov pc,r5 map: sub @(sp),r5 ;Get virtual address of desired loc add #2,(sp) ;So we return properly. cmp r5,#120000 ;Mapped? blo 10$ ;No - no problems. mov r5,-(sp) ;Yes. Hold virtual address mov @#172352,r5 ;Get PAR5 value ashc #6,r4 ;Convert to physical address bic #160000,(sp) ;Remove offset from virtual address add (sp)+,r5 ;Add to physical address offset adc r4 ;(Need high order bits right-justified) 10$: return .Sbttl . TSX Job Number Determination ;Expects CQE pointer in R4 ;Returns job number in R1, * 8. ; CS if > ts$job Jobnum:: movb q$jnum(r4),r1 ;Job & unit numbers bic #^c370,r1 ;Job number * 8 cmp r1,#8.*31. bne 10$ ;If not 31., no problems. clr r1 bisb q$job(r4),r1 ;Otherwise get it from other job location cmp r1,#ts$job bhi 20$ asl r1 asl r1 asl r1 ;Want it * 8. 10$: tst (pc)+ 20$: sec return .endc .Sbttl . Buffer Initialization .enabl lsb ;These routines return the buffer address in R3, suitable for use with ; the MSCP offsets defined at the end of this file. Mset:: mov r5,-(sp) clr rspint ;Clear interrupt flag .addr #mesage,r3 ;Address of text portion of message buffer mov #p.msiz/2,r5 ;Number of words in text portion of buffer mov #p.msiz,(r3)+ ;Length available for messages br 10$ Cset:: mov r5,-(sp) clr cmdint ;Clear interrupt flag .addr #comand,r3 ;Address of text portion of command buffer mov #p.csiz/2,r5 ;Number of words in text portion of buffer mov #p.csiz,(r3)+ ;Length of command 10$: clr (r3)+ ;Zero for connection ID, message type etc mov r3,-(sp) ;Actually points to text area of buffer now 20$: clr (r3)+ ;Zero out buffer dec r5 bne 20$ mov (sp)+,r3 ;Return buffer address in r3. mov (sp)+,r5 return .dsabl lsb .Sbttl .Sbttl ------------------------------- .Sbttl .Sbttl Bootstrap Driver .psect dudvr .psect junk ;Used to force an even block boundary for boot linking .psect duboot ; (necessary for SET UNIT & PART to work properly) .Drbot du,boot1,read,control= . = duboot+40 boot1: jmp @#boot-duboot . = duboot+120 read: tst hrdbot beq reada mov @#b$devu,(pc)+ bunit: .word 0 reada: mov #3,bretry asl r1 asr #1 bcc read1 binit: dec (pc)+ bretry: .word 0 blt bioelk mov bducsr,r5 mov r4,(r5)+ mov #istep1,r3 mov #binlst-duboot,r4 1$: tst @r5 bmi binit bit @r5,r3 beq 1$ mov (r4)+,@r5 asl r3 bpl 1$ cmp (r4)+,(r4)+ mov r4,bcring mov r4,bmring jsr r0,bgtbuf .word op.onl call bdoio .br read1 READ1: jsr r0,bgtbuf .word op.rd mov r0,p.lbn(r4) mov r1,p.bcnt(r4) mov r2,p.buff(r4) .br bdoio .Enabl lsb bdoio: mov (pc)+,r3 bducsr: .word du$csr 1$: mov #bcring+2-duboot,r4 mov #own,@r4 mov (r3)+,r5 2$: tst @r3 bne 4$ tst @r4 bmi 2$ tst -(r4) mov #own,-(r4) 3$: tst @r3 bne 4$ tst @r4 bmi 3$ tstb bbuff+p.sts bioelk: bne bioerr return 4$: tst (sp)+ br binit .Dsabl lsb Bgtbuf: mov #bbuff-duboot+p.msiz,r4 1$: clr -(r4) cmp r4,#bbuff-duboot bhi 1$ mov #p.msiz,-4(r4) mov bunit,r5 ;Translate logical unit asl r5 ; to physical unit asl r5 ; and partition. .addr #bpartb,r5,add ;Table address + <4 * offset> mov (r5)+,p.unit(r4) ;Unit cmp (r0),#op.rd ;Only put in partition if bne 2$ ; a READ command (not for ONLINE) mov (r5)+,p.part(r4) ;(Goes in high-order block number) 2$: mov (r0)+,p.opcd(r4) rts r0 .Sbttl Bootstrap Impure Area Binlst: .byte 0 .byte 0*10+0+step .word bmring-duboot .word 0 .word go Bln: .word 0 Bvc: .word 0 Bbuff: .blkb p.msiz .word 0,0 Bmring: .word 0,0 Bcring: .word 0,0 .Sbttl Bootstrap Partition Table bpartb: .word 0,0, 0,1, 0,2, 0,3, 0,4, 0,5, 0,6, 0,7 .assume . le duboot+576 .Sbttl Bootstrap Primary Routine . = duboot+576 Boot: mov #10000,sp mov r0,-(sp) bic #^c<7>,@sp mov (sp),bunit mov #2,r0 mov #<4*400>,r1 mov #1000,r2 clr (pc)+ hrdbot: .word 1 call read mov #read-duboot,@#b$read mov #b$dnam,@#b$devn mov (sp)+,@#b$devu jmp @#b$boot .Sbttl Handler Termination .drend du .Sbttl Force boot code to be linked at start of disc block for SETs .save .psect dudvr .if ne < <.-dustrt> & 777 > $$$ = 1000 - < <.-dustrt> & 777 > .psect junk .blkb $$$ .endc .restore .Sbttl .Sbttl ---------------------------- .Sbttl .Sbttl PROGRAMME PORTION .Sbttl ***************** .nlist bex .psect program .mcall .sreset,.spfun,.print,.exit,.savestatus,.reopen,.purge,.csigen,.wait .mcall .csispc,.dstatus,.gval userrb=53 ;User Error Byte error$=4 ;Value for normal error jsw=44 ;Job Status Word ttlc$=40000 ;Allow Lower Case cr=15 lf=12 .macro type string ;Convenient form of .PRINT request .save .psect mesage con $$$=. .ascii string .restore mov r0,-(sp) .print #$$$ mov (sp)+,r0 .endm type tabsiz=<2*8.>+2 ;Words in partition table stack: 0 area: .blkw 7 ;General EMT Area defext: .rad50 / / limit: .limit tsxloc: 0 ;Negative if running under TSX-plus rttyp2: 0 ;Non-zero if running under >= 5.4 RT ptab: 0 ;Pointer to start of data in PTABLE ntab: 0 ;Pointer to start of data in NTABLE ptable: .blkw tabsiz ;Partition table ntable: .blkw tabsiz ;New partition table line: .blkb 100. ;Input line saves: .blkw 5 ;Savestatus area s.csw=0 ; Channel status s.sblk=2 ; Starting block s.leng=4 ; Length s.hibl=6 ; Highest block written s.reqs=10 ; Pending requests (byte) s.devu=11 ; Device unit (byte) size: .blkw 2 ;For unit size swt.e: 0 ;Non-zero if /E specified swt.l: 0 ;Non-zero if /L specified swt.x: 0 ;Non-zero if /X specified swt.c: 0 ;Non-zero if /C specified swt.p: 0 ;Non-zero if /P specified swt.u: 0 ;Non-zero if /U specified swt.s: 0 ;Non-zero if /S specified val.c: 0 ;Value if /C specified val.p: 0 ;Value if /P specified val.u: 0 ;Value if /U specified outfil: .blkw 3*5 ;CSISPC block, output files infil: .blkw 6*4 ;ibid, input files .macro .error routine,?tag bcc tag jmp routine tag: .endm .error .Sbttl Get Command and Process Switches .Enabl lsb Badrun:: bisb #error$,@#userrb ;Error which will. Rerun:: mov stack,sp Start:: .sreset mov sp,stack ;Save for reruns bis #ttlc$,@#jsw ;Who wants upper case anyhow? .gval #area,#sysgen mov r0,tsxloc clr rttyp2 ;Zero unless > RT 5.4 mov #ptable,ptab ;If < 5.4, no additional table words mov #ntable,ntab .gval #area,#sysver ;System version number cmpb r0,#5 blo 6$ bhi 4$ .gval #area,#sysupd cmpb r0,#4 blo 6$ 4$: dec rttyp2 ;Under RT 5.4 or greater mov #ptable+4,ptab ;Data starts after additional words mov #ntable+4,ntab 6$: .csigen limit+2,#defext,,#line cmp r0,limit+2 beq 10$ type > br badrun 10$: tstb line bne 20$ .print #vermes br start 20$: .csispc #outfil,#defext,#line ;Get rad50 names clr swt.e ;Clear switch locations clr swt.l clr swt.x clr swt.c clr swt.p clr swt.u clr swt.s clr val.c clr val.p clr val.u mov (sp)+,r5 ;# of switches bne nexswt jmp endswt ;None specified Nexswt: dec r5 ;Any left? bpl 25$ ;Yes jmp endswt ;No. 25$: clr r2 ;In case no value. mov (sp)+,r1 ;b15 set if value specified, b14-8 file on ; which switch specified, b7-0 ascii value bpl 30$ ; of switch. mov (sp)+,r2 ;Value 30$: bic #40,r1 ;In case lower case cmpb r1,#'E ;/E - list error table bne 40$ inc swt.e br nexswt 40$: cmpb r1,#'L ;/L - list partition table bne 45$ inc swt.l br nexswt 45$: cmpb r1,#'X ;/X - exit after this command bne 50$ inc swt.x br nexswt 50$: cmpb r1,#'S ;/S - size the device bne 55$ inc swt.s br nexswt 55$: cmpb r1,#'C ;/C - change unit (6 or 7) bne 80$ tst r1 bmi 60$ type <#?DU-E-/C requires a value (6 or 7 only if TSX)#<0>> jmp badrun 60$: cmp r2,#7 blos 70$ type <#?DU-E-/C out of range 0 through 7#<0>> jmp badrun 70$: cmp r2,#6 bhis 75$ tst tsxloc bpl 75$ ;(RT may change anything) type <#?DU-E-/C may only change units 6 or 7 under TSX-plus#<0>> jmp badrun 75$: tst swt.c bne only1 inc swt.c mov r2,val.c br nexswt 80$: cmpb r1,#'P ;/P:n Partition for /C bne 100$ tst r1 bmi 90$ type <#?DU-E-/P must have a value specified#<0>> jmp badrun 90$: tst swt.p bne only1 inc swt.p mov r2,val.p br nexswt 100$: cmpb r1,#'U ;/U:n Unit for /C bne 120$ tst r1 bmi 110$ type <#?DU-E-/U must have a value specified#<0>> jmp badrun 110$: tst swt.u bne only1 inc swt.u mov r2,val.u br nexswt 120$: cmpb r1,#'H ;/H Help bne illswt .print #vermes .print #hmes jmp rerun illswt:: type <#?DU-E-Illegal switch /#<200>> .ttyou r1 type <#. For help type /H#<0>> jmp badrun only1: type <#?DU-E-Only one of any of /C, /P, or /U on any 1 line#<0>> jmp badrun .Dsabl lsb .Enabl lsb Endswt: tst swt.s ;Does he want the size? beq 5$ call telsiz 5$: tst swt.e ;Was /E specified? beq 10$ call typerr ;Yes - type the error table 10$: tst swt.c ;Was /C specified? beq 20$ call chgtab ;Yes - go and change the table clr swt.p ;Have used these! clr swt.u 20$: tst swt.l ;Was /L specified? beq 30$ call typtab ;Yes - go and type the table 30$: tst swt.x ;Was /X specified? beq 40$ clr r0 ;Yes - die. .exit 40$: tst swt.p ;See if naked /P or /U beq 50$ type <#?DU-E-/P requires /C to be of any use#<0>> jmp badrun 50$: tst swt.u beq 60$ type <#?DU-E-/U requires /C to be of any use#<0>> jmp badrun 60$: jmp rerun .Dsabl lsb .psect mesage con hmes: .ascii .ascii #Switches available are:# .ascii #/E type the error table# .ascii #/L type the current units and partitions# .ascii #/S type the size of the device by partitions# .ascii #/C:n change the partition/unit for logical unit n (6 or 7 only if# .ascii # TSX) used with one or both of the following switches:# .ascii #/P:n partition number# .ascii #/U:n physical unit number# .ascii #/H type this message# .byte 0 .psect program .Sbttl Get & Check Details of DU: .Enabl lsb Chkdu:: .wait #3 bcs 2$ .dstatus #area,#infil ;Gets status thereof. bcs 2$ bic #^c177,area cmp area,#50 ;Make sure it's a DU beq 3$ 2$: type <#?DU-E-DU class device not specified#<0>> jmp badrun 3$: .spfun #area,#3,#sp.sts,#ptable,#0,#0 bcc 10$ type <#?DU-E-Cannot read DU status table#<0>> jmp badrun 10$: cmp ptable,#du.ver beq 60$ type > jmp badrun 60$: .spfun #area,#3,#sp.dat,#ptable,#0,#0 ;Read partition table bcc 61$ type <#?DU-E-Cannot read DU partition table#<0>> jmp badrun 61$: .savest #area,#3,#saves bcc 62$ type <#?DU-E-Cannot save status of input file#<0>> jmp badrun 62$: .reopen #area,#3,#saves ;If this prangs, HELP! bcc 63$ type <#?DU-E-Cannot restore status of input file#<0>> jmp badrun 63$: mov #ptable,r0 ;Take a copy of the partition mov #ntable,r1 ; table to play with. mov #tabsiz,r2 100$: mov (r0)+,(r1)+ dec r2 bne 100$ return .Dsabl lsb .Sbttl List Current Partition Table Typtab: call chkdu ;Check bona fides mov ptab,r1 clr r2 call typt1 return .Enabl lsb Typt1: type > type > 10$: type > mov r2,r0 call w8t type > mov (r1)+,r0 call wdt type > mov (r1)+,r0 call wdt call tcrlf inc r2 cmp r2,#7 blos 10$ return .Dsabl lsb .Sbttl List Error Table .Enabl lsb Typerr:: call chkdu ;Check bona fides .spfun #area,#3,#sp.sts,#ptable,#0,#0 bcc 10$ type > jmp badrun 10$: mov #ptable,r1 type > mov (r1)+,r0 call w8t call tcrlf type > call type1 type > call type1 type > call type1 type > call type1 type <#Number of I/O retries: #<200>> call type1 type <#Number of I/O errors: #<200>> call type1 return type1: mov (r1)+,r0 call wdt jmp tcrlf .Sbttl Size the Device .Enabl lsb Telsiz:: call chkdu .spfun #area,#3,#sp.usz,#size,#0,#0 ;Get its size. If prangs, .error er.siz mov size,r0 ;Number of partitions = 65535 blocks beq 10$ ;None - so don't tell him anything. call wdt type > 10$: mov size+2,r1 ;Remainder beq 20$ type > mov r1,r0 call wdt type > 20$: jmp tcrlf .Dsabl lsb .Sbttl Change Partition Table .Enabl lsb Chgtab:: mov swt.u,r0 ;See that at least /U or /P specified bis swt.p,r0 bne 5$ type <#?DU-E-/C requires /P &/or /U to effect a change#<0>> jmp badrun 5$: call chkdu mov val.c,r2 ;Get pointer into ptable asl r2 asl r2 mov r2,r3 add ptab,r2 ;Partition table add ntab,r3 ;Table for checking tst swt.u bne 10$ mov (r2),val.u 10$: tst swt.p bne 20$ mov 2(r2),val.p 20$: mov val.u,(r3)+ mov val.p,(r3)+ .purge #1 ;Get a spare channel movb val.c,saves+s.devu ; accessible to DU6 or DU7 .reopen #area,#1,#saves .error er.reo .spfun #area,#3,#sp.dat,#ntable,#-1,#0 ;Re-write partition table .error er.wpt .spfun #area,#1,#sp.psz,#size,#0,#0 ;Get its size. If prangs, bcc 40$ ; invalid. .spfun #area,#3,#sp.dat,#ptable,#-1,#0 ;Go back to original for the .error er.wpt ; moment, as have pranged. type <#?DU-E-Non-existent unit/partition specified: unit #<200>> mov val.u,r0 call wdt type > mov val.p,r0 call wdt call tcrlf jmp badrun 40$: return .Dsabl lsb .Sbttl Error Routines er.dst: type > br .badr er.look:type > br .badr er.sav: type > br .badr er.reo: type > br .badr er.sts: type > br .badr er.rpt: type > br .badr er.wpt: type > br .badr er.siz: type > .badr:: call tcrlf jmp badrun .Sbttl .Sbttl Subroutines for Programme Portion - Taken from CVLLIB .Sbttl --------------------------------- .Sbttl W8T - Write an unsigned octal number to the terminal .if eq 1 Called by: mov number,r0 call w8t .endc W8T: mov r0,-(sp) bne 10$ .ttyou #'0 ;Send a zero if it is. br 40$ 10$: clr -(sp) ;Flag for when finished with stack 20$: mov r0,-(sp) clc ;In case negative ror r0 asr r0 asr r0 bne 20$ 30$: mov (sp)+,r0 beq 40$ bic #177770,r0 bis #60,r0 .ttyou br 30$ 40$: mov (sp)+,r0 return .Sbttl WDT - Write a signed or unsigned decimal number to the terminal .If eq 1 Called by: mov number,r0 call wdt .endc DECTAB: .WORD 10.,100.,1000.,10000.,-1 WDT: mov r0,-(sp) bge 10$ mov #'-,r0 movb r0,(r1)+ mov (sp),r0 neg r0 bic #100000,r0 10$: mov r3,-(sp) mov r2,-(sp) mov r0,r2 clr -(sp) mov #dectab,r3 20$: cmp r0,(r3) ;Compare value with subtractors blo 40$ mov (r3)+,-(sp) ;Stack next subtractor if relevant tst (r3) bpl 20$ 40$: mov (sp)+,r3 ;Get next subtractor beq 70$ ;Last one zero, in case number = 0. mov #60,r0 ;Initalize digit 50$: sub r3,r2 blt 60$ inc r0 br 50$ 60$: add r3,r2 .ttyou br 40$ 70$: add #60,r2 mov r2,r0 .ttyou mov (sp)+,r2 mov (sp)+,r3 mov (sp)+,r0 return .Sbttl TCRLF Teletype routine for VT100 esc=33 TCRLF: ;Print a carriage-return line-feed mov r0,-(sp) .print #nul mov (sp)+,r0 return .psect mesage con nul: .byte 0 .psect program .Sbttl TLOUB - Output Buffer for TT output TLOUB: .blkb 140. ;Allow for a printer line .Sbttl ------------------------------- .Sbttl .Sbttl MSCP Protocol Definitions .Sbttl . Control Message Opcodes OP.ABO ==: 1 ;ABORT OP.ACC ==: 20 ;ACCESS OP.AVL ==: 10 ;AVAILABLE OP.CMP ==: 40 ;COMPARE HOST DATA OP.DAP ==: 13 ;DETERMINE ACCESS PATHS OP.ERS ==: 22 ;ERASE OP.GCS ==: 2 ;GET COMMAND STATUS OP.GUS ==: 3 ;GET UNIT STATUS OP.ONL ==: 11 ;ONLINE OP.RD ==: 41 ;READ OP.RPL ==: 24 ;REPLACE OP.SCC ==: 4 ;SET CONTROLLER CHARACTERISTICS OP.SUC ==: 12 ;SET UNIT CHARACTERISTICS OP.WR ==: 42 ;WRITE OP.END ==: 200 ;End message flag (added to opcode & returned) OP.SEX ==: 7 ;Serious Exception end message OP.AVA ==: 100 ;AVAILABLE Attention Message OP.DUP ==: 101 ;DUPLICATE UNIT NUMBER Attention Message OP.ACP ==: 102 ;ACCESS PATH Attention Message .Sbttl . Command Modifiers ;Generic Command Modifiers ------------- MD.CMP ==: 40000 ;Compare MD.EXP ==: 100000 ;Express Request MD.ERR ==: 10000 ;Force Error MD.SEC ==: 1000 ;Suppress Error Correction MD.SER ==: 400 ;Suppress Error Recovery ;AVAILABLE Command Modifiers ------------- MD.ALL ==: 2 ;All Class Drivers MD.SPD ==: 1 ;Spin down ;GET UNIT STATUS Command Modifier ------------- MD.NXU ==: 2000 ;Next Unit ;ONLINE Command Modifiers ------------- MD.RIP ==: 1 ;Allow Self-Destruction MD.IMP ==: 2 ;Ignore Media Format Error ;ONLINE and SET UNIT CHARACTERISTICS Command Modifier ------------- MD.SWP ==: 4 ;Enable Set Write Protect ;REPLACE Command Modifier ------------- MD.PRI ==: 1 ;Primary Replacement Block .Sbttl . End Message Flags EF.BBR ==: 200 ;Bad Block Reported EF.BBU ==: 100 ;Bad Block Unreported EF.LOG ==: 40 ;Error Log Generated .Sbttl . Unit Flags UF.CMR ==: 1 ;Compare Reads UF.CMW ==: 2 ;Compare Writes UF.RMV ==: 200 ;Removable Media UF.WPH ==: 20000 ;Write Protect (hardware) UF.WPS ==: 10000 ;Write Protect (software) UF.576 ==: 4 ;576 byte sectors .Sbttl . Controller Flags CF.ATN ==: 200 ;Enable Attention Messages CF.MSC ==: 100 ;Enable Miscellaneous Error Log Messages CF.OTH ==: 40 ;Enable Other Host's Error Log Messages CF.THS ==: 20 ;Enable This Host's Error Log Messages CF.576 ==: 1 ;576 byte sectors .Sbttl . Status and Event Codes ST.MSK ==: 37 ;Status / Event Code Mask ST.SUB ==: 40 ;Sub-Code Multiplier ST.SUC ==: 0 ;Success ST.CMD ==: 1 ;Invalid Command ST.ABO ==: 2 ;Command Aborted ST.OFL ==: 3 ;Unit Offline ST.AVL ==: 4 ;Unit Available ST.MFE ==: 5 ;Media Format Error ST.WPR ==: 6 ;Write Protected ST.CMP ==: 7 ;Compare Error ST.DAT ==: 10 ;Data Error ST.HST ==: 11 ;Host Buffer Access Error ST.CNT ==: 12 ;Controller Error ST.DRV ==: 13 ;Drive Error ST.DIA ==: 37 ;Message from an Internal Diagnostic .Sbttl . Command Message Offsets P.CSIZ ==: 60 ;Minimum size of Command Buffer ;(Size) (Description) P.CRF ==: 0 ;4 Command reference number P.UNIT ==: 4 ;2 Unit number ;2 (6=reserved) P.OPCD ==: 10 ;1 Opcode ;1 (11=reserved) P.MOD ==: 12 ;2 Modifiers P.BCNT ==: 14 ;4 Byte count P.BUFF ==: 20 ;12 Buffer descriptor (here 4 byte addr lo first) P.LBN ==: 34 ;4 Logical Block Number P.PART ==: 36 ;(hi-ord word of logical block number) ;ABORT and GET COMMAND STATUS Command Message Offset: ------------- P.OTRF ==: 14 ;4 Outstanding Reference Number ;ONLINE and SET UNIT CHARACTERISTICS Command Message Offsets: ------------- ;2 (14=reserved) P.UNFL ==: 16 ;2 Unit Flags ;12 (20=reserved) P.DVPM ==: 34 ;4 Device dependent parameters ;REPLACE Command Message Offset: ------------- P.RBN ==: 14 ;4 Replacement block number ;SET CONTROLLER CHARACTERISTICS Command Message Offsets: ------------- P.VRSN ==: 14 ;2 MSCP version (must be zero?) P.CNTF ==: 16 ;2 Controller flags P.HTMO ==: 20 ;2 Host timeout TO.MIN == 0 ; Minutes to time out - zero for us. ;2 (22=reserved) P.TIME ==: 24 ;8 Quad-word time & date .Sbttl . End & Attention Message Offsets P.MSIZ ==: 60 ;Minimum Message Buffer Size ;(Size) (Description) P.CRF ==: 0 ;4 Command Reference Number P.UNIT ==: 4 ;2 Unit Number ;2 (6=reserved) P.OPCD ==: 10 ;1 Opcode/Endcode P.FLGS ==: 11 ;1 End Message Flags P.STS ==: 12 ;2 Status P.BCNT ==: 14 ;4 Byte Count ;12 (20=reserved) P.FBBK ==: 34 ;4 First Bad Block ;ABORT and GET COMMAND STATUS Message Offset: ------------- P.OTRF ==: 14 ;4 Outstanding Reference Number ;GET COMMAND STATUS End Message Offset: ------------- P.CMST ==: 20 ;4 Command Status ;GET UNIT STATUS End Message Offsets: ------------- P.MLUN ==: 14 ;2 Multi-Unit Code P.UNFL ==: 16 ;2 Unit Flags ;4 (20=reserved) P.UNTI ==: 24 ;8 Unit Identifier P.MEDI ==: 34 ;4 Media Type Identifier P.SHUN ==: 40 ;2 Shadow Unit P.TRCK ==: 44 ;2 Track Size P.GRP ==: 46 ;2 Group Size P.CYL ==: 50 ;2 Cylinder Size ;2 (52=reserved) P.RCTS ==: 54 ;2 RCT Table Size P.RBNS ==: 56 ;1 RBN's per Track P.RCTC ==: 57 ;1 RCT Copies ;ONLINE and SET UNIT CHARACTERISTICS End Message and AVAILABLE ; Attention Message Offsets: ------------- P.MLUN ==: 14 ;2 Multi-Unit Code P.UNFL ==: 16 ;2 Unit Flags ;4 (20=reserved) P.UNTI ==: 24 ;8 Unit Identifier P.MEDI ==: 34 ;4 Media Type Identifier P.UNSZ ==: 44 ;4 Unit Size P.VSER ==: 50 ;4 Volume Serial Number ;SET CONTROLLER CHARACTERISTICS End Message Offsets: ------------- P.VRSN ==: 14 ;2 MSCP Version P.CNTF ==: 16 ;2 Controller Flags P.CTMO ==: 20 ;2 Controller Timeout ;2 (22=reserved) P.CNTI ==: 24 ;8 Controller ID .Sbttl . Error Log Message Offsets ;(Size) (Description) L.CRF ==: 0 ;4 Command Reference Number L.UNIT ==: 4 ;2 Unit Number L.SEQ ==: 6 ;2 Sequence Number L.FMT ==: 10 ;1 Format L.FLGS ==: 11 ;1 Error Log Message Flags L.EVNT ==: 12 ;2 Event Code L.CNTI ==: 14 ;8 Controller ID L.CSVR ==: 24 ;1 Controller Software Version L.CHVR ==: 25 ;1 Controller Hardware Version L.MLUN ==: 26 ;2 Multi-Unit Code L.UNTI ==: 30 ;8 Unit ID L.USVR ==: 40 ;1 Unit Software Version L.UHVR ==: 41 ;1 Unit Hardware Version ;2 (Format dependent) L.VSER ==: 44 ;4 Volume Serial Number ;Host Memory Access Errors with Bus Address Error Log ; Message Offset: ------------- L.BADR ==: 30 ;4 Bus Address ;Disc Transfer Errors Error Log Message Offsets: ------------- L.LVL ==: 42 ;1 Level L.RTRY ==: 43 ;1 Retry L.VSER ==: 44 ;4 Volume Serial Number L.HDCD ==: 50 ;4 Header Code ;SDI Errors Error Log Message Offsets: ------------- L.HDCD ==: 50 ;4 Header Code L.SDI ==: 54 ;12 SDI Information .Sbttl . Error Log Message Format Codes FM.CNT ==: 0 ;Controller Errors FM.BAD ==: 1 ;Host Memory Access Errors with Bus Address FM.DSK ==: 2 ;Disc Transfer Errors FM.SDI ==: 3 ;SDI Errors .Sbttl . Error Log Message Flags LF.SUC ==: 200 ;Operation Successful LF.CON ==: 100 ;Operation Continuing LF.SNR ==: 1 ;Sequence Number Reset .Sbttl UDA Port Definitions OWN ==: 100000 ;Set in header if owned by controller FLAG ==: 40000 ;Set on return from controller; host to clear if don't ; want interrupts from action being requested. .Sbttl . Initialization Values & Parameters ;During initialization: flags for SA register: ;Step 1 - returned in SA after any value inserted into IP ISTEP1 ==: 4000 ;Initialization step 1 NV ==: 2000 ;Set if port does not support host-settable vector QB ==: 1000 ;Set if Q-bus DI ==: 400 ;Set if port implements enhanced diagnostics ;Step 2 - sent to SA STEP ==: 200 ;Gawd knows why this is defined with this name! ; 100000 - Used as the high-order bit, high byte, always set WR ==: 40000 ;Set if want DIAGNOSTIC WRAP MODE (& DI set) ; 34000 Mask for command ring length - # slots, as power of 2 ; 3400 Mask for response ring, ibid IE ==: 200 ;Allow interrupts during initialization ; 177 Vector address/4 ;Step 2 - returned in SA ISTEP2 ==: 10000 ;Initialization step 2 ; 3400 Port Type No ( = 0 ) ; 200 Set ; 100 Set if WR set ; 70 Mask of command ring length ; 7 Mask of response ring length ;Step 3 - sent to SA ; 177776 Low-order address of base of "ring" PI ==: 1 ;Set if host needs Unibus adapter purge interrupts ;Step 3 - returned in SA ISTEP3 ==: 20000 ;Initialization step 3 ; 200 If IE set ; 177 Interrupt vector/4 ;Step 4 - sent to SA PP ==: 100000 ;Set if requesting execution of purge & poll tests ; (only valid if DI=1) ; 77777 Ringbase high address ;Step 4 - returned in SA ISTEP4 ==: 40000 ;Initialization step 4 ; 377 Control Code Version ;Step 5 - sent to SA ; 177400 (reserved) BURST ==: 374 ;1 less than max # long words host is willing to allow ; per DMA transfer. .LF ==: 2 ;Send LAST FAIL response packet at end of init ; (define with "." as lf usu means ) GO ==: 1 ;Enter functional controller microcode when init done ;(If IE set, interrupts may occur after steps 2, 3, and 4) ISTEPS ==: 74000 ;Mask of all init steps .end start