;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 <C R T X E B >
MOVW #-0DF,D1 ; end reverse video
TCRT
MOVW #0101,D1 ; cursor 1,1
TCRT
TYPESP <Version ->
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 <Program restricted to use on local system only>
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 does not exist> ; 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 <?Cannot certify>
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 <?Cannot certify>
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 <The driver for>
PFILE DDB(A5) ; output device driver
TYPECR < is not compatible wiht this version of CRTXEB>
TYPECR <?Program aborted.>
EXIT
OKVER:
CMPW DX.WIN(A1),#071C7 ; xebex controller
BEQ OKXEB ; is this a supported controller
TYPE <?>
TYPESP <The controller for>
PFILE DDB(A5)
TYPECR < is not compatible with this version of CRTXEB.>
TYPECR <?Program aborted.>
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 <?Insufficient memory for alternate track table>
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 <Begin certification of>
PFILE DDB(A5)
CRLF
CRLF
CALL FMTYN ; should we format drive
BTST #5,PRAMTR(A5) ; skip formatting if not set
BEQ VERFY
TYPECR <Formatting Drive>
CALL FMTDRV ; format drive
CRLF
VERFY:
TYPECR <Verifying Contents>
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 <Certification complete>
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 <?Certification incomplete>
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 <?Error during initialization>
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 <?Format drive error>
JMP ABORT
CALERR:
TYPECR <?Error during recalibrate>
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 <Enter Starting track:>
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 <Current track is:>
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 <Block>
MOV D5,D1
OCVT 0,OT$TRM!OT$LSP!OT$TSP
TYPECR <did not verify>
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 <?Cylinder zero did not certify>
JMP ABORT
BADALT:
TYPECR <?Device has exceeded maximum number of errors>
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 <Enter maximum acceptable number of bad blocks:>
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 <Enter number of accounts to preallocate:>
KBD
CTRLC ABORT
GTDEC
MOVW D1,PREALO(A5)
CTRACK:
TYPESP <Display current track? (Y or N):>
KBD
CTRLC ABORT
BYP
CMPB @A2,#'N
BEQ 10$
CMPB @A2,#'Y
BNE CTRACK
BSET #4,PRAMTR(A5) ; display current track
10$:
TYPESP <Flag soft errors defective? (Y or N):>
KBD ABORT
BYP
CMPB @A2,#'N
BEQ 20$
CMPB @A2,#'Y
BNE 10$
BSET #6,PRAMTR(A5) ; flag soft errors
20$:
RTN
SETSNO:
TYPESP <Enter serial number (10 char. max.):>
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 <Format Disk? (Y or N):>
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],<D.FIL+2>+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 <Unable to write diagnostic cylinder>
JMP ENDIT
MFDEND:
REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0
TYPECR <Unable to initialize MFD>
JMP ENDIT
PPNEND:
REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0
TYPECR <Unable to add [1,2] PPN>
JMP ENDIT
BBSEND:
REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0
TYPECR <Unable to open BADBLK.SYS >
JMP ENDIT
PAAEND:
REST A5,A4,A3,A2,A1,A0,D5,D4,D3,D2,D1,D0
TYPECR <Unable to allocate extra MFD blocks>
JMP ENDIT
DNGCYL:
ASCIZ /DIAGNOSTICCYLINDER/
EVEN
WORD 1343.
WORD 0
BLKW 250. ; buffer filler
ENDIT:
EXIT
END