;CRTXEB.LIT - certify XYBEC 1410 and 1410A alpha micro systems ;MODIFIED CODE TO WORD WITH AM1000-1500-2000 ;WILL PRODUCE A DISK THAT WILL FORMAT TO HIDDEN SECTOR AND BOOT IF USING ;XEBEC 1410 OR 1410A CONTROLLER ;created 04-24-87 sef 1.3B(100) ; SEARCH SYS SEARCH SYSSYM RADIX 16. EXTERN $INMFD,$ADPPN,$PAMFD OBJNAM CRTXEB.LIT VMAJOR=1. VMINOR=3. VSUB=2. VEDIT=100. VWHO=0. ;Xebec type 0000 commands DRVRDY = 0 ; drive online & ready RECAL = 1 ; recalibrate to track 000 ERR = 2 ; retrieve error code RSENSE = 3 ; request sense status FORMAT = 4 ; format drive REED = 8. ; read sector from disk and pass data RDVFY = 9. ; read verify read sector don't pass data WRIT = 10. ; write sector to disk INITL = 12. ; initialize controller SEEK = 13. ; seek to specific track ; XEBEC 1410A DEVICE CONTROL BLOCK (DCB) ; byte 0 bits 0-4 = command opcode ; byte 0 bits 5-7 = command class ; byte 1 bit 5 = logical unit number ; uses 21 bit addressing (2,097,151 max) ; byte 1 bit 0-4 = high address (16-20) ; byte 2 bit 0-7 = middle address (8-15) ; byte 3 bit 0-7 = low address (0-7) ; byte 4 bit 0-7 = interleave or sector count (block count) ; byte 5 bit 0-7 = control field ; bit 7 = retries 0 = none 1 = 4 ; bit 6 = reread before error correction 0 = no 1 = yes ; bit 4 = imbedded servo ; bits 0-3 step rate for drive ; status byte 0 = errors ; status byte 1 = 0 command complete BUSY$ = 2 CMDDON = 4 ; scsi controller command completed ; read data port completes sequence GTSTS = 10 ; scsi status byte pending SENCMD = 4. ; scsi ready to accept command GETDAT = 16. ; scsi ready to transfer data to s100 SENDAT = 32. ; scsi ready ro receive data from s100 ;Controller I/O port offsets RDSTS = 0 ; status port = read CTLSEL = 0 ; controller select RDDATA = 1 ; read data following are true ; getstat* - getdat* - cmddon* WTDATA = 1 ; write data / command following true ; sencmd* - sendat* PORT.2 = 2 ; interrupt read = off write = on CTLRST = 0 ; reset to s-100 via RTS (j1-pin 39) DEVLNK = 0 ; device table link address LWORD DEVMNT = 4 ; mount flag bit 3 set if mounted DEVNAM = 6 ; rad50 device name (3 char) DEVNO = 8. ; device number DEVPHY = 32. ; physical device = 0 EMBSRV = 2. ; embedded servo DX.BUF = 00 ; buffer size = 512 DX.DFG = 04 ; device flags DX.VER = 0A ; driver version current = 52 DX.PHY = 0C ; physical block size 512 DX.BLK = 10 ; blocking size = 1 DX.LSZ = 14 ; logical disk size DX.HAD = 18 ; hardware controller address DX.INT = 1C ; hardware interrupt address DX.BMS = 20 ; logical bitmap size DX.ALT = 24 ; alternate track table size DX.VLD = 38 ; winchester driver flag = 0F1C7 DX.RET = 3A ; # of retries DX.HED = 3C ; number of heads DX.CYL = 3E ; number of cylinders DX.SEC = 40 ; number of sectors DX.ATC = 42 ; number of spare tracks(cylinders) DX.WIL = 44 ; write interleave DX.RIL = 46 ; read interleave DX.NLG = 48 ; number of logicals DX.PRE = 4A ; write pre-comp cylinder DX.WTC = 4C ; reduced write cylinder DX.LND = 4E ; landing zone cylinder DX.FLG = 50 ; special flags DX.STP = 52 ; controller step rate DX.SEL = 53 ; controller select bits DX.WIN = 5A ; driver controller ID .OFINI .OFDEF PRAMTR,2 ; bit 3 = display track & cylinder ; bit 4 = soft errors ; bit 5 = ok to format .OFDEF BUFF1,68. .OFDEF DDB,D.DDB ; 44 or 68. our ddb .OFDEF BUFF2,220. .OFDEF PREALO,2 ; 18a or 394. .OFDEF DEVTAD,4 ; 18C or 396. .OFDEF BUFF3,22. .OFDEF TLBLKS,4. ; 1a6 or 422. .OFDEF ALTRKS,4. ; 1aa or 426. .OFDEF SOFTER,4. ; 1ae or 430 soft error count .OFDEF BLKBAD,4. ; 1b2 or 434 hard error count .OFDEF DSKSNO,10. ; 1b6 or 438. dirve serial number .OFDEF ALTADD,4 ; 1c0 or 448. alternate track memory .OFDEF ALTSIZ,4 ; 1c4 or 452. size alt track table .OFDEF DAT0,1 ; 600 or 1536. i/o command .OFDEF DAT1,1 ; 601 or 1537. .OFDEF DAT2,1 ; 602 or 1538. .OFDEF DAT3,1 ; 603 or 1539. .OFDEF DAT4,1 ; 604 or 1540. .OFDEF DAT5,1 ; 605 or 1541. .OFDEF FF,4 ; 606 or 1542. .OFDEF BADTRK,4. ; 60a or 1546. .OFDEF TOTLTK,4. ; 60E or 1550. total alternate tracks .OFDEF STPRTE,1 ; 612 or 1554. .OFDEF SELCTL,1 ; 613 or 1555. .OFDEF DRVSEL,1 ; DRIVE SELECT .OFDEF VMESYS,1 ; .OFDEF VME,1 .OFSIZ IMPSIZ START: L0: PHDR -1,PV$RSM!PV$RPD!PV$WPD,PH$OPR PUSH A2 ; save filspec LEA A2,START MOVW #-0100,D1 ; clear crt TCRT MOVW #014E,D1 ; cursor 1,78 TCRT MOVW #-0DF,D1 ; end reverse video TCRT MOVW #0121,D1 ; cursor 1,33 TCRT MOVW #-0E0,D1 ; start reverse video TCRT TYPESP MOVW #-0DF,D1 ; end reverse video TCRT MOVW #0101,D1 ; cursor 1,1 TCRT TYPESP VCVT 2(A2),OT$TRM ; output version # MOVW #0210,D1 ; cursor 2,15 TCRT TTYI ASCII !5 1/4 Winchester/XEBEC Alpha Micro Certification! BYTE 0 EVEN CRLF POP A2 ; restore filespec GETIMP IMPSIZ,A5 ; local memory for work & var storage FSPEC DDB(A5) ; set up dsk i/o ddb LEA A6,DDB(A5) ; certification for local cpu TST D.CPU(A6) ; only BEQ LOCCPU ; TYPECR JMP ENDIT LOCCPU: INIT DDB(A5) ; & get buffers MOV DEVTBL,A0 ; find target device in device table LOKDEV: MOVW DEVNAM(A0),D7 ; get device name CMPW D7,D.DEV+DDB(A5) ; is it target device BNE NXTDEV ; no, check next device entry MOVW DEVNO(A0),D7 ; get device # CMPW D7,D.DRV+DDB(A5) ; same ? BEQ DEVFND ; yes NXTDEV: MOV DEVLNK(A0),A0 ; next device table link address CMP A0,#0 ; 0 = end of table BNE LOKDEV ; check device name TYPECR ; device not found JMP ENDIT DEVFND: MOV A0,DEVTAD(A5) ; JMP MONTED ; bypass mount routein MOVW DEVMNT(A0),D6 ; device must be mounted AND #1000,D6 ; test bit 12 BNE MONTED TYPESP PFILE DDB(A5) ; output lookup device TYPECR < - device not mounted> JMP ENDIT MONTED: TSTW DEVPHY(A0) ; must be 1st physical disk BEQ MTPHY ; the one with badblk.sys TYPESP PFILE DDB(A5) TYPECR < - not the physical device> JMP ENDIT MTPHY: ORB #3,D.FLG+DDB(A5) ; 1 rtn on error no exit to monitor ; 2 bypass printing error messages DSKMNT DDB(A5) ; mount disk XORB #-2,D.FLG+DDB(A5) MOV D.DVR+DDB(A5),A1 ; check version number CMPW DX.VER(A1),#80. ; lowest version number supported BHIS OKVER ; version # ok TYPE ? TYPESP PFILE DDB(A5) ; output device driver TYPECR < is not compatible wiht this version of CRTXEB> TYPECR EXIT OKVER: CMPW DX.WIN(A1),#071C7 ; xebex controller BEQ OKXEB ; is this a supported controller TYPE TYPESP PFILE DDB(A5) TYPECR < is not compatible with this version of CRTXEB.> TYPECR JMP ENDIT OKXEB: TYPECR < CAUTION: This program writes to all blocks> INIT DDB(A5) MOVW D.DRV+DDB(A5),D1 ; get ddb drive unit # MOV D.DVR+DDB(A5),A1 ; driver address DIV D1,DX.NLG(A1) ; convert to physical unit # LSLW D1,#5 ; bit 5 = logical unit # (0 or 1) ; controller supports 2 drives only MOVB D1,DRVSEL(A5) ; save drive select CLR D1 MOVW DX.CYL(A1),D1 ; # usable cylinders ADDW DX.ATC(A1),D1 ; # spare cylinders ADDW #1,D1 ; start counting from 1 MUL D1,DX.HED(A1) ; # heads MUL D1,DX.SEC(A1) ; # sectors MOV D1,TLBLKS(A5) ; total logical blocks/drive MOV DX.ALT(A1),D1 ; alternate track table ; # words to hold bad tracks MOV D1,ALTSIZ(A5) ; alternate track table size GETMEM ALTADD(A5) ; pointer to alternate track table BEQ OKALT TYPECR EXIT OKALT: SUB #16.,D1 ; header DIV D1,#4 ; words/4 = entries MOV D1,TOTLTK(A5) ; save # alternate entries MOV D1,ALTRKS(A5) MOVB DX.SEL(A1),SELCTL(A5) ; controller # MOVB DX.STP(A1),STPRTE(A5) ; step rate MOV DX.HAD(A1),A4 ; hardware address = A4 CALL SETPAR ; get formatting parameters CALL SETSNO ; get serial # JLOCK ; hog computer all other's locked out CALL CTLINT ; initialize controller CRLF TYPESP PFILE DDB(A5) CRLF CRLF CALL FMTYN ; should we format drive BTST #5,PRAMTR(A5) ; skip formatting if not set BEQ VERFY TYPECR CALL FMTDRV ; format drive CRLF VERFY: TYPECR CRLF CALL VERFY1 ; build badblk table at badblk(a5) CALL BLDMFD BTST #0,DX.FLG(A1) ; hidden sector 0 BEQ NOHSEC ; no CALL HIDSEC ; set up hidden sector zero NOHSEC: JUNLOK CRLF CRLF MOV BLKBAD(A5),D1 ; total number of bad blocks DCVT 0,OT$TRM ; output to crt and we are done TYPECR < bad blocks detected> TYPECR JMP ENDIT HIDSEC: ; hidden sector = first sector on disk ; bytes 0-7 header ; bytes 8-41. drive info hd,cyl,ect ; bytes 42-45 byte hash total MOV D.BUF+DDB(A5),A2 ; clear our ddb output buffer MOVW #127.,D0 ; 256 lwords MOV A2,A6 ; 512 bytes 10$: CLR (A6)+ DBF D0,10$ LEA A6,HIDHED ; hidden sector header MOVW #7,D0 ; output 8 bytes 0 - 7 20$: MOVB (A6)+,(A2)+ ; output hidden sector header DBF D0,20$ LEA A6,DX.VLD(A1) ; location 38H-5C (36 bytes) MOVW #35.,D0 ; vld,retries,heads,cyl,sec,atc 30$: MOVB (A6)+,(A2)+ ; wil,ril,nlg,prt,wtc,lnd,flg DBF D0,30$ ; stp,sel,win MOV D.BUF+DDB(A5),A2 ; buffer address MOVW #41.,D0 CLR D6 ; for bytes 0 - 41 (42 total) CLR D7 40$: MOVB (A2)+,D7 ; add all the bytes ADD D7,D6 ; sum = d6 DBF D0,40$ MOV D6,@A2 ; hash total @ 42-45 MOV D.BUF+DDB(A5),A2 ; ddb buffer address CLR D5 ; d5 = hidden sector = 0 CALL WRTSEC ; write hidden sector (sector 0) RTN HIDHED: WORD 773. ; 305H WORD 772. ; 304H WORD 1029. ; 405H WORD 3 ; 3H WORD 0E159 WORD 01941 WORD 0001 WORD 0E159 WORD 01941 WORD 0001 WORD 04E75 WORD 0A00C ABORT: TYPECR JMP ENDIT CTLINT: MOVB #INITL,DAT0(A5) ; initialize drive characteristics ; drive parameters in 8 byte block ; cyl,heads,redwite,precomp,max ecc length ; c=2 h=1 w=2 p=2 e=1 CALL SNDCMD 10$: MOVB RDSTS(A4),D7 ; read status port ANDB #CMDDON,D7 ; wait for command completion BEQ 10$ ; MOVW DX.CYL(A1),D1 ; # of useable cylinders ADDW DX.ATC(A1),D1 ; # of alternate tracks ADDW #1,D1 ; start counting from 1 CALL SNDDTA ; send data to controller TSTB VME(A5) BEQ 20$ 30$: MOVB RDSTS(A4),D7 ; check status port ANDB #CMDDON,D7 ; wait for command completion BEQ 30$ 20$: MOVB DX.HED(A1),WTDATA(A4) ; # of heads MOVW DX.WTC(A1),D1 ; reduced write current cylinder CALL SNDDTA MOVW DX.PRE(A1),D1 ; precomp cylinder CALL SNDDTA TSTB VME(A5) BEQ 50$ 40$: MOVB RDSTS(A4),D7 ; read status port ANDB #CMDDON,D7 ; untill controller done and BEQ 40$ ; status byte pending 50$: MOVB #0,WTDATA(A4) ; no ecc error correcting 60$: MOVB RDSTS(A4),D7 ; read status port ANDB #CMDDON,D7 ; untill controller done and BEQ 60$ ; status byte pending SLEEP #500. ; stall CALL GETSTS TST D1 ; 0 = no error 1 = error BNE INTERR ; initialization error RTN SNDDTA: TSTB VME(A5) ; vme system BNE AM1K ROLW D1,#8 ; swap high and low bytes MOVB D1,WTDATA(A4) ; send controller high byte ROLW D1,#8 ; swap high & low bytes MOVB D1,WTDATA(A4) ; send controller low byte BR ENDWRT AM1K: ROLW D1,#8. ; swap high & low bytes 10$: MOVB RDSTS(A4),D7 ; check controller status ANDB #CMDDON,D7 ; ready for data BEQ 10$ MOVB D1,WTDATA(A4) ; send high byte ROLW D1,#8. ; swap high & low bytes 20$: MOVB RDSTS(A4),D7 ANDB #CMDDON,D7 BEQ 20$ MOVB D1,WTDATA(A4) ; send low byte ENDWRT: RTN INTERR: TYPECR JMP ABORT FMTDRV: ; ddc controll block ; byte 1 = drive & high address ; byte 2 = middle address ; byte 3 = low address ; byte 4 = interleave ; byte 5 = options MOVB #FORMAT,DAT0(A5) ; lets format the drive MOVB DRVSEL(A5),DAT1(A5) ; set drive # and address 0000 CLRB DAT2(A5) CLRB DAT3(A5) ; format from address 000 MOVW DX.WIL(A1),D7 ; write interleave MOVB D7,DAT4(A5) ; BNE 10$ MOVB #8.,DAT4(A5) ; if = 0 use interleave = 8 10$: MOVB STPRTE(A5),DAT5(A5) ; step rate seek option CALL SNDCMD ; output format command 20$: MOVB RDSTS(A4),D7 ; wait for completion ANDB #CMDDON,D7 ; BEQ 20$ CALL GETSTS ; get status bytes TST D1 ; 0 = ok 1 = error BNE FMTERR ; format error MOVB #RECAL,DAT0(A5) ; recalibrate to track 000 CALL SNDCMD 30$: MOVB RDSTS(A4),D7 ; wait for completion ANDB #CMDDON,D7 BEQ 30$ CALL GETSTS ; get status bytes TST D1 ; 0 = ok 1 = error BNE CALERR ; calibration error RTN FMTERR: TYPECR JMP ABORT CALERR: TYPECR JMP ABORT VERFY1: CLR D2 ; current track CLR D5 ; logical sector number BTST #5,PRAMTR(A5) ; was disk formatted BNE DSPTRK ; yes verify all tracks TYPESP KBD ABORT ; verify only from this track forward BYP GTDEC ; convert to decimal number d1 MOV D1,D2 MOVW DX.SEC(A1),D5 ; # of sectors MUL D5,DX.HED(A1) ; X # of heads MUL D5,D2 ; = logical sector number DSPTRK: MOV ALTADD(A5),A2 ; our bad track table stack VERTRK: BTST #4,PRAMTR(A5) ; display current track BEQ NOTDSP TYPESP MOV D2,D1 DCVT 0,OT$TRM CRLF NOTDSP: MOVW DX.SEC(A1),D3 ; # of sectors MUL D3,DX.HED(A1) ; X # of heads = logical sector # for track DEC D3 ; number from 0 - end INC D2 ; next track VFYSEC: SAVE D2,D3,D5 ; save track ; track logical sector # ; drive logical sector # CALL RDLSEC ; read a logical sector REST D5,D3,D2 BNE BADSEC ; error bad sector NXTSEC: INC D5 ; increment next logical sector # CMP D5,TLBLKS(A5) ; compare to total sectors on drive BCC 30$ ; if = then done DBF D3,VFYSEC ; verify next logical sector this track BR VERTRK ; verify next track 30$: RTN BADSEC: CMPB D1,#018 ; correctable data error ? BNE HRDERR ; no BTST #6,PRAMTR(A5) ; flag soft errors as hard BNE HRDERR ; yes ? flag as hard error INC SOFTER(A5) ; yes, increment soft error count BR NXTSEC ; check next sector HRDERR: INC BLKBAD(A5) ; add 1 to bad block count MOV D5,(A2)+ ; output to crt bad block # TYPE MOV D5,D1 OCVT 0,OT$TRM!OT$LSP!OT$TSP TYPECR CMP D5,#63. ; cylinder zero ? BLOS BADZRO ; fatal error MOV BLKBAD(A5),D7 ; compare bad blocks to max allowed CMP D7,ALTRKS(A5) ; altrks = max allowed BHI BADALT ; > max allowed yes = fatal BR NXTSEC ; check next sector BADZRO: TYPECR JMP ABORT BADALT: TYPECR JMP ENDIT ;read a logical sector into a buffer that means data too (512 bytes/sector) RDLSEC: ; ddc controll block ; byte 1 = drive & high address ; byte 2 = middle address ; byte 3 = low address ; byte 4 = block count ; byte 5 = seek, step rate option MOVW #1,DAT4(A5) ; set up to read 1 sector MOVB STPRTE(A5),DAT5(A5) ; set step rate seek option MOVB DRVSEL(A5),DAT1(A5) ; get drive select MOVB DAT1(A5),D7 ; drive # and high track address AND #0E0,D7 ; save only drive # 0 or 1 SWAP D7 ; in high word byte 3 & 4 OR D5,D7 ; get drive logical sector address MOVB D7,DAT3(A5) ; store low address ROR D7,#8 MOVB D7,DAT2(A5) ; store middle address ROR D7,#8 MOVB D7,DAT1(A5) ; store high address & drive # ; MOVB #REED,DAT0(A5) ; read track MOVB #RDVFY,DAT0(A5) ; verify track only CALL SNDCMD ;if using rdvfy then no 512 bytes transferred and this code can be erased ;but change above bne 10$ ten execute rdsts this should be faster ;10$: ; MOVB RDSTS(A4),D7 ; is a status byte pending ; ANDB #CMDDON,D7 ; ; BEQ 10$ ; yes read the status ; MOVB RDSTS(A4),D7 ; is data pending (our 512 bytes) ; ANDB #GETDAT,D7 ; no check port again ; BNE RDSTAT ; MOV #511.,D6 ; throw data away ; TSTB VME(A5) ; BNE 15$ ;12$: ; MOVB RDDATA(A4),(A2)+ ; read data into ddb buffer ; DBF D6,12$ ; BR RDSTAT ;20$: ; MOVB RDSTS(A4),D7 ; ANDB #CMDDON,D7 ; BEQ 20$ ; MOVB RDDATA(A4),(A2)+ ; DBF D6,20$ 30$: MOVB RDSTS(A4),D7 ; check for status byte ANDB #CMDDON,D7 ; and loop untill ready BEQ 30$ RDSTAT: CALL GETSTS ; get status bytes TST D1 ; = 0 no error read next sector BEQ RDDONE ; no error return for next sector CALL REQSEN ; read error code TST D1 RDDONE: RTN WRTSEC: MOVW #1,DAT4(A5) ; set up to write 1 sector MOVB STPRTE(A5),DAT5(A5) ; set step rate seek option MOVB DRVSEL(A5),DAT1(A5) ; get drive select MOVB DAT1(A5),D7 ; drive # and high track address AND #0E0,D7 ; save only drive # 0 or 1 SWAP D7 ; in high word byte 3 & 4 OR D5,D7 ; get drive logical sector address MOVB D7,DAT3(A5) ; store low address ROR D7,#8 MOVB D7,DAT2(A5) ; store middle address ROR D7,#8 MOVB D7,DAT1(A5) ; store high address & drive # MOVB #WRIT,DAT0(A5) ; write sector command CALL SNDCMD 10$: MOVB RDSTS(A4),D7 ; controller ready to receive data ANDB #CMDDON,D7 ; from host to disk BEQ 10$ ; loop untill controller ready MOV #511.,D0 ; send 512 bytes TSTB VME(A5) BNE 30$ 20$: MOVB (A2)+,WTDATA(A4) DBF D0,20$ BR 40$ 30$: MOVB RDSTS(A4),D7 ; status byte pending ? ANDB #CMDDON,D7 ; loop untill byte ready BEQ 30$ MOVB (A2)+,WTDATA(A4) DBF D0,30$ 40$: MOVB RDSTS(A4),D7 ANDB #CMDDON,D7 BEQ 40$ CALL GETSTS ; get status TST D1 ; 0 = no error BEQ 50$ CALL REQSEN ; get error into d1 TST D1 50$: RTN SNDCMD: TSTB VMESYS(A5) ; check for vme yet ? BNE 20$ ; - 1 = check already MOVB #-1,VMESYS(A5) ; flag vmesys as checked MOV SYSTEM,D1 ; system attribute and status flag PUSH D1 ; save d1 AND #4,D1 ; am1000 ? BNE 10$ ; yes done MOV @SP,D1 ; get system back into d1 AND #40,D1 ; 1500 ? (40hex) BEQ 10$ ; no done MOVB #-1,VME(A5) ; set vme flag 10$: POP 20$: LEA A3,DAT0(A5) ; get output bytes MOV #5,D1 ; output 6 bytes to controller CTLRDY: MOVB RDSTS(A4),D7 ; controller status ANDB #BUSY$,D7 ; controller free BNE CTLRDY ; if not loop untill ready MOVB #DRVRDY,WTDATA(A4) ; test drive ready MOVB #0,CTLRST(A4) ; reset controller NOP NOP MOVB SELCTL(A5),D7 ; get controller # (select 1-8) MOVB D7,CTLSEL(A4) ; send to controller ORB #010,D7 ; set controller select bit MOVB D7,CTLSEL(A4) ; select controller CMDRDY: MOVB RDSTS(A4),D7 ; read status ANDB #BUSY$,D7 ; check busy BEQ CMDRDY ; loop until ready MOVB #0,CTLRST(A4) ; reset controller 10$: MOVB RDSTS(A4),D7 ; read sasi status ANDB #018,D7 ; strip to i/o and c/d XORB #8,D7 ; xor c/d place in i/o state CMPB D7,#018 BNE 10$ TSTB VME(A5) ; vme system BNE NOVME ; no skip it VVME: MOVB RDSTS(A4),D7 ; read sasi status ANDB #CMDDON,D7 ; check MSG command done BEQ VVME ; wait for command to complete SNDVME: ; send block of data hardware handshake MOVB (A3)+,WTDATA(A4) ; send command to controller DBF D1,SNDVME BR ENDSND ; skip non vme transfer NOVME: ; non vme transfer one byte at a time MOVB RDSTS(A4),D7 ; read sasi status ANDB #CMDDON,D7 ; chg MSG command done BEQ NOVME ; wait for command to complete MOVB (A3)+,WTDATA(A4) ; send command to controller DBF D1,NOVME ; one byte at a time ENDSND: RTN GETSTS: CLR D1 ; clear error check register ; completion code 2 bytes ; 0 = error ; 1 = 0 MOVB RDDATA(A4),D1 ; read error code from s100 HA 10$: MOVB RDSTS(A4),D7 ; check status port is byte transfered ANDB #1,D7 ; yes BEQ 10$ 20$: MOVB RDSTS(A4),D7 ; check status ANDB #CMDDON,D7 ; controller free ? BEQ 20$ MOVB RDDATA(A4),D2 30$: MOVB RDSTS(A4),D7 ; check status ANDB #BUSY$,D7 ; controller free ? BNE 30$ AND #2,D1 ; bit 1 = 1 only if error occured RTN REQSEN: MOVB #RSENSE,DAT0(A5) ; read controller error MOVB DRVSEL(A5),DAT1(A5) ; controller select ; MOVW D5,DAT2(A5) ; logical sector # in error ; CLRB DAT5(A5) ; controll byte ORB #2,DAT4(A5) CALL SNDCMD LEA A6,BADTRK(A5) ; bad block address MOV #3,D0 ; read 4 bytes (0 - 3) ; byte 0 = error code ; byte 1-3 = address TSTB VME(A5) ; BNE 30$ 10$: MOVB RDSTS(A4),D7 ; error data ready ? ANDB #CMDDON,D7 ; loop untill ready BEQ 10$ 20$: MOVB RDDATA(A4),(A6)+ ; read byte DBF D0,20$ ; untill done BR 40$ 30$: MOVB RDSTS(A4),D7 ; check for status byte pending ANDB #CMDDON,D7 BEQ 30$ ; loop untill ready MOVB RDDATA(A4),(A6)+ ; read status byte DBF D0,30$ 40$: MOVB RDSTS(A4),D7 ; check for command done ANDB #CMDDON,D7 BEQ 40$ MOVB RDDATA(A4),D7 ; read completion code 50$: MOVB RDSTS(A4),D7 ; check for controller not busy ANDB #1,D7 ; controller free ? BEQ 50$ ; loop untill free 60$: MOVB RDSTS(A4),D7 ANDB #CMDDON,D7 BEQ 60$ MOVB RDDATA(A4),D7 70$: MOVB RDSTS(A4),D7 ANDB #BUSY$,D7 BNE 70$ CLR D1 ; clear work register ; sense byte = 0 ; bits 0-3 = error code ; bits 4-5 = error type ; bit 7 = valid address ANDW #03F,BADTRK(A5) ; save error code & error type only MOVW BADTRK(A5),D7 ; ANDW #0F,D7 ; sense byte only BEQ SENOK MOVB BADTRK(A5),D1 SENOK: RTN SETPAR: CRLF TYPESP KBD CTRLC ABORT GTDEC CMP D1,ALTRKS(A5) ; cannot be greater than max # BLOS OKALTK ; drive formatted for TYPE ; too many output largest MOV ALTRKS(A5),D1 ; number driver can support DCVT 0,OT$TRM TYPECR < bad blocks is maximum> BR SETPAR OKALTK: MOV D1,ALTRKS(A5) TYPESP KBD CTRLC ABORT GTDEC MOVW D1,PREALO(A5) CTRACK: TYPESP KBD CTRLC ABORT BYP CMPB @A2,#'N BEQ 10$ CMPB @A2,#'Y BNE CTRACK BSET #4,PRAMTR(A5) ; display current track 10$: TYPESP KBD ABORT BYP CMPB @A2,#'N BEQ 20$ CMPB @A2,#'Y BNE 10$ BSET #6,PRAMTR(A5) ; flag soft errors 20$: RTN SETSNO: TYPESP KBD CTRLC ABORT BYP MOV #9.,D7 ; 0 to 9 makes 10 characters LEA A3,DSKSNO(A5) ; save drive serial number here GETSNO: CMPB @A2,#13. ; cr = end of serial number BEQ ENDSN MOVB (A2)+,(A3)+ ; move a byte DBF D7,GETSNO ; do it 9 times or cr RTN ENDSN: CLRB (A3)+ ; pad unused characters with nulls DBF D7,ENDSN ; untill max 10 characters RTN FMTYN: TYPESP KBD ABORT CMPB (A2),#'N ; no skip formatting BEQ 10$ CMPB (A2),#'Y ; yes format drive BNE FMTYN BSET #5,PRAMTR(A5) ; ok to format drive 10$: RTN BLDMFD: ; badblk.sys layout ; bytes 0-1 next block link ; bytes 2-3 32773,8005H,[TSM] ; bytes 4-13 serial number ; bytes 14-17 hash total ; hash total = word sum of all bad blocks SAVE D0,D1,D2,D3,D4,D5,A0,A1,A2,A3,A4,A5 MOV D.DVR+DDB(A5),A1 ; device driver address MOVW DX.CYL(A1),D5 ; calculate total # of usable logical ADDW DX.ATC(A1),D5 ; blocks on disk. This number MUL D5,DX.HED(A1) ; multiplied X 512 = disk capacity MUL D5,DX.SEC(A1) ; cyl X hd X sec LEA A2,DNGCYL ; ASCII DIAGNOSTIC CYLINDER CALL WRTSEC ; write out diagnostic cylinder to disk JNE WRTEND ; error = cannot write to dx cylinder LEA A2,DDB(A5) CALL $INMFD ; initialize a mfd JNE MFDEND ; error = cannot initialize mfd MOVW #0102,D1 ; add ppn [1,2] CLR D2 CALL $ADPPN ; add [1,2] to our disk JNE PPNEND ; error cannot add ppn MOVW #[BAD],D.FIL+DDB(A5) ; filname MOVW #[BLK],+DDB(A5) ; MOVW #[SYS],D.EXT+DDB(A5) ; OPENO DDB(A5) ; open badblk.sys for output JNE BBSEND ; error cannot open MOVW #08005,D1 ; 32773. [TSM] ? header FILOTW DDB(A5) ; write word to opened file LEA A1,DSKSNO(A5) ; output our serial # MOV #4,D2 ; which is 10 bytes 10$: MOVW (A1)+,D1 ; write serial number to drive FILOTW DDB(A5) DBF D2,10$ MOV ALTADD(A5),A1 ; index badblk area MOV TOTLTK(A5),D2 ; Max # of alternate tracks ASL D2,#1 ; multiply X 2 = # entries DEC D2 ; count from 0 CLR D3 20$: CLR D7 MOVW (A1)+,D7 ; create badblk hash count ADD D7,D3 ; which is the sum of all DBF D2,20$ ; bad blocks MOV D3,D1 ; output low word FILOTW DDB(A5) SWAP D1 FILOTW DDB(A5) ; output high word MOV ALTADD(A5),A1 ; index badblk area MOV TOTLTK(A5),D2 ASL D2,#1 DEC D2 30$: MOVW (A1)+,D1 ; now output each FILOTW DDB(A5) ; individual bad block DBF D2,30$ ; to badblk.sys on disk CLR D1 40$: FILOTW DDB(A5) ; write nulls to remaining CMP 060(A5),#01FE ; unused blocks BNE 40$ CLOSE DDB(A5) ; close badblk.sys file JNE MFDEND MOV #512.,D.SIZ+DDB(A5) ; buffer size INIT DDB(A5) ; init our ddb CLR D1 MOVW PREALO(A5),D1 ; number of accounts to preallocate LEA A2,DDB(A5) CALL $PAMFD ; allocate extra mfd blocks JNE PAAEND DSKMNT DDB(A5),#MT$PHY ; do a physical mount MOV DEVTAD(A5),A0 ; our device table INTNLG: MOV DEVLNK(A0),A0 ; anymore logicals this drive MOV A0,D7 BEQ ENDMFD ; 0 = end of table MOVW DEVMNT(A0),D7 ; is this device mounted ANDW #8,D7 ; all logicals this drive BEQ ENDMFD ; are unmounted (there is no mfd !!!) MOVW DEVNAM(A0),D.DEV+DDB(A5) MOVW DEVNO(A0),D.DRV+DDB(A5) CLR D.FIL+DDB(A5) ; remove badblk.sys CLRW D.EXT+DDB(A5) INIT DDB(A5) MOV #512.,D.SIZ+DDB(A5) DSKMNT DDB(A5) ; mount the disk LEA A2,DDB(A5) CALL $INMFD ; initialize mfd MOVW #0102,D1 ; add ppn [1,2] CLR D2 CALL $ADPPN ; add [1,2] to our disk CLR D1 MOVW PREALO(A5),D1 CALL $PAMFD BR INTNLG ; initialize next logical ENDMFD: REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0 RTN WRTEND: REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0 TYPECR JMP ENDIT MFDEND: REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0 TYPECR JMP ENDIT PPNEND: REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0 TYPECR JMP ENDIT BBSEND: REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0 TYPECR JMP ENDIT PAAEND: REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0 TYPECR JMP ENDIT DNGCYL: ASCIZ /DIAGNOSTICCYLINDER/ EVEN WORD 1343. WORD 0 BLKW 250. ; buffer filler ENDIT: EXIT END .