        .TITLE  DWDRV
        .IDENT  /01/
 
        .LIST   ME
        .LIST   BEX
        .NLIST  CND
        .NLIST  TTM
 
;
; DWK mini winchester controller driver
;
; MACRO library calls
;
 
D$$W11=2
LD$DW=1
VC$DW=0
 
        .MCALL  PKTDF$
        .MCALL  KRBDF$,UCBDF$
 
        PKTDF$                  ; Define i/o packet offsets
        KRBDF$
        UCBDF$
 
.MACRO DB REPT
  .REPT 'REPT'
    .WORD 0
  .ENDR
.ENDM DB
 
.MACRO PATCH REPT
; .REPT 'REPT'
;   NOP
; .ENDR
.ENDM PATCH
;
; Equated symbols
;
 
RETRY=2.                        ; Error retry count
 
DWID=-20
        DW$ID=401
DWPRE=-14
DWERR=-14
        ER.SNF=400
        ER.TR0=1000
        ER.GFL=2000
        ER.HNF=10000
        ER.ACR=20000
        ER.DCR=40000
DWREV=-12
DWSEC=-12
DWRD=-10
DWCYL=-6
DWTRK=-4
DWCSR2=-2
        HSEEK= 20
        READ=  40
        WRITE= 60
        FORMAT=120
 
        S2.ERR=400
        S2.DRQ=4000
        S2.SEK=10000
        S2.WRF=20000
        S2.DWY=40000
DWCSR=0
        ST.OPN= 1
        ST.INIT=10
        ST.IE=  100
        ST.DRQ= 200
        ST.DCP= 4000
        ST.BUSY=100000
;
; Local data
;
; Controller impure data tables (indexed by controller number)
;
 
;
; Diagnostic function code table
;
FUNTBL: .WORD   IO.HMS!IQ.UMD, 20
        .WORD   IO.WDH!IQ.UMD, 120
FUNTBE:
 
.IF DF  R$$MPL
 
S.VCTM=-1
S.VITM=-1
S.VKRB=-1
S.VPKT=-1
S.VSTS=-1
S.VST2=-1
 
EXEVEC: .WORD   0               ; Vector yet not filled
 
SCTM:   .WORD   S.CTM
SITM:   .WORD   S.ITM
SKRB:   .WORD   S.KRB
SPKT:   .WORD   S.PKT
SSTS:   .WORD   S.STS
SST2:   .WORD   S.ST2
 
BLKC2:  .WORD   $BLKC2
BMSET:  .WORD   $BMSET
CRPAS:  .WORD   $CRPAS
CVLBN:  .WORD   $CVLBN
DTOER:  .WORD   $DTOER
DVERR:  .WORD   $DVERR
FORK:   .WORD   $FORK
GTPKT:  .WORD   $GTPKT
IODON:  .WORD   $IODON
KISR6:  .WORD   KISAR6
RLCN:   .WORD   $RLCN
RQCND:  .WORD   $RQCND
VOLVD:  .WORD   $VOLVD
 
EXEVCL=<<<.-EXEVEC>/2>-1>
 
SCBPAT: .WORD   CTM1,SCTM
        .WORD   ITM1,SITM
        .WORD   RKRB1,SKRB
        .WORD   KRB1,SKRB
        .WORD   KRB2,SKRB
        .WORD   KRB3,SKRB
        .WORD   KRB4,SKRB
        .WORD   KRB5,SKRB
        .WORD   PKT1,SPKT
        .WORD   PKT2,SPKT
        .WORD   PKT3,SPKT
        .WORD   PKT4,SPKT
        .WORD   STS1,SSTS
        .WORD   RST21,SST2
        .WORD   0
 
.ENDC   ;DF R$$MPL
 
RTTBL:  DB      D$$W11          ; Error retry count and positioning flag
 
;
; Driver dispatch table
;
 
        DDT$    DW,D$$W11,NEW=Y,OPT=Y   ; Generate dispatch table
 
;+
; ** - DWINI - Controller initiator
;
; This routine is entered from the queue I/O directive when an I/O request
; is queued and at the end of a previous I/O operation to propagate the ini-
; tion of the driver. If the specified controller is not busy, then an attempt
; is made to dequeue the next 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.
;
; Inputs:
;
;       R5=address of the UCB of the controller to be initiated.
;
; Outputs:
;
;       If the specified controller is not busy and an I/O request is waiting
;       to be processed, then the request is dequeued and the I/O operation
;       is initiated.
;-
 
        .ENABL  LSB
DWINI:  NOP                     ; OR BPT - CALL XDT - for debug only
        GTPKT$  DW,D$$W11       ; Get next i/o packet to process
