.TITLE SLDRV Memory Disk Driver .IDENT /X01.20/ ; Experimental .ENABL LC ; Enable lower case .SBTTL Introduction ; ; SLDRV - M+ Memory Resident Disk Driver for System Libraries ; RX01 Emulator Version ; ; Companion source file to SLPRE.MAC and SLDAT.MAC ; Authors: ; Bruce R. Mitchell ; Michael J. Lynch ; ; Patterned from the DKDRV Cartridge Disk driver distributed by ; Digital Equipment Corporation on RSX-11M-Plus V1.0 Autopatch E ; Source Site: ; Engineering Systems and Technology Laboratory ; 3M Company, 3M Center, St. Paul, Minnesnota 55144 ; Source Hardware and Operating System: ; DEC PDP-11/70 under RSX-11M-Plus V1.0 Autopatch E ; Target Site: ; Same ; Target Hardware and Operating System: ; Same ; Revision History: ; 27-Dec-81 Cancel entry point added to resolve MOUNT problem ; 29-Dec-81 Corrections made to packet release IE.xxx error codes ; 18-Mar-82 Inclusion of BLX64K routine from mailbox driver .PAGE .SBTTL Description and Philosophy 101 ; ; Problem: On most development systems, a major slowdown in ; task building and assembling programs is the rotational latency ; of the system disk drive(s) when accessing system libraries. On ; a development system with more than 15 or so users, disk accesses ; can greatly degrade the potential speed of assembling and ; building over that which could be obtained if disk accesses to ; libraries could be performed at memory-to-memory speeds. ; ; One newly developed potential solution to this problem is to ; add a semiconductor or core disk emulator to the system for ; storage of work files and system libraries. This effectively ; solves the problem, but has the drawback that these devices are ; very costly. ; ; With the increasing popularity of the 22-bit DEC PDP-11 ; machines (the PDP-11/23-Plus, PDP-11/44, PDP-11/70, and ; especially the remarkable PDP-11/74) and the constantly ; decreasing cost of main memory, it is no longer ridiculous to ; consider storing libraries and workfiles in main memory in a ; special partition. If SYSLIB is 400 disk blocks, then only 200K ; byte of main memory is required to store it in a "memory resident ; disk". ; ; On the 11/70, typically with 500K word or more of main ; memory, the sacrifice of 100K word for a memory resident disk is ; not impossible, and is quite a bit cheaper than a disk emulator. ; ; This driver is aimed at the problem of emulating a memory ; resident disk for system libraries. Please, do not ask if you ; can speed up checkpointing by keeping your checkpoint files on it ; too. If you do, we shall be forced to hang you up by your thumbs ; and leave you to dry. ; ; Our thanks to Ralph Stamerjohn's lecture at the Fall 1981 ; DECUS symposium for the idea, and to a real smoooooth bottle for ; the implementation of it. ; .PAGE .SBTTL Caveats and Warnings ; ; The memory resident disk driver will give up if it cannot find ; its data partition. ; ; This driver has been known to crash the system under the following ; condition: Trying to MOUnt an unINItialized resident disk. This ; problem does not always occur in this situation, and is believed to ; be caused by garbage found in the home block of the disk. ; ; Some of the error codes returned may be peculiar. These codes ; are returned in the following cases: ; .PAGE .SBTTL System Routine Descriptions ; $BLXIO - Move Block of Data ; ; This routine will move up to 4K words (8K bytes) of data by using ; the APR5 and APR6 mapping registers. The 4K limit is due to the ; window size of an APR. ; ; Inputs: R0 - number of BYTES to move ; R1 - Source APR5 bias ; R2 - Source Displacement ; R3 - Destination APR6 bias ; R4 - Destination displacement ; ; Outputs: R0 is destroyed ; R1, R3, R5 are preserved ; R2, R4 point to last byte of source and destination + 1 ; If R0 is out of range, nothing is changed and it returns ; $GTPKT - Get a QIO I/O Packet ; ; Inputs: R5 - Address of the controller UCB to get a packet for ; ; Outputs: R1 - Address of the QIO packet ; R2 - Physical unit number of the target device ; R3 - Controller index ; R4 - Address of the Status Control Block ; R5 - Address of the Unit Control Block ; ; Carry set - No packet available ; Carry clear - Packet available ; $IOALT - I/O Done (Alternate Entry) ; $IODON - I/O Done ; ; Inputs: R0 - First I/O status word ; R1 - Second I/O status word ; R2 - Starting, final err retry counts (errlogging devices) ; R5 - Address of UCB for the unit being completed ; (SP) - Return address to driver's caller ; ; Outputs: Unit and controller are set idle ; R3 - address of the current I/O packet ; R4 - Destroyed ; ; If entry was at $IOALT, then R1 is cleared to signify that the ; second I/O status word is zero. ; $SRNAM - Search for named partition ; ; Inputs: R3 - Pointer to double-word RAD50 partition name ; ; Outputs: Carry set - No match on name ; ; Carry clear - Named partition found ; R2 - PCB address ; $VOLVD - Preprocess volume valid function ; ; This routine determines if the volume valid bit should be set or ; cleared. If the function code is not IO.STC (Set volume valid), ; the volume valid bit is tested to see if a transfer function can ; be issued. ; ; Inputs: R1 - Address of QIO packet ; I.PRM Always zero ; I.PRM+2 0 to reset volume valid bit ; 1 to set volume valid bit ; 2 to reset volume valid and spin drive down ; 3 to set volume valid and spin drive up ; -1 to size the disk (volume valid not changed) ; I.PRM+4 Reserved for port specification ; R5 - Address of the Unit Control Block ; ; Outputs: Carry set - Function rejected ; R0 - I/O error code ; ; Carry clear - Volume valid bit was set or cleared ; R0 - IS.SUC&377 if function code is IO.STC ; R0 - -1 if a transfer function ; .PAGE .SBTTL QIO Format ; ; DX Memory Resident Disk QIO Packet Format ; ; Packet RSX Functional ; Offset Name Description ; ------ ---- ------------ ; Word 00 I.LNK I/O queue thread word ; Byte 02 I.PRI Request priority ; Byte 03 I.EFN Event flag number ; Word 04 I.TCB Address of the TCB of the requesting task ; Word 06 I.LN2 Address of second LUN word in requesting task header ; Word 10 I.UCB Address of the redirect UCB ; Byte 11 +1 I/O function code modifier byte ; Byte 12 I.FCN I/O function code ; Word 14 I.IOSB Virtual address of I/O status block ; Word 16 +2 Relocation bias of I/O status block ; Word 20 +4 I/O status block address (Real or displacemt+140000) ; Word 22 I.AST Virtual address of AST service routine ; Word 24 I.PRM Relocation bias of data buffer ; Word 26 +2 Buffer address of I/O transfer ; Word 30 +4 Number of bytes to be transferred ; Word 32 +6 Unused ; Word 34 +10 Low byte must be zero; high byte is unused ; Word 36 +12 Logical or physical block number of I/O request ; Word 40 I.AADA Attachment descriptor pointer ; Word 42 +2 Attachment descriptor pointer ; .PAGE .SBTTL .SBTTL Macro Calls and Definitions ; ; System Directive Macros from LB:[1,1]EXEMC.MLB ; .MCALL HWDDF$ ; Define hardware reg symbols .MCALL PKTDF$ ; Define I/O packet offsets .MCALL DCBDF$ ; Define Device Ctrl Block offsets .MCALL SCBDF$ ; Define Status Ctrl Block offsets .MCALL UCBDF$ ; Define Unit Ctrl Block offsets .MCALL PCBDF$ ; Define Partition Ctrl Block offsets HWDDF$ PKTDF$ DCBDF$ SCBDF$ UCBDF$ PCBDF$ ; ; Error Definition Macros from LB:[1,1]RSXMAC.SML ; .MCALL QIOSY$ ; Define system QIO error codes .MCALL DRERR$ ; Define directive QIO error codes QIOSY$ DRERR$ .PAGE .SBTTL Dispatch Tables ; Driver Dispatch Table ; ; Device mnemonic is DX ; Number of controllers is 1 ; No interrupt entry point (memory resident disks don't have any) ; I/O initiation entry point is DXINI ; No space allocated for table of UCB addresses (we only allow one unit) ; Controller and unit status change entry points defined .LIST MEB ; Turn on macro expansion DDT$ DX, 1, NONE,,, NEW .NLIST MEB ; Turn off macro expansion .PAGE .SBTTL Local Data Storage ; Resident disk partition name PARNAM: .RAD50 /RESDSK/ ; Partition name is RESDSK .PAGE .SBTTL .SBTTL DXINI I/O Initiator Routine ; ; This routine is entered from the QIO directive when an I/O request ; is queued and at the end of a previous I/O operation to propagate ; the execution of the driver. If the specified controller is not busy, ; then an attempt is made to dequeue a new I/O request, else a return ; to the caller is executed. If the dequeue attempt is successful, then ; the next I/O operation is initiated. A return to the caller is then ; executed. ; ; When called at this entry point, R5 contains the address of the UCB ; of the controller to be initiated. ; DXINI: CALL $GTPKT ; Get next QIO packet BCC 10$ ; If packet available, continue RETURN ; Return if no packet available ; Check to see if this is a valid volume 10$: CALL $VOLVD ; Verify that volume is valid BCC 20$ ; If carry clear, volume is valid ; Volume is invalid; release QIO packet with error status CALL $IOALT ; Release QIO packet w/o status word 2 BR DXINI ; Go look for more packets ; Volume is valid; check to see if disk data partition is still in 20$: MOV #PARNAM, R3 ; Copy address of partition name to R3 CALL $SRNAM ; Ask system to search for partition BCC 30$ ; If partition was found, proceed ; Partition was not found; release QIO packet with error status MOV #IE.PNS&377, R0 ; Show partition not in system CALL $IOALT ; Release QIO packet w/o status word 2 BR DXINI ; Go look for more packets ; Partition was found; check to see if it is large enough for disk 30$: MOV P.SIZE(R2), R3 ; Get partition size in 64 byte blocks MOV U.CW3(R5), R4 ; Get size of disk in 512 byte LBNs ASH #3, R4 ; Disk size in units of 64 byte blocks CMP R3, R4 ; Is the partition large enough? BGE 40$ ; If large enough, proceed ; Disk partition not large enough; release QIO packet with error status MOV #IE.BLK&377, R0 ; Show partition too small CALL $IOALT ; Release QIO packet w/o status word 2 BR DXINI ; Go look for more packets ; Partition is large enough; check to see if this is a transfer function 40$: TST R0 ; Transfer function? ($VOLVD set R0) BMI 50$ ; If so, proceed ; Not a transfer function. Ignore IO.STC, which should be the only way ; to get here. Return to the Exec with R0 = IS.SUC&377 (set by $VOLVD) CALL $IOALT ; Release QIO packet w/o status word 2 BR DXINI ; Go look for more packets ; Function is a transfer function; find out exactly which one 50$: MOV #IE.IFC&377, R0 ; Assume the function is invalid BITB #IO.RPB&377, I.FCN(R1) ; Physical block transfer ? BEQ 55$ ; If not, ok, jump around ; Physical block functions are invalid; release packet with error CALL $IOALT ; Dismiss error packet BR DXINI ; Go look for another packet ; Function is a logical block function; find out which one it is 55$: CMPB #IO.RLB/256., I.FCN+1(R1) ; Is this Read Logical Block? BEQ DXRLB ; Yes; go do it ; Function code not IO.RLB; check to see if IO.WLB, Write Logical Block 90$: CMPB #IO.WLB/256., I.FCN+1(R1) ; Is this Write Logical Block? BEQ DXWLB ; Yes; go do it ; Function code is illegal; release QIO packet with error status 95$: CALL $IOALT ; Release QIO packet BR DXINI ; Go look for more packets .PAGE .SBTTL DXRLB Read Logical Block ; ; Function code is IO.RLB, Read Logical Block ; DXRLB: MOV R5, -(SP) ; Save the UCB pointer on the stack MOV I.PRM(R1), R3 ; Copy buffer APR6 relocation bias to R3 MOV I.PRM+2(R1), R4 ; Copy buffer APR6 displacement to R4 MOV I.PRM+4(R1), R0 ; Copy size of transfer in bytes to R0 MOV I.PRM+12(R1), R1 ; Obtain logical block number ASH #3, R1 ; Multiply LBN by 8. ADD P.REL(R2), R1 ; Add partition base address/64. CLR R2 ; Start at disk block boundary CALL BLX64K ; Transfer from disk to user buffer 80$: MOV (SP)+, R5 ; Restore the UCB pointer to R5 MOV #IS.SUC&377, R0 ; We always transfer successfully MOV U.CNT(R5), R1 ; Showing bytes transferred in R1 ??? CALL $IODON ; Release QIO packet BR DXINI ; Go look for more packets .PAGE .SBTTL DXWLB Write Logical Block ; ; Function code is IO.WLB, Write Logical Block ; DXWLB: MOV R5, -(SP) ; Save the UCB pointer on the stack MOV I.PRM+4(R1), R0 ; Copy size of transfer in bytes to R0 MOV I.PRM+12(R1), R3 ; Obtain logical block number ASH #3, R3 ; Multiply LBN by 8. ADD P.REL(R2), R3 ; Add partition base address/64. MOV I.PRM+2(R1), R2 ; Copy buffer APR5 displacement to R2 MOV I.PRM(R1), R1 ; Copy buffer APR5 relocation bias to R1 SUB #20000, R2 ; Convert RSX APR6 displacement to APR5 CLR R4 ; Start out with no disk granularity CALL BLX64K ; Transfer from user buffer to disk 130$: MOV (SP)+, R5 ; Restore the UCB pointer to R5 MOV #IS.SUC&377, R0 ; We always transfer successfully MOV U.CNT(R5), R1 ; Showing bytes transferred in R1 ??? CALL $IODON ; Release QIO packet JMP DXINI ; Go look for more packets .PAGE .SBTTL DXCAN Cancel I/O Routine ; ; Cancel I/O operation is normally a NOP for file structured devices, ; but code has been included to abort and release the I/O packet just ; in case. This was added after it was noticed that the system crashed ; when trying to MOUnt an unINItialized disk. (And still does, but we ; left the code in anyway.) ; DXCAN: MOV #IE.ABO&377, R0 ; Show that operation was cancelled CALL $IOALT ; Release I/O packet RETURN ; Return to Executive .PAGE .SBTTL DXPWF Power Fail Routine ; ; Power fail initialization is a NOP on a memory resident disk. ; ; It will be necessary to include code here to zero the entire ; partition allocated for the disk. ; ; It may be necessary to include get partition parameters here so that ; the driver knows where to look, when installed - default partition ; name for memory resident disks is RESDSK. ; DXPWF: RETURN .PAGE .SBTTL DXOUT Device Timeout ; ; Device timeout is impossible on a memory resident disk. ; (No, no! It really IS impossible!) ; DXOUT: RETURN .PAGE .SBTTL DXKRB Controller Online/Offline ; ; These conditions are checked each time through at DXINI ; DXKRB: RETURN .PAGE .SBTTL DXUCB Unit Online/Offline ; ; This routine is called when an individual unit is brought online or ; taken offline. In the case of a unit being brought online, it checks ; to see that the partition is loaded, large enough to hold the resident ; disk, and locks the partition against checkpointing, shuffling, and ; other tampering. In the case of a unit being taken offline, it unlocks ; the partition. ; DXUCB: BCS 30$ ; If carry set, unit going offline ; Unit is coming online; check to see if partition is in system MOV #PARNAM, R3 ; Address of partition name to R3 CALL $SRNAM ; Search for partition BCC 10$ ; If carry clear, partition was found ; Partition not found; release with error status $SCERR = -1 * IE.PNS ; Show partition not in system RETURN ; Return to caller ; Partition found; check to see if it is large enough for disk 10$: MOV P.SIZE(R2), R3 ; Partition size in 64 byte blocks MOV U.CW3(R5),R4 ; Get size of disk in LBNs ASH #3, R4 ; size in units of 64 byte blocks CMP R3, R4 ; is partition large enough BGE 20$ ; If GE, large enough ; Partition not large enough; release with error status $SCERR = -1 * IE.BLK ; Show partition too small RETURN ; Return to caller ; Partition large enough; lock partition and return with valid code 20$: BIS #, P.STAT(R2) ; Lock up partition RETURN ; Unit is going offline; check for partition parameters 30$: MOV #PARNAM, R3 ; Address of partition name to R3 CALL $SRNAM ; Search for partition BCC 40$ ; If carry clear, partition was found ; Partition not found; we in a heap of trouble now, boy! $SCERR = -1 * IE.PNS ; Show partition not in system RETURN ; Return to caller ; Partition found; check to see if it is large enough for disk 40$: BIC #, P.STAT(R2) ; Unlock partition RETURN ; Return to caller .PAGE .SBTTL .SBTTL Subroutines .SBTTL .SBTTL BLX64K $BLXIO For Up to 64K Byte Transfers ; ; BLX64K - Move Block of Data from Memory to Memory ; ; This routine will move up to 32K words (64K bytes) of data using ; the Executive $BLXIO routine. It is superior to $BLXIO in that ; $BLXIO is able to move only 4K words (8K byte) at a time, and it ; does APR granularity alignment internally. ; ; Inputs: R0 - Number of BYTES to move ; R1 - Source APR5 bias ; R2 - Source displacement ; R3 - Destination APR6 bias ; R4 - Destination displacement ; ; Outputs: R2, R4 point to last byte of source and destination + 1 ; If R0 is out of range, nothing is changed and it returns ; ; Register Dispositions: R0 is destroyed ; R1, R3, R5 are preserved ; BLX64K: MOV R2, -(SP) ; Save source displacement on stack BIC #177700, (SP) ; Clean it off to 64 byte boundary MOV R4, -(SP) ; Save destination displacemt on stack BIC #177700, (SP) ; Clean it off to 64 byte boundary MOV R0, -(SP) ; Save byte transfer count on stack BIC #160000, R2 ; Clean off the APR6 displacement ; Loop here for every 4K-32. word transfer 10$: BIS #120000, R2 ; Bitset the APR5 value in R2 BIS #140000, R4 ; Bitset the APR6 value in R4 MOV (SP), R0 ; Assume transfer is < 8192.-64. bytes CMP R0, #<8192.-64.> ; Is it larger than that size? BLO 20$ ; If not, go do the full transfer ; Transfer is larger than 8192.-64. bytes; transfer 8192.-64. bytes MOV #<8192.-64.>, R0 ; Transfer the maximum 8K-64. bytes ; Check for completion of transfer 20$: SUB R0, (SP) ; Update bytes remaining after transfer CALL $BLXIO ; Transfer block of data TST (SP) ; Is the transfer complete? BEQ 30$ ; If so, go return to the caller ; Transfer not complete. Last transfer copied full 8K-64. bytes. ; APR displacement registers R1 and R3 are incremented by 177 octal ; (177 * 64. bytes was transfer size). Granularity displacement ; registers R2 and R4 are restored ($BLXIO destroyed them). ADD #177, R1 ; Adjust source mapping MOV 4(SP), R2 ; Recover source displacement ADD #177, R3 ; Adjust destination mapping MOV 2(SP), R4 ; Recover destination displacemt BR 10$ ; Go do next 4K transfer ; Transfer is complete; restore the stack and return to the caller 30$: ADD #6, SP ; Restore the stack RETURN ; Return to caller .END