.TITLE XE - IOMEGA DISK HANDLER .IDENT /ALPHA1/ ; ; RT11 V4 SYS HANDLER FOR XEBEC/MSC S1410 CONTROLLER ; PROVIDES PARTIAL (SIZING) EMULATION OF RK05 OR RL01/02. ; NOTE THAT ONLY 18 BIT ADDRESSING IS CURRENTLY SUPPORTED BY RT-11. ; ; WRITTEN BY: ; ; EVAN L SOLLEY ; NORTEK, INC ; 2432 NW JOHNSON ; PORTLAND, OR 97210 ; 503-226-3515 ; ; REWRITTEN FOR IOMEGA BY: ; ; MARTIN BURGER ; BASE SYSTEMS ; 760 E 78 ST ; BROOKLYN, NY 11236 ; 718-531-2341 (HOME) ; ; TO INSTALL, DEFINE ; THE LOGICAL UNIT SIZING DESIRED (RK05/RL01/RL02/IOMEG) ; .IIF NDF DSIZE, DSIZE = IOMEG ;LOGICAL UNIT SIZING MMG$T = 0 ; NO MEMORY MANAGEMENT 0=RT11SJ OR FB, 1=TSX+ OR XM TSX$P = 1 ; 1=TSX+ , 0=XM ; .IIF NDF SPECIAL, SPECIAL = 0 ;SET ONLY FOR BOARDS MODIFIED BY M.B. ; .IF NE TSX$P KISADR = 172354 ;TSX+ PAR 6 .IFF KISADR = 172342 ;XM PAR 1 .ENDC ;TSX$P ; .MCALL .DRDEF,.DRSET .MACRO ADDR LOC,REG MOV PC,REG ADD #LOC-.,REG .ENDM ADDR ; ; COMMAND OP CODES FOR ALPHA 10 ; SENSE = 03 ;3 SENSE ERROR INFORMATION READ = 10 ;8 READ N BLOCKS WRITE = 12 ;A WRITE N BLOCKS SEEK = 13 ;B SEEK TO BLOCK N ; ; REGISTERS FOR S1410 HOST (DTC) ADAPTER ; XE$CCR = XE$CSR-2 ;COMMAND COMPLETION STATUS REGISTER XE$CSR = XE$CSR ;CONTRO/STATUS REGISTER XE$DAR = XE$CSR+2 ;DATA ADDRESS REGISTER XE$CAR = XE$CSR+4 ;COMMAND ADDRESS REGISTER XE$XD = XE$CSR+6 ;20-21 BITS FOR DAR XE$XC = XE$CSR+10 ;20-21 BITS FOR CAR .SBTTL DRIVER CONFIGURATION AND SIZING ; ; DEFINE EMULATION SIZE OPTIONS (ALL UNITS MUST BE THE SAME SIZE). ; RK05 = 4800. ;BLOCKS PER LOGICAL RK05 RL01 = 10210. ;BLOCKS PER LOGICAL RL01 RL02 = 20450. ;BLOCKS PER LOGICAL RL02 IOMEG = 19584. ;BLOCKS PER LOGICAL IOMEGA ALPHA 10 .SBTTL REQUEST ENTRY POINT .DRDEF XE,141,FILST$,DSIZE,177462,134 .DRBEG XE ;DEFINE ENTRY POINT MOV XECQE,R5 ;R5 -> QUEUE ELEMENT MOVB Q$UNIT(R5),R0 ;R0 = LOGICAL UNIT# ; ; DETERMINE WHICH PHYSICAL DRIVE TO USE ; ASL R0 ASL R0 ASL R0 ASL R0 ASL R0 MOVB R0,DRIVE ; ; MAP USER LOGICAL BLOCK TO DRIVE LOGICAL BLOCK. ; 10$: MOV Q$BLKN(R5),R2 ;R2 = BLOCK NUMBER ASL R2 ;FOR RT11 1 BLOCK = 2 IOMEGA BLOCKS ;MB01 SWAB R2 ;BYTE ORDER FOR CONTROLLER MOV R2,SECTOR ;SET INTO COMMAND BLOCK ; ; DETERMINE FUNCTION, AND PREP FOR ACTION ; CLR LAST ;CLEAR FLAG CLR REMAIN ;CLEAR PARTIAL SECTOR COUNT MOV Q$WCNT(R5),R0 ;GET WORD COUNT BMI WR ;NEGATIVE THEN A WRITE BNE RD ;READ ? MOVB #SEEK,OPCODE ;NO THEN A SEEK BR PREP WR: MOVB #WRITE,OPCODE ;A WRITE NEG R0 ;NEGATE WORD COUNT TO MAKE IT POSITIVE BR PREP RD: MOVB #READ,OPCODE ;A READ PREP: ; ; DO ALL WHOLE SECTORS FIRST, HANDLE ANY PARTIAL SECTOR SEPARATELY ; MOVB R0,REMAIN ;SAVE PARTIAL SECTOR WORD COUNT, IF ANY CLRB R0 ;R0 = WHOLE-SECTOR COUNT .IF EQ MMG$T MOV Q$BUFF(R5),R4 ;R4 -> DATA ADDRESS MOV R4,BUFADR ;SAVE FOR SHORT SECTORS .IFF MOV Q$PAR(R5),R3 ;WORKING WITH THE DOUBLE REG PAIR (R2,R3) CLR R2 ;WE WILL CREATE THE PHYSICAL ADDRESS ASHC #6,R2 ;MOVE THE REG PAIR CONTAINING PAR 6 PLACES LEFT MOV Q$BUFF(R5),R1 ;GET THE VIRTUAL BUFFER ADDRESS BIC #160000,R1 ;REMOVE THE PAR POINTER ADD R1,R3 ;ADD TO REG PAIR GIVING US THE PHYSICAL ADC R2 ;MEMORY LOCATION. ; MOV R3,R4 ;MOVE BITS 0-15 ; MOV R2,R1 ;SET UP FOR BITS 16-19 BIC #177760,R1 ASL R1 ;MOVE BITS 16-19 TO BIT 2,3 FOR CONTROLLER ASL R1 MOV R1,XMBITS ;STORE EXTENDED BITS FOR CONTROLLER ; TST REMAIN ;SEE IF THERE IS A PARTIAL SECTOR TO DO BEQ 80$ MOV R0,R1 ;MOVE OVER WORD COUNT (FULL SECTORS WORTH) ASL R1 ;CONVERT TO BYTE COUNT ADD R1,R3 ;ADD TO PHYSICAL MEMORY LOCATION OF BUFFER ADC R2 MOV R3,R1 ;STORE FOR VIRTUAL LOCATION ASHC #-6,R2 ;SHIFT OVER 6 PLACES TO RIGHT FOR PAR VALUE MOV R3,PARADR ;STORE PAR VALUE BIC #177700,R1 ;FOR BUFFER KEEP ONLY LAST 6 BITS .IF NE TSX$P BIS #140000,R1 ;TSX+ PAR 6 POINTER .IFF BIS #20000,R1 ;XM PAR 1 POINTER .ENDC ;TSX$P MOV R1,BUFADR ;STORE BUFFER VIRTUAL POINTER 80$: .ENDC ; MMG$T ;ELS01 SWAB R0 ;FIX INTO CONTROLLER ORDER ASLB R0 ;FOR RT11, 1 BLOCK = 2 IOMEGA BLOCKS ;MB01 MOVB R0,WCNT ; BNE WORK ;ANY FULL SECTORS TO DO IO ON? CMPB OPCODE,#SEEK ;FOR SEEK, JUST DO IT BNE PARSEC ;IF NO WHOLE SECTORS, GO DO PARTIAL SECTOR WORK: NEXT: MOV R4,@#XE$DAR ;SET DATA BUFFER ADDRESS ADDR CMDBLK,R1 ;R1 -> COMMAND BLOCK MOV R1,@#XE$CAR ;SET ADDRESS CLR @#XE$XD CLR @#XE$XC INTRPT: .IF NE SPECIAL 91$: BIT #10001,@#XE$CSR ;UNIT READY (NOT BUSY)? BNE 91$ ;WAIT UNTIL READY .ENDC .IF EQ MMG$T MOV #101,@#XE$CSR ;EXECUTE FUNCTION .IFF MOV #101,R3 ;PREP FINAL COMMAND (GO+IE) BIS XMBITS,R3 ;ADD IN HIGH ORDER DATABUF ADDR BITS MOV R3,@#XE$CSR ;EXECUTE FUNCTION .ENDC RETURN ;AWAIT INTERRUPT ; ; .SBTTL INTERRUPT SERVICE ROUTINE .DRAST XE,5 MOV XECQE,R5 ;R5 -> QUEUE ELEMENT MOV @#XE$CSR,R4 ;R4 = PRIMARY STATUS BMI HERROR ;BR IF ERROR BIT #10,@#XE$CCR ;TEST IF BUSY BEQ G .FORK XE$FBK ;WASTE SOME TIME BY GOING TO FORK LEVEL ;ALSO ALLOWS OTHER I/O TO COMPLETE BR INTRPT ;RE-ISSUE COMMAND G: 20$: TST REMAIN ;IS THERE A PARTIAL SECTOR TO DO? BEQ DONE ;NOPE, ALL DONE .FORK XE$FBK ;SAVE R0-R3 GO: ; ; PARTIAL SECTOR TRANSFER REQUIRED TO FINISH REQUEST ; TST LAST ;DID WE JUST READ PARTIAL SECTOR? BNE RDONE ;YES, GO MOVE IT TO USER MOV SECTOR,R0 ;UPDATE CURRENT SECTOR# SWAB R0 ; MOVB WCNT,R4 ;BY ADDING IN #BLOCKS MOVED BIC #177400,R4 ;DON'T SIGN EXTEND ADD R4,R0 ;WITH PREVIOUS VALUE SWAB R0 ; MOV R0,SECTOR ;AND RESTORE .IF EQ MMG$T MOV @#XE$DAR,BUFADR ;SAVE USER ADDRESS .ENDC PARSEC: ADDR BUFFER,R4 ;POINT TO OUR BUFFER MOV R4,LAST ;SET FLAG CMPB OPCODE,#WRITE ;IF WRITE, TRANSFER USER DATA TO OUR BUFFER BNE 50$ ;ELSE FOR READ, JUST GET A SECTOR MOV R4,R1 ;R1 -> BUFFER ADDRESS ADD #512.,R1 ;POINT TO END OF BUFFER MOV #256.,R2 ;R2 = LENGTH SUB REMAIN,R2 30$: CLR -(R1) ;PRE-ZERO BUFFER SOB R2,30$ ; ; MOV BUFADR,R0 ;FROM MOV R4,R1 ;TO MOV REMAIN,R2 ;AMOUNT .IF NE MMG$T MOV @#KISADR,-(SP) ;SAVE KERNAL PAR POINTER MOV PARADR,@#KISADR ;PUT IN OUR'S INSTEAD .ENDC ;MMG$T 35$: MOV (R0)+,(R1)+ ;MOVE IT SOB R2,35$ .IF NE MMG$T MOV (SP)+,@#KISADR ;RESTORE PAR VALUE .ENDC ;MMG$T CLR REMAIN ;CLEAR WORDS TO BE TRANSFERED COUNT CLR LAST ;AND CLEAR FLAG 50$: CLR XMBITS ;MAKE SURE WE DON'T MAP ADDRESS ;ELS01 MOVB #2,WCNT ;JUST ONE SECTOR WILL DO IT ;ELS01 BR NEXT ; ; RDONE: MOV LAST,R0 ;R0 -> BUFFER SOURCE MOV BUFADR,R1 ;R1 -> DATA BUFFER MOV REMAIN,R2 ;R2 -> WORDS TO MOVE .IF NE MMG$T MOV @#KISADR,-(SP) ;SAVE KERNAL PAR POINTER MOV PARADR,@#KISADR ;REPLACE IT WITH OUR'S .ENDC ;MMG$T 65$: MOV (R0)+,(R1)+ ;MOVE IT SOB R2,65$ .IF NE MMG$T MOV (SP)+,@#KISADR ;RESTORE PAR VALUE .ENDC ;MMG$T DONE: ;END OF TRANSFER EXIT: .DRFIN XE ;RETURN TO Q MANAGER .DSABL LSB ; OK: TST REMAIN ;IS THERE A PARTIAL SECTOR TO DO? BEQ DONE ;NOPE, ALL DONE BR GO ;THEN DO IT HERROR: .FORK XE$FBK ;SAVE R0-R3 MOV @#XE$DAR,WCBUF ;SAVE DATA BUFFER ADDRESS MOVB DRIVE,LUNS ;SET UP DRIVE # ADDR ERBUF,R4 ;POINT TO SENSE DATA BUFFER MOV R4,@#XE$DAR ; ADDR REQBLK,R4 ;POINT TO SENSE COMMAND BUFFER MOV R4,@#XE$CAR ; CLR @#XE$XD CLR @#XE$XC 94$: .IF NE SPECIAL BIT #10001,@#XE$CSR ;TEST IF BUS IS BUSY BNE 94$ ;WAIT IF NOT .ENDC MOV #1,@#XE$CSR ;ISSUE REQUEST 80$: TSTB @#XE$CSR ;DONE? BPL 80$ ;BR IF NOT AND WAIT BIT #10,@#XE$CCR ;CHECK IF UNIT IS BUSY BNE 94$ ;REISSUE COMMAND IF YES TST @#XE$CSR ;ERROR? BMI 90$ BICB #360,SENKEY ;SETUP SENSE TEST CMPB SENKEY,#1 ;TEST FOR ECC SUCCESS RECOVER BEQ OK CMPB SENKEY,#6 ;TEST FOR MEDIA CHANGED BNE 90$ MOV WCBUF,R4 ;RESTORE BUFFER POINTER JMP NEXT ;RE-ISSUE COMMAND ; ; ERROR ; 90$: MOV XECQE,R5 ;POINT TO QUEUE ELEMENT BIS #HDERR$,@-(R5) ;SET HARD ERROR BIT BR DONE ;THEN GET OUT OF HERE .SBTTL COMMAND BLOCKS ; ; COMMAND BLOCK FOR S1410 CONTROLLER ; CMDBLK: OPCODE: .BYTE 0 ;OPCODE DRIVE: .BYTE 0 ;DRIVE NUMBER SECTOR: .WORD 0 ;SECTOR NO WCNT: .BYTE 2 ;WORD COUNT CNTRL: .BYTE 0 ;CONTROL FIELD ; ; COMMAND BLOCK & BUFFER FOR REQUEST SENSE ; WCBUF: .WORD 0 REQBLK: .BYTE 3 LUNS: .BYTE 0,0,0,9.,0 ERBUF: .BYTE 0,0 SENKEY: .BYTE 0,0,0,0,0,0 ERCODE: .BYTE 0,0 .SBTTL MISCELLANEOUS DATA CELLS XE$FBK: .BLKW 4 ;FORK BLOCK REMAIN: .WORD 0 ;PARTIAL SECTOR WORD COUNT LAST: .WORD 0 ;LAST SECTOR FLAG XMBITS: .WORD 0 ;HOLDS HIGH ORDER MEM ADDR BITS BUFADR: .WORD 0 ;HOLDS USER Q$BUFF WHILE WE CHANGE IT .IF NE MMG$T ;ELS01 PARADR: .WORD 0 .ENDC ; ; FULL SECTOR BUFFER FOR PARTIAL SECTOR TRANSFERS ; BUFFER: .BLKW 256. ;PARTIAL SECTOR BUFFER .SBTTL SECONDARY BOOT DRIVER .DRBOT XE,BOOT1,B.READ . = XEBOOT+40 ;PUT THE JUMP BOOT INTO SYSCOM AREA BOOT1: JMP @#BOOT-XEBOOT ;START THE BOOTSTRAP ; . = XEBOOT+210 ;BOOTSTRAP READ ROUTINE BOOT: MOV #10000,SP ;INIT STACK MOV R0,-(SP) ;SAVE BOOTED UNIT FOR RT MOV R0,@#B$DEVU ;SET THE UNIT NUMBER IN THE BOOT MOV #2,R0 ;READ IN SECOND PART OF BOOT MOV #<4*256.>,R1 ;FOUR BLOCKS TO READ MOV #1000,R2 ;JUST ABOVE US CALL B.READ ;DO THE READ MOV #B.READ-XEBOOT,@#B$READ ;STORE START LOCATION OF READ MOV #B$DNAM,@#B$DEVN ;STORE RAD50 DEVICE NAME MOV (SP)+,@#B$DEVU ;SET THE UNIT NUMBER IN THE BOOT JMP @#B$BOOT ;THEN GO TO SECONDARY BOOT ; ; SECONDARY BOOT DRIVER FOR XEBEC S1410 MASQUERADING AS RK05/RL01/RL02/IOMEG ; B.READ: MOV @#B$DEVU,R3 ;GET THE BOOTED UNIT NUMBER ASL R3 ASL R3 ASL R3 ASL R3 ASL R3 MOVB R3,BDRIV 4$: MOV R2,@#XE$DAR ;DATA ADDRESS MOVB R1,BREM ;SAVE PARTIAL SECTOR COUNT CLRB R1 ;CLEAR RESIDUAL SWAB R1 ;R1 = #FULL SECTORS BEQ 10$ ;NO FULL SECTORS CALL RD2 ;FIRST READ-FULL SECTORS TSTB BREM ;IS THERE A PARTIAL SECTOR BEQ 30$ ;NO, DONE 10$: ;PARTIAL SECTOR READ MOV @#XE$DAR,-(SP) ;SAVE NEXT MEM ADDRESS MOV @SP,BUSER ;PUT IT WHERE WE CAN GET TO IT MOV #BBUFF,@#XE$DAR ;USE BUFFER ADD R1,R0 ;BUMP SECTOR NUMBER MOV #1,R1 ;READ JUST ONE SECTOR CALL RD2 ;TRANSFER SECTOR MOV #BBUFF,R0 ;SOURCE MOV (SP)+,R1 ;DEST MOV BREM,R2 ;*** DON'T SIGN EXTEND *** ASL R2 20$: MOVB (R0)+,(R1)+ ;COPY DATA SOB R2,20$ ; 30$: RETURN ; ; ; TRANSFER SUBROUTINE - R0 HAS BLOCK NO, R1 HAS SECTOR COUNT AT ENTRY ; XE$DAR HAS MEMORY ADDRESS ; RD2: MOVB #READ,BOPCD ;INITIALIZE COMMAND BLOCK ADDR BOPCD,R4 MOV R4,@#XE$CAR ;COMMAND ADRS ASL R0 SWAB R0 ;SWAP BYTES FOR CONTROLLER TST (R4)+ ;SKIP PAST OPCODE MOV R0,(R4)+ ;SET SECTOR# SWAB R0 ;RESTORE BYTE ORDER FOR RE-ENTRANCY ASR R0 ASL R1 MOVB R1,(R4)+ ;SECTOR COUNT ASR R1 MOV #XE$CSR,R4 ;POINT TO CSR CLR @#XE$XC CLR @#XE$XD .IF NE SPECIAL 93$: BIT #10001,@#XE$CSR ;IS BUS BUSY? BNE 93$ ;WAIT UNTIL NOT .ENDC MOV #1,(R4) ;GO!!! 10$: TSTB (R4) ; BPL 10$ ; TST (R4) ; BMI BIOERR ;ERROR ON BOOT RETURN ;RETURN ; BOPCD: .BYTE 10 ;COMMAND BLOCK - OPCODE BDRIV: .BYTE 0 ;DRIVE NUMBER BSECT: .WORD 0 ;SECTOR NUMBER .WORD 0,0 ;BLKN & CFIELD BREM: .WORD 0 ;PARTIAL SECTOR COUNT BUSER: .WORD 0 ;POINTER TO SHORT READ DEST. ; ; PARTIAL SECTOR BUFFER IS LOCATED BELOW THE BOOTSTRAP STACK ; .DREND XE BBUFF = 6000 ;256 WORD SECTOR BUFFER .END