;
; The following arguments are returned by $GTPKT:
;
;       R1=address of the I/O request packet.
;       R2=physical unit number of the request UCB.
;       R3=controller index.
;       R4=address of the status control block.
;       R5=address of the UCB of the controller to be initiated.
;
; Controller I/O request packet format:
;
;       WD. 00 -- I/O queue thread word.
;       WD. 01 -- request priority, event flag number.
;       WD. 02 -- address of the tcb of the requestor task.
;       WD. 03 -- pointer to second lun word in requestor task header.
;       WD. 04 -- contents of the first lun word in requestor task heade
;       WD. 05 -- I/O function code (IO.RLB or IO.WLB).
;       WD. 06 -- virtual address of I/O status block.
;       WD. 07 -- relocation bias of I/O status block.
;       WD. 10 -- I/O status block address (real or displacement + 14000
;       WD. 11 -- virtual address of AST service routine.
;       WD. 12 -- relocation bias of buffer address
;       WD. 13 -- buffer address of I/O transfer.
;       WD. 14 -- number of bytes to be transfered.
;       WD. 15 -- not used.
;       WD. 16 -- cylinder
;       WD. 17 -- sector in low and track in high byte of word
;       WD. 20 -- relocation bias of diagnostic reg. adrs else not used
;       WD. 21 -- diagnostic reg. blk adrs (real or displ.+140000)
;
 
        PATCH 5
 
        CALL    @RQCND          ; Request controller for data transfer
        MOV     S.VPKT(R4),R1   ; Retreive I/O packet address
PKT1=.-2
        MOV     S.VKRB(R4),R3   ; Retrieve address of KRB
KRB1=.-2
        MOVB    K.CON(R3),R3    ; Retrieve controller index
        CALL    @VOLVD          ; Validate volume valid
        BCS     50$             ; If CS we failed (JMP 200$ THRU 50$:)
        TST     R0              ; Transfer function?
        BMI     10$             ; If MI yes
        TST     I.PRM+2(R1)     ; Size the disk?
        BPL     50$             ; If PL no (JMP 200$ THRU 50$:)
 
        MOV     @S.VKRB(R4),R2  ; RETREIVE CSR ADDRESS
KRB2=.-2
        CALL    DWWAIT          ;
        MOV     #IS.SUC&377, R0
        CLR     U.CNT(R5)
        JMP     220$            ;  and exit
 
10$:                            ; Ref label
        PATCH 3
 
        MOV     #RETRY&377,RTTBL(R3)    ; Clear recal flag and set retries
 
        CLC                             ; Convert
        ROR     U.CNT(R5)               ;   to word count
 
        PATCH 5
 
        CMPB    #IO.HMS/^D<256>,I.FCN+1(R1)  ; DIAGNOSTIC FUNCTION?
        BNE     40$             ; IF NE NO
        MOV     #FUNTBL,R0      ; GET ADDRESS OF FUNCTION TABLE
20$:    CMP     (R0)+,I.FCN(R1) ;  FUNCTION CODE MATCH?
        BEQ     30$             ; IF EQ YES
        TST     (R0)+           ; BYPASS CONTROLLER CODE
        CMP     #FUNTBE,R0      ; END OF FUNCTION TABLE?
        BEQ     40$             ; IF EQ YES
        BR      20$             ; TRY AGAIN
30$:    MOV     (R0),U.BUF(R5)  ; SET CONTROLLER FUNCTION BITS
        BR      70$             ; GO CHECK LOGICAL BLOCK NUMBER
40$:    MOV     #IE.IFC&377,R0  ; ASSUME ILLEGAL FUNCTION
        MOV     #READ,U.BUF(R5) ; ASSUME READ LOGICAL FUNCTION
        CMPB    #IO.RLB/256.,I.FCN+1(R1) ; READ LOGICAL FUNCTION?
        BHIS    60$             ; IF HIS FUNCTION IS LEGAL
 
50$:    JMP     200$            ; FUNCTION IS ILLEGAL
 
60$:    BEQ     70$             ; IF EQ FUNCTION WAS READ
                                ; CONVERT TO WRITE LOGICAL FUNCTION
        ADD     #WRITE-READ, U.BUF(R5)
70$:
        PATCH 3
;
; INITIATE i/o OPERATION
;
DWLOOP:
        PATCH 5
 
        MOV     @S.VKRB(R4),R2  ; GET ADDRESS OF CSR
KRB3=.-2
        MOV     S.VPKT(R4),R1   ; RETRIEVE ADDRESS OF I/O REQUEST PACKET
PKT2=.-2
        MOVB    S.VITM(R4),S.VCTM(R4)   ; SET CURRENT DEVICE TIMEOUT COUNT
ITM1=.-4
CTM1=.-2
        CALL    DWWAIT                  ;
        MOV     I.PRM+10(R1), DWCYL(R2) ; INSERT CYLINDER ADDRESS
        MOVB    I.PRM+13(R1), DWTRK(R2) ; INSERT TRACK ADDRESS
        MOVB    I.PRM+12(R1), R0
        INC     R0
        BIC     #^C<17>, R0
        MOVB    R0,           DWSEC(R2) ; INSERT SECTOR ADDRESS
        CMP     U.BUF(R5), #WRITE
        BNE     80$
        MOV     #360./4,      DWPRE(R2)
80$:
        MOV     U.BUF(R5),   DWCSR2(R2) ; LOAD FUNCTION AND GO
        CMP     U.BUF(R5), #WRITE
        BNE     90$
        CALL    LOAD
 
90$:
        CALL    @BMSET
        BIS     #ST.IE, (R2)
        BMI     100$
        BIC     #ST.IE, (R2)
        CALL    @(SP)+
        BR      110$
100$:   RETURN
 
;+
; CANCEL i/o OPERATION IS A NOP FOR FILE STRUCTURED DEVICES.
;-
DWCAN:                          ;;;NOP FOR DW
 
;+
; POWERFAIL IS HANDLED VIA THE DEVICE TIMEOUT FACILITY AND
; CAUSES NO IMMEDIATE ACTION ON THE UNIT.
;-
DWPWF:
        RETURN
 
;+
; **-$DWINT-CONTROLLER INTERRUPTS
;-
 
        INTSE$  DW,PR4,D$$W11   ;;;SAVE REGISTERS AND SET PRIORITY
 
        PATCH 5
 
        MOV     U.SCB(R5),R4    ;;;GET ADDRESS OF SCB
        MOV     @S.VKRB(R4),R4  ;;;GET ADDRESS OF CSR
KRB4=.-2
        BIC     #ST.IE,(R4)     ;;;CLEAR INTERRUPT ENABLE
        CALL    @FORK           ;;;CREATE A SYSTEM PROCESS
 
        PATCH 5
 
        MOV     R4,R2           ;COPY ADDRESS OF CSR
        MOV     U.SCB(R5),R4    ;RETRIEVE ADDRESS OF SCB
        MOV     S.VKRB(R4),R3   ;RETRIEVE ADDRESS OF KRB
KRB5=.-2
        MOVB    K.CON(R3),R3    ;RETRIEVE CONTROLLER INDEX
        MOV     S.VPKT(R4),R1   ;GET i/o PACKET ADDRESS
PKT3=.-2
 
110$:   MOV     #IS.SUC&377,R0  ;ASSUME SUCCESSFUL TRANSFER
        BITB    #IQ.UMD,I.FCN(R1)  ;DIAGNOSTIC FUNCTION EXECUTED?
        BNE     220$            ;IF NE YES
 
        PATCH 5
 
        BIT     #S2.ERR, DWCSR2(R2)     ; Any errors ?
        BEQ     150$            ; Branch, if no
        CALL    @DVERR          ; Log device error
        CALL    FLUSH
120$:   BITB    #IQ.X,I.FCN(R1) ; Inhibit retries ?
        BNE     180$            ; Branch, if yes
130$:   DECB    RTTBL(R3)       ; Any more retries ?
        BLE     180$            ; Branch, if no
140$:   JMP     DWLOOP          ; Retry entire operation
 
150$:
        PATCH 5
 
        BITB    #IO.WLC&377,I.FCN(R1)   ; Write followed by write check ?
        BNE     170$                    ; Branch, if yes
        BITB    #US.WCK,U.STS(R5)       ; Write check enabled by MCR?
        BEQ     170$                    ; Branch, if no
160$:   CMPB    U.BUF(R5), #WRITE       ; Write function ?
        BNE     170$                    ; Branch, if no
;       BIS     #2*2,U.BUF(R5)          ; Set write check function
;       BIT     #2*2,R1                 ; Was last function a write check ?
;       BNE     170$                    ; Branch, if yes
;       MOV     #RETRY&377,RTTBL(R3)    ; Reinitialize retry count
;       BR      140$                    ; Start write check operation
 
170$:   CMPB    U.BUF(R5), #READ
        BNE     172$
        CALL    UNLOAD
172$:
        ADD     #256.*2/100, I.PRM(R1)  ; Adjust KISAR6 value
        SUB     #256., U.CNT(R5)        ; Yet one sector
        BHI     175$                    ; Branch, if request not sutisfied
        CLR     U.CNT(R5)               ; All request
        BR      190$
 
175$:
        PATCH 5
 
        INCB    I.PRM+12(R1)            ; Next sector
        BICB    #^C<17>, I.PRM+12(R1)   ; Up to 16. sectors on track
        BNE     140$                    ; Branch, if not sector #0
        INCB    I.PRM+13(R1)            ; Next track
        BICB    #^C<3>, I.PRM+13(R1)    ; Up to 4. headers on cylinder
        BNE     140$                    ; Branch, if not header #0
        INC     I.PRM+10(R1)            ; Next cylinder
        BR      140$
 
180$:
        MOV     #IE.VER&377,R0  ;UNRECOVERABLE ERROR
        CLR     R1
        BR      200$
 
190$:   MOV     I.PRM+4(R1), R1
        CLC
        ROL     U.CNT(R5)
        SUB     U.CNT(R5), R1   ; CALCULATE BYTES ACTUALLY TRANSFERED
 
200$:   MOVB    RTTBL(R3),R2    ;GET FINAL ERROR RETRY COUNT
        BIS     #RETRY*256.,R2  ;MERGE STARTING RETRY COUNT
 
        PATCH 2
 
        CALL    @RLCN           ;RELEASE CONTROLLER
        CALL    @IODON          ;FINISH i/o OPERATION
        JMP     DWINI           ;PROCESS NEXT REQUEST
 
;
; DEVICE TIMEOUT RESULTS IN A HOME SEEK FOLLOWED BY THE i/o OPERATION
; BEING REPEATED UNLESS THE OPERATION WAS DIAGNOSTIC.  TIMEOUTS ARE
; USUALLY CAUSED BY POWERFAILURE BUT MAY ALSO BE THE RESULT OF A
; HARDWARE FAILURE.
;
 
DWOUT:  INCB    S.VSTS(R4)      ;;;LEAVE CONTROLLER BUSY
STS1=.-2
        CALL    @DTOER          ;;;LOG DEVICE TIMEOUT
        BCC     230$            ;IF CC TIMEOUT DURING NORMAL FUNCTION
 
220$:   CALL    @CRPAS          ; Pass controller registers to task
        BR      190$            ; Diagnostic processing complete
 
230$:   MOV     S.VPKT(R4),R1   ;GET i/o PACKET ADDRESS
PKT4=.-2
        BITB    #IQ.X,I.FCN(R1) ;INHIBIT RETRIES?
        BNE     180$            ;IF NE YES
        BR      130$            ;
 
        .DSABL  LSB
 
;+
;
;-
DWWAIT:
        PATCH 6
 
        TST     (R2)
        BMI     DWWAIT
        RETURN                  ;
;+
;
;-
FLUSH:
        PATCH 4
        TST     DWRD(R2)
        BIT     #S2.DRQ, DWCSR2(R2)
        BNE     FLUSH
        RETURN
;+
; R0 -
; R1 - I/O packet address
; R2 - CSR
; R3 - controller index
; R4 - SCB
; R5 - UCB
;-
LOAD:
        PATCH 4
        BIT     #S2.DRQ, DWCSR2(R2)
        BEQ     LOAD
        MOV     R0, -(SP)
        MOV     U.CNT(R5), R0
        MOV     R5, -(SP)       ; for KISAR6
        MOV     R4, -(SP)
        MOV     R3, -(SP)
        MOV     KISR6, R5
        MOV     (R5), -(SP)
        MOV     I.PRM(R1), (R5)
        MOV     I.PRM+2(R1), R4
        MOV     #256., R3
10$:    TST     R0
        BEQ     20$
        MOV     (R4)+, DWRD(R2)
        DEC     R0
        BR      30$
20$:    CLR     DWRD(R2)
30$:    SOB     R3, 10$
        BR      COMM
 
;+
; R0 -
; R1 - I/O packet address
; R2 - CSR
; R3 - controller index
; R4 - SCB
; R5 - UCB
;-
UNLOAD:
        PATCH 4
 
        BIT     #S2.DRQ, DWCSR2(R2)
        BEQ     UNLOAD
        MOV     R0, -(SP)
        MOV     U.CNT(R5), R0
        MOV     R5, -(SP)       ; for KISAR6
        MOV     R4, -(SP)
        MOV     R3, -(SP)
        MOV     KISR6, R5
        MOV     (R5), -(SP)
        MOV     I.PRM(R1), (R5)
        MOV     I.PRM+2(R1), R4
        MOV     #256., R3
10$:    TST     R0
        BEQ     20$
        MOV     DWRD(R2), (R4)+
        DEC     R0
        BR      30$
20$:    TST     DWRD(R2)
30$:    SOB     R3, 10$
COMM:   MOV     (SP)+, (R5)
        MOV     (SP)+, R3
        MOV     (SP)+, R4
        MOV     (SP)+, R5
        MOV     (SP)+, R0
        RETURN
;+
; **-DWCHK-VALIDATE AND CONVERT THE LBN
;
; THIS ROUTINE IS CALLED FROM $DRQRQ TO DO LBN PROCESSING
; FOR DEVICES WHICH SUPPORT QUEUE OPTIMIZATION.  IF BLKC2
; DETECTS AN ERROR IT WILL RETURN TO THE CORRECT PLACE IN
; $DRQRQ AFTER CALLING $IOALT.
;
; INPUTS:
;
;       R1=i/o PACKET ADDRESS
;       R5=ucb ADDRESS
;
; OUTPUTS:
;
;       IF THE CHECKS SUCCEEDS, THEN THE LBN IN THE PACKET
;       IS REPLACED BY THE CYLINDER/TRACK/SECTOR.  R1 IS PRESERVED.
;
;       IF THE CHECKS FAILS, THEN $IOALT IS ENTERED WITH A FINAL
;       STATUS OF IE.BLK AND A RETURN TO THE CORRECT PLACE IN
;       $DRQRQ IS EXECUTED.
;
;
; NOTE: ALL FUNCTIONS PUT INTO THE DRIVER QUEUE ARRIVE HERE.
;       THESE INCLUDE IO.ATT, IO.DET, AND ACP FUNCTIONS.
;-
 
DWCHK:
        PATCH 5
 
        MOV     I.FCN(R1),-(SP) ;PUT THE FUNCTION ONTO THE STACK
        CMPB    #IO.ATT/256.,1(SP) ;IS IT ATTACH
        BEQ     20$             ;IF EQ YES - LEAVE IT ALONE
        CMPB    #IO.DET/256.,1(SP) ;IS IT DETACH
        BEQ     20$             ;IF EQ YES - LEAVE IT ALONE
        BIC     #7,(SP)         ;CLEAR THE SUBFUNCTION BITS
        CMP     #IO.STC,(SP)    ;IS IT SET CHARACTERISTICS?
        BEQ     20$             ;IF EQ YES - LEAVE IT ALONE
        TST     (SP)+           ;CLEAN THE STACK
        CALL    @BLKC2          ;CHECK LOGICAL BLOCK NUMBER
        CALL    @CVLBN          ;CONVERT LOGICAL BLOCK NUMBER
        SWAB    R1              ;SWAP TRACK TO HIGH BYTE
        BIS     R1,R0           ;MERGE TRACK WITH SECTOR
        MOV     R0,I.PRM+12(R3) ;SAVE DESIRED TRACK AND SECTOR ADDRESS
        MOV     R2,I.PRM+10(R3) ;SAVE DESIRED CYLINDER ADDRESS
        MOV     R3,R1           ;RESTORE THE PACKET ADDRESS
10$:    RETURN                  ;EXIT
20$:    TST     (SP)+           ;CLEAN THE STACK
        BR      10$             ;AND EXIT
 
 
.IF DF  R$$MPL
 
DWKRB:  BCS     20$             ; Off-line request - done
 
        TST     EXEVEC          ; If done already
        BNE     20$             ; Skip this
 
        PATCH 5
 
        MOV     R2,-(SP)        ; Save R2
        MOV     R3,-(SP)        ;  and R3
        MOV     @#KINAR6,-(SP)  ;   and mapping APR6
        MOV     @#112,R0        ; Get address of table of entries
        MOV     (R0),R0         ; Get address of APR bias (first word)
        MOV     (R0),@#KINAR6   ; Map common through APR6
        MOV     #EXEVEC,R3      ; Point to vector
        MOV     #EXEVCL,R2      ; Specify length of vector
        CALL    @#140004        ; Translate vector
        MOV     (SP)+,@#KINAR6  ; Restore mapping
        MOV     (SP)+,R3        ;  And R3
        MOV     (SP)+,R2        ;   And R2
        MOV     #SCBPAT,R0      ; Get patch table address
10$:    MOV     (R0)+,R1        ; Move table entry
        BEQ     20$             ; If EQ - end of table
        MOV     @(R0)+,(R1)     ; If NEQ - start to patch
        BR      10$             ; Complete it
20$:
        RETURN
 
DWUCB:  RETURN
 
        PATCH 40
 
.ENDC   ;DF R$$MPL
 
        .END
