home *** CD-ROM | disk | FTP | other *** search
- ;---------------------------------------------------------------;
- ;---------------------------------------------------------------;
- ; SCSI DRIVER - for AMSCSI hardware ;
- ; NCR 53C80 - SCSI ctrl chip ;
- ; Rich Frantz 24-may-87 ;
- ; Version 0.1 ;
- ; This routine should be called from a DOS handler ;
- ; it should be noted that all command data should be ;
- ; checked for validity before calling. Also I have ;
- ; not finished the error handling. ;
- ;---------------------------------------------------------------;
- ;---------------------------------------------------------------;
-
- ; equates
-
- NCR equ $800001 ;SCSI ctrl chip
- M250 equ $1E000 ;250 mSEC dly
- U200 equ $64 ;200 uSEC dly
- SELlp equ $100 ;Selection timeout
- LUv equ $1 ;select drive 0
- TarIDv equ $1 ;target I D
- InitIDv equ $8 ;Initiator I D
- ;
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- ; REMOVE THIS START UP ROUTINE WHEN USING
- ; AS A REAL AMIGA DRIVER - THE CALLING ROUTINE SHOULD
- ; CALL ReadSCSI: , WriteSCSI: , or FormatSCSI: DIRECTLY
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- ; equates for test routines ( START )
- ;
- Data_Len equ $100
- Sect equ $140000 ;bytes not sectors
- Loop equ 100
- Data_Len1 equ $300
- Sect1 equ $200
-
- ;---------------------------------------------------------------;
- ; a0 = IO_DATA - MUST BE SETUP BY CALLER ;
- ; a6 = DEVICE POINTER - MUST BE SETUP BY CALLER ;
- ; a4 = SCSI buffer pointer ;
- ; a5 = unassigned ;
- ; d0 = IO_LENGTH ( in bytes) - MUST BE SETUP BY CALLER ;
- ; d1 = IO_OFFSET - MUST BE SETUP BY CALLER ;
- ; d4 = unassigned - used by driver ;
- ; d5 = unassigned - used by driver ;
- ; d6 = Tid - setup by this driver (target I D) ;
- ; d7 = Iid - setup by this driver (iniator I D) ;
- ;---------------------------------------------------------------;
-
- START: ; this starts the program by fake setting the regs
- move.l #Loop,d2 ;set loop counter
- move.b #TarIDv,TarID ;set up traget ID
- move.b #InitIDv,InitID ;set up initiator ID
- move.b #LUv,LU ;set up logical unit #
- STLP: move.l #Data_Buf,a0 ;set up IO_DATA
- move.l #Data_Len,d0 ;set up IO_LENGTH
- move.l #Sect,d1 ;set up IO_OFFSET
- bsr WriteSCSI ;go write it
- move.l #Data_Len1,d0 ;get new IO_LENGTH
- move.l #Sect1,d1 ;get new IO_OFFSET
- bsr ReadSCSI ;go read it
- subq.l #1,d2 ;dec counter
- bne.s STLP
- rts ;done
- ReadSCSI: ;read data from the SCSI
- movem.l d4/d5/d6/d7/a4/a5,-(sp) ;save regs
- bsr Build_CMD ;build the scsi cmd packet
- btst.b #0,ERROR ;check for any error
- bne.s ReadSCSI_End ;if so, exit
- move.b #$08,CMDBUF ;set cmd to read
- bsr SELph ;select the target
-
- ReadSCSI_End:
- movem.l (sp)+,d4/d5/d6/d7/a4/a5 ;restore regs
- rts ;return to caller
-
- WriteSCSI: ;send data to the SCSI
- movem.l d4/d5/d6/d7/a4/a5,-(sp) ;save regs
- bsr Build_CMD ;build the scsi cmd packet
- btst.b #0,ERROR ;check for any error
- bne.s WriteSCSI_End ;if so, exit
- move.b #$0A,CMDBUF ;set cmd to write
- bsr SELph ;do it
-
- WriteSCSI_End:
- movem.l (sp)+,d4/d5/d6/d7/a4/a5 ;restoer regs
- rts ;return to caller
-
- FormatSCSI:
- movem.l d4/d5/d6/d7/a4/a5,-(sp) ;save the regs
- move.w #$0400,CMDBUF ;set the cmd
- move.l #0,CMDBUF+2 ;clr the cmd packet
- bsr Unit_No ;set I D's & L U #
- btst.b #0,ERROR ;check for any error
- bne.s FormatSCSI_End ;if so, end
- bsr SELph ;do it
-
- FormatSCSI_End:
- movem.l (sp)+,d4/d5/d6/d7/a4/a5 ;restore th regs
- rts ; return to caller
-
- Request_Sense:
- movem.l d4/d5/d6/d7/a4/a5,-(sp) ;save regs
- move.w #$0300,CMDBUF ;set the cmd
- move.l #0,CMDBUF+2 ;clr the rest of the packet
- bsr Unit_No set I D's & L U #
- btst.b #0,ERROR ;check for any error
- bne.s Request_End ;if so exit
- bsr SELph ;do it
-
- Request_End:
- movem.l (sp)+,d4/d5/d6/d7/a4/a5 ;restore regs
- rts
- Build_CMD: ;build the scsi cmd packet
- move.l d1,d4 ;get the start sect #
- move.l d0,d5 ;get the #bytes to transfere
- asr.l #8,d5 ;shift 8 palces to get sectors
- and.l #$FF,d5 ;must be less than 1 byte
- asl.l #8,d5 ;move to upper byte in word
- move.w d5,CMDBUF+4 ;place in packet
- asr.l #8,d4 ;convert to sectors
- and.l #$000FFFFF,d4 ;mask out L U #
- move.l d4,CMDBUF ;place in packet
- Unit_No: ; add the logical unit # & get I D's
- move.l #$01,d5 ;load d0
- move.l #$0,d4 ;clear d4
- move.b TarID,d4 ;get TarID
- subq.l #$01,d4 ;-1
- bmi ID_ERROR ;oops ! TARGET ID NO GOOD
- asl.l d4,d5 ;shift TarID palces
- move.b d5,d6 ;store in target I D
- move.l #$01,d5 ;same for the Initiator (us)
- move.l #$0,d4 ;clear d4
- move.b InitID,d4 ;get InitID
- subq.l #$01,d4 ;-1
- bmi ID_ERROR ;oops ! INIT ID NO GOOD
- asl.l d4,d5
- move.b d5,d7 ;store in Init I D
- ; get Logical Unit # (drive #)
- move.l #$0,d5 ;clear d5
- move.b LU,d5 ;get the drive number
- asl.l #$5,d5 ;shift to LUN
- and.l #$E0,d5 ;mask all other bits
- or.b d5,CMDBUF+1 ;put it in the packet
- rts ;packet complete
-
- ID_ERROR:
- move.b #$01,ERROR ;set the drive not ready error
- rts
-
- SELph: ;select the target
- move.l #SELlp,d4 ;set SEL loop value
- SELph1: move.b #0,NCR+2 ;clr NCR
- move.b #0,NCR+4
- move.b #0,NCR+8
- ARB: move.b d7,NCR ;ld init I D
- or.b #1,NCR+4 ;set ARB bit
- NFREE: subq.l #$01,d4 ;dec SEL loop
- beq SEL_ERROR ;stuck in the loop
- btst.b #6,NCR+2 ;check arib in proc.
- beq NFREE ;wait
- nop ;delay for bus settle
- nop
- nop
- nop
- btst.b #5,NCR+2 ;check lost arb
- bne.s SELph1 ;try again
- ;
- ;check for higher priority
- ;
- move.l #0,d5 ;lcr d5
- move.b NCR,d5 ;load scsi data
- sub.b d7,d5 ;sub our id
- beq.s WIN ;if = we are the only bidder
- sub.b d7,d5 ;sub again
- bmi.s WIN ;if - we are the highest
- bra.s SELph1 ;try again
- WIN: btst.b #5,NCR+2 ;check lost arb bit
- bne.s SELph1 ;if lost , retry
- move.b #$0c,NCR+2 ;set SEL
- nop ;delay
- nop
- nop
- nop
- move.b d7,NCR ;load init I D
- or.b d6,NCR ;load target I D
- move.b #5,NCR+2 ;set SEL & Data Bus
- and.b #$FE,NCR+4 ;clr ARB
- and.b #$F7,NCR+2 ;clr BSY
- move.l #M250,d5 ;load timer
- loop1: btst.b #6,NCR+8 ;test BSY
- bne.s SLECT ;if busy , selected
- subq #1,d5 ;dec timer
- bne.s loop1 ;loop
- move.b #0,NCR ;clr I D's
- move.l #U200,d5 ;load timer
- loop2: btst.b #6,NCR ;test BSY
- bne.s SLECT ;if busy , selected
- subq #1,d5 ;dec timer
- bne.s loop2 ;loop
- bra SEL_ERROR ;selection failed
- SLECT: and.b #$FB,NCR+2 ;clr SEL
- ; NextPhase
- NextPhase: ;Check the SCSI bus phase
- btst.b #7,NCR+8 ;check RESET
- bne RSTph ;reset phase
- btst.b #6,NCR+8 ;check BUSY
- beq Done ;bus free
- btst.b #3,NCR+8 ;check C/D
- beq.s Dat ;data in/out phase
- btst.b #4,NCR+8 ;check MSG
- bne.s Message ;Message in/out phase
- btst.b #2,NCR+8 ;check I/O
- bne.s STATph ;stat phase
- bra.s CMDph ;command phase
- Message: ;check to see if it is message in or out
- btst.b #2,NCR+8 ;check I/O
- bne.s MSGINph
- bra.s MSGOUTph
- Dat: ;check to see if it is data in or out
- btst.b #2,NCR+8 ;check I/O
- bne.s RDATph
- bra.s SDATph
- Done: ;did we end normally ?
- btst.b #1,STAT ;do we have an error
- bne Return_ERROR
- rts ;return to caller
-
- RSTph: ;reset phase
- bra.s Done ;done
- CMDph: ;send command
- move.l #CMDBUF,a4 ;set the cmd buffer add
- move.b #$02,NCR+6 ;set TCR to command phase
- bra.s Send ;send the command
-
- STATph: ;get status byte
- move.l #STAT,a4 ;set the stat buffer add
- move.b #$03,NCR+6 ;set TCR to status phase
- bra.s Rec ;get the stat
-
- MSGINph: ;get message from target
- move.l #MSGINBUF,a4 ;set the message in buffer add
- move.b #$07,NCR+6 ;set TCR to message in phase
- bra.s Rec ;get the message
-
- MSGOUTph: ;send message to target
- bra NextPhase ;error try again
-
- RDATph: ;receive data fron target
- move.l a0,a4 ;set the data buffer add
- move.b #$01,NCR+6 ;set TCR to receive data
- bra.s Rec ;get the data
-
- SDATph: ;send data to target
- move.l a0,a4 ;set the data buffer add
- move.b #$00,NCR+6 ;set TCR to send data
-
- Send: ;send x characters to the target
- move.b (a4)+,NCR ;set the byte
- Send1: btst.b #5,NCR+8 ;test for REQ
- beq.s Send1 ;wait for REQ
- or.b #$10,NCR+2 ;set ACK
- Send2: btst.b #5,NCR+8 ;test REQ
- bne.s Send2 ;wait for /REQ
- andi.b #$EF,NCR+2 ;clr ACK
- btst.b #3,NCR+10 ;test pahse match
- bne.s Send
- bra NextPhase
-
- Rec: ;receive x characters form the target
- Rec1: btst.b #5,NCR+8 ;test REQ
- beq.s Rec1 ;wait for REQ
- move.b NCR,(a4)+ ;get byte from target
- or.b #$10,NCR+2 ;set ACK
- Rec2: btst.b #5,NCR+10 ;test REQ
- bne.s Rec2 ;wait for /REQ
- andi.b #$EF,NCR+2
- btst.b #3,NCR+10 ;test for phase match
- bne.s Rec
- bra NextPhase
-
- SEL_ERROR:
- move.b #$01,ERROR ;set drive not ready error
- rts
-
- Return_ERROR:
- ;must be finnished
- rts ;return to caller
-
- CMDBUF dc.b $0A,$00,$00,$00,$01,$00 ;command string (write 1 block)
-
- STAT ds.b $01 ;status word
-
- MSGINBUF ds.b $04 ;message buffer
-
- TarID ds.b $01 ;target ID location
-
- InitID ds.b $01 ;initiator ID location
-
- ERROR ds.b $01 ;error flag
-
- LU ds.b $01 ;logical unit #
-
- Data_Buf ds.b $500 ;data buffer (reduce the size when real)
-
- end
-