.Title MDDRV - P/OS Memory Disk Driver .Ident /V02.07/ ; Version information ; ; Copyright ()) 1986 ; Prolifix, Inc., Frankfort, Kentucky ; ; This software is made available to any user of a Digital Equipment ; Corporation Professional 300 series computer without charge. You may ; distribute, modify, and use this software as long this copyright ; notice is included and you do not charge anything beyond the cost of ; duplication. Title to and ownership of the software shall at all ; times remain with Prolifix, Inc. ; ; No committment for support or development of this software is implied ; or intended. No responsibility for the use or reliability of this ; software shall be assumed. ; ; JWE001 X01.01 Jerry W. Ethington 20-Feb-85 ; Use P/OS V2.0 executive vectoring scheme to make MDDRV ; relatively version independent. ; ; JWE002 X01.02 Jerry W. Ethington 25-Feb-85 ; Make a parametric subroutine to handle prompts. ; ; JWE003 X01.03 Jerry W. Ethington 09-Mar-85 ; Use executive routine $SRNAM to save some code. ; ; JWE004 X02.00 Jerry W. Ethington 01-Aug-85 ; Rewrite into a normal device driver loaded by PROLOD. Make ; executive vectoring code execute at driver load time at the ; $MDLOA entry point. ; ; JWE005 X02.01 Jerry W. Ethington 17-Dec-85 ; Make sure our common is nailed down tight by incrementing ; I/O count and clearing the "beat me" bit in the PCB. ; ; JWE006 X02.02 Jerry W. Ethington 31-Dec-85 ; Allocate a UCB extension since we are a mass storage device. ; This allows tracking I/O counts with RMD and may be required for ; P/OS V3 and Pro Clusters, if the memory disk should be ; transparently available to a workstation in the cluster. ; ; JWE007 X02.03 Jerry W. Ethington 14-Feb-86 ; Relocate SYSCM references at load time rather than at run time. ; ; JWE008 X02.04 Jerry W. Ethington 8-Mar-86 ; Lose code that increments I/O count to our region - it doesn't ; seem to be necessary. ; ; X02.05 Jerry W. Ethington 06-May-1986 18:22:13 ; V3 Toolkit is finally here! Add code to allow unload of ; driver and kill off dynamic region on offline request. ; ; V02.06 Jerry W. Ethington 16-May-1986 19:07:01 ; Add code to zero fill blocks that are partially written. ; ; V02.07 Jerry W. Ethington 26-May-1986 23:22:46 ; Install warp drive in zero fill code. Use a vector of MOVs to ; clear the remainder of the block instead of a CLR/SOB loop. ; .Sbttl Definitions Xlen = 2*512. ; Transfer size in bytes before checking ; fork list - this should be a power of ; 2 times 512. N$$Mov = 32. ; Size of zero fill vector (words) .Sbttl MDIni - I/O Initialization DDT$ MD,,None,,,New ; Generate Dispatch Table MDKrb: MDOut: MDPwf: MDCan: Return ; Nop ;+ ; MDIni - I/O Initialization Entry Point ; ; Inputs: ; ; R5 => UCB of the unit a packet is queued for ; ;- MDIni: Call @Gtpkt ; Get next packet Bcc 10$ ; Got one Return ; None left, return to exec ; ; The following arguments are returned by $GTPKT: ; ; R1 => I/O packet ; R2 = Physical unit number of the device to process ; R3 = Controller index ; R4 => SCB ; R5 => UCB ; ; I/O Request Packet Format ; ; I.Lnk -- I/O queue thread word. ; I.Pri/I.Efn -- Request priority, Event flag number. ; I.Tcb -- Address of the TCB of the requester task. ; I.Ln2 -- Pointer to second LUN word in requester task ; header. ; I.Ucb -- UCB address of device. ; I.Fcn -- I/O function code (Io.Rlb or Io.Wlb). ; I.Iosb -- Virtual address of I/O status block. ; I.Iosb+2 -- Relocation bias of I/O status block. ; I.Iosb+4 -- I/O status block address (displacement + 140000). ; I.Ast -- Virtual address of AST service routine. ; I.Prm -- Relocation bias of user buffer. ; I.Prm+2 -- Buffer address of I/O transfer. ; I.Prm+4 -- Number of bytes to be transfered. ; I.Prm+6 -- Not used. ; I.Prm+10 -- High byte not used, Low byte = high order byte of ; LBN. ; I.Prm+12 -- Logical block number of I/O request. ; I.Prm+14 -- Not used. ; I.Prm+16 -- Not used. ; 10$: Call @Volvd ; Validate Volume Valid Bcs Iodone ; Failed Tst R0 ; Check for a transfer function Bpl Iodone ; Not a transfer, exit Mov U.Cnt(R5),Savcnt ; Save byte count of transfer Mov #Ie.Ifc&377,R0 ; Assume we will flunk Cmpb I.Fcn+1(R1),#Io.Rlb/256. ; Better be a read or lower Bhi Iodone ; Wasn't - die horribly Movb I.Fcn+1(R1),Savfnc ; Save I/O function code Call @Blkck ; Range check the LBN Ash #3,R0 ; Convert LBN to memory blocks (32W) Add Rgbias,R0 ; Get physical APR bias of transfer Cmpb #Io.Wlb/256.,Savfnc ; Was this a write? Bne 20$ ; If NE, it is a read ; ; IO.WLB serviced here ; Mov U.Buf(R5),R1 ; Set up source APR 5 bias Mov U.Buf+2(R5),R2 ; Get the source APR 6 displacement Sub #20000,R2 ; Force to APR 5 displacement Mov R0,R3 ; Set up destination APR 6 bias Mov #140000,R4 ; Set up destination APR 6 displacement Br 30$ ; Enter loop ; ; Reads serviced here ; 20$: Mov R0,R1 ; Set up source APR 5 bias Mov #120000,R2 ; Set up source APR 5 displacement Mov U.Buf(R5),R3 ; Set up destination APR 6 bias Mov U.Buf+2(R5),R4 ; Set up destination APR 6 displacement .Sbttl Transfer Code 30$: Mov U.Cnt(R5),R0 ; Get byte count of transfer Beq Xfrdon ; Nothing left, all done Cmp R0,#Xlen ; More than one transfer block left? Blos 40$ ; No, continue Mov #Xlen,R0 ; Yes, move one block this trip 40$: Sub R0,U.Cnt(R5) ; Decrement transfer length Mov R2,-(SP) ; Save source displacement Mov R4,-(SP) ; And destination displacement Call @Blxio ; Do the move Mov (SP)+,R4 ; Restore destination displacement Add #Xlen/64.,R3 ; Increment destination APR6 bias Mov (SP)+,R2 ; Restore source displacement Add #Xlen/64.,R1 ; Increment source APR5 bias Tst @Frkhd ; Anyone waiting to fork ? Beq 30$ ; No, move more data ; ; At this point, we want to re-fork to let other fork processes run a ; while. Since $Fork preserves only R4-R5, we need to save R1-R3 ; ourselves without using the stack, which is a restriction of using ; $Fork. ; Mov R1,U.Buf(R5) ; Save source APR 5 bias Mov R2,U.Buf+2(R5) ; Save source APR 5 displacement Mov R3,Savdst ; Save destination APR 6 bias Call @Fork ; Relinquish the CPU Mov U.Buf(R5),R1 ; Restore R1-R3 Mov U.Buf+2(R5),R2 ; ... Mov Savdst,R3 ; ... Br 30$ ; Do the next block .Sbttl Transfer Completion ; ; Common Finish ; Xfrdon: Cmpb Savfnc,#Io.Wlb/256. ; Was this a write? Bne 10$ ; If NE, no - skip all this Bit #777,Savcnt ; Did we write a partial block? Beq 10$ ; If EQ, no - skip this Call Fillbk ; Yes - zero out rest of block 10$: Mov #Is.Suc,R0 ; Load I/O status code ; ; Finish up this request and look for more work ; Iodone: Mov Savcnt,R1 ; R1 = bytes requested Sub U.Cnt(R5),R1 ; Subtract bytes remaining Clr R2 ; Clear error counts Mov R5,Savcnt ; Save R5 around Iodon Call @Iodon ; Finish this request Mov Savcnt,R5 ; Get back R5 Br MDIni ; Get the next request ; ; Fillbk - zero fill the remainder of a partial block write. We still ; have the following useful information in registers as input: ; ; R3 = APR 6 bias ; R4 = APR 6 displacement ; R5 => UCB ; Fillbk: Sub #Xlen/64.,R3 ; Back up to start of last transfer Mov Savcnt,R0 ; R0 = byte count of transfer Bic #^C,R0 ; Isolate size of last transfer 10$: Cmp R0,#512. ; At least one block left? Ble 20$ ; No, we have the partial block Sub #512.,R0 ; Yes, decrement size of transfer Add #512./64.,R3 ; Increment APR bias Br 10$ ; Loop 20$: Add R0,R4 ; Point to word after partial write Sub #512.,R0 ; Make negative byte count for fill Neg R0 ; Positate it Mov @Isar6,-(SP) ; Save Kisar6 Mov R3,@Isar6 ; Map to our region Clr R1 ; Get a zero word for move vector 30$: Sub #,R0 ; Subtract vector size from byte count Bcc 40$ ; If CC, move an entire vector Sub R0,PC ; Skip right amount of vector 40$: .Rept N$$Mov ; This many moves in vector Mov R1,(R4)+ ; Move zero to next word .Endr Bcc 30$ ; If CC, it wasn't our last trip Mov (SP)+,@Isar6 ; Restore mapping Return ; All done Savfnc: .Blkw 1 ; Saved I/O function code Savcnt: .Blkw 1 ; Saved transfer byte count Savdst: .Blkw 1 ; Saved destination APR 6 bias .Sbttl Driver Online/Offline Code ; ; MDUCB is called when attempting to bring the unit online/offline. If ; we detected at load time a mismatch in the versions of executive ; routines we use, then we refuse all online requests. Otherwise, if ; request is for online, check for the presence of partition MDCOM and ; use that as our disk. Set up the UCB accordingly. If request is ; offline, release our meathooks from the partition so it can be ; deallocated. ; ; Input: ; R5 -> Ucb ; R4 -> Scb ; R3 = Controller Index ; Output: ; UCB updated ; MDUcb: Ror (SP) ; Save C bit on stack - this depends on ; having an even return address on ; stack, a reasonable assumption Tstb Okvect ; Did load detect errors? ; (This also clears C bit so we shift in ; a 0 for upcoming ROLs) Bgt 10$ ; If GT, no Rol (SP) ; Yes! Fix return address Movb Okvect,@Scerr ; Store error from load Return ; Lose big bub 10$: Rol (SP) ; No errors, get back C bit Bcs 100$ ; If CS, we want to go offline Mov #Comnam,R3 ; R3 => Rad50 Name of our common Call @Srnam ; Find our common Bcs 50$ ; If CS, we couldn't find it Mov P.Size(R2),R0 ; R0 = Partition size in 32 word blocks Ash #-3,R0 ; Convert memory blocks to disk blocks Mov R0,U.Cw3(R5) ; Set device size Mov P.Rel(R2),Rgbias ; Set base address Bis #Ps.Chk!Ps.Fxd!Ps.Nsf,P.Stat(R2) ; Set -CHK FXD NSF Bic #Ps.Del,P.Stat(R2) ; Clear the delete bit Bic #P2.Lma,P.St2(R2) ; Clear the "beat me" bit ; ; The following code to properly set up a UCB extension is cheerfully ; ripped off from RSX-11M+ HRSIZ.MAC. If we are unable to grab a chunk ; of secondary pool for the extension to live in, we will ignore the ; error - error logging and seek optimization will not be available, but ; P/OS doesn't use them anyway. I don't really know what effect this ; would have in a PRO/Server environment, but the failure should be a ; VERY rare event, so it probably isn't worth losing sleep over. ; Mov @Isar6,-(SP) ; Save KISAR6 mapping Mov U.Ucbx(R5),@Isar6 ; UCB extension already present? Bne 20$ ; If so, don't take another one Mov #/100,R1 ; Get length of a UCB extension Call @Alsec ; Allocate it Bcs 40$ ; If we couldn't, give up Mov R0,@Isar6 ; Map our new UCB extension 20$: Mov #</100>*32.,R1 ; R1 = size in words to clear Mov #140000,R2 ; R2 => UCB extension 30$: Clr (R2)+ ; Clear out UCB extension Sob R1,30$ ; Loop Movb #X.Dfhl,@#X.Erhl+140000 ; Initialize hard error limit Movb #X.Dfsl,@#X.Ersl+140000 ; Initialize soft error limit Movb #X.Dffl,@#X.Flim+140000 ; Initialize fairness count Mov #^RMEM,@#X.Name+140000 ; Set device name Mov #^RORY,@#X.Name+2+140000 ; ... Mov @Isar6,U.Ucbx(R5) ; Point UCB at extension 40$: Mov (SP)+,@Isar6 ; Restore APR 6 mapping Return ; Then exit 50$: Movb #Ie.Dnr&377,@Scerr ; Store return code Return ; Lose big, bud ; ; Code to take us offline - we need to reverse the actions of the online ; code by unfixing the region, releasing the UCB extension, etc. I ; would like to actually delete the region, but guess what - the $DELRG ; entry point isn't vectored! Rather than introduce a version problem ; when the address of $DELRG moves, we'll just set the "beat me" bit ; again and have to settle for letting the next atomic blast when the ; user leaves an application zap the darned thing. If you are in the ; toolkit, you can just do a Remove/Region Mdcom and that will get rid ; of it without leaving the tool kit. ; 100$: Mov #Comnam,R3 ; R3 => Rad50 name of our common Call @Srnam ; Find it Bcs 110$ ; If CS, couldn't (shouldn't happen) Bic #Ps.Chk!Ps.Fxd!Ps.Nsf,P.Stat(R2) ; Clear -CHK FXD NSF Bis #Ps.Del,P.Stat(R2) ; Set the delete bit Bis #P2.Lma,P.St2(R2) ; Set the "beat me" bit 110$: Mov U.Ucbx(R5),R0 ; R0 => UCB extension Beq 120$ ; Might not be one Mov #/100,R1 ; R1 = length in MMUs Call @Desec ; Return extension to secondary pool Clr U.Ucbx(R5) ; We don't have a UCB extension now 120$: Return ; All done Comnam: .Rad50 /MDCOM / ; Name of our common Rgbias: .Blkw 1 ; APR bias of our region .Sbttl Load Time Driver Initialization ; ; $MDLOA validates executive subroutine calls and sets up the addresses ; needed. If any subroutine used has an incompatible version, an error ; is stored and the driver will later refuse to go online. ; $MDLOA::Tst Okvect ; Have we already initialized? Bne 50$ ; If NE, yes - don't do it again Mov #Ie.Ice&377,Okvect ; No - assume we will fail Mov @#$Vecsc,R0 ; R0 => $Cmbeg Bit #F2.Das,$Fmask+2-$Cmbeg(R0) ; On a Kernel Dspace exec? Beq 10$ ; Nope, use Kinar6 Mov #Kdsar6,Isar6 ; Yes - use Kdsar6 10$: Mov #Cmtab,R0 ; R0 => table of SYSCM addresses Mov #Cmlen,R1 ; R1 = number of addresses to relocate 20$: Add @#$Vecsc,(R0)+ ; Relocate address Sob R1,20$ ; All of them Mov @Isar6,-(SP) ; Save APR6 mapping Mov @#$Vecvt,@Isar6 ; Map executive vector table Mov @#$Vecvt+2,R0 ; R0 => vector table Mov -2(R0),R5 ; R5 = number of vectors available Mul #6,R5 ; R5 = length of table in bytes Mov #Exevec,R1 ; R1 => table to be relocated Mov #Veclen,R4 ; R4 = no. of entries in table 30$: Cmp (R1),R5 ; Beyond end of exec vector? Bhi 40$ ; If HI, yes, incompatible version Mov (R1),R2 ; Get offset to examine Add R0,R2 ; R2 => entry in exec vector Mov (R2),(R1)+ ; Save address of exec routine Cmp 4(R2),(R1)+ ; Compatible version of routine? Bne 40$ ; If NE, no, barf Sob R4,30$ ; Loop through table Mov #Is.Suc&377,Okvect ; Flag we won big 40$: Mov (SP)+,@Isar6 ; Restore APR6 mapping 50$: Return ; All done ; ; The table of exec routines to be relocated consists of two word ; entries, .Word offset, version. ; Okvect: .Word 0 ; Flag not initialized Exevec:: Alsec: .Word Alsec$, 1 Blkck: .Word Blkck$, 1 Blxio: .Word Blxio$, 1 Desec: .Word Desec$, 1 Fork: .Word Fork$, 1 Gtpkt: .Word Gtpkt$, 1 Iodon: .Word Iodon$, 1 Srnam: .Word Srnam$, 1 Volvd: .Word Volvd$, 1 Veclen = <. - Exevec>/4 ; ; Now let's have some words in SYSCM that need to be relocated. We will ; enter them as a displacement from $CMBEG and add the value of $CMBEG ; to them at load time. ; Cmtab:: Frkhd: .Word $Frkhd-$Cmbeg Scerr: .Word $Scerr-$Cmbeg Cmlen = <. - Cmtab>/2 Isar6:: .Word Kinar6 ; Address of Kisar6 .End