;  
; SCSIDirectCmd, based on "SCSIRdWt" 
;
; Original version by Paul Harker
; BUSY check on SELECT
; improved handshake on MSGIN, CMDOUT 
; 26 May 1992 TM
; 17 Jun 1992 TM	SCSI BUSY FLAG ADDED for simaltaneous copy bug
; 15 Sep 1992 TM        GENERIC version
; 05 Oct 1992 HL        SCSI-Direct version
;			New selection of unit
;			Return status when sel. timed out
;			Return status zero on normal return
;			Buffers not on 512 b boundaries are treated with
;			  their actual length
; 22 Oct 1992 HL	Return status bug fixed
; 25 Oct 1992 HL	Bug introduced above fixed
;
	include		"exec/types.i"
	include		"exec/io.i"
	include		"exec/devices.i"
	include		"exec/tasks.i"
	include		"exec/interrupts.i
	include		"devices/scsidisk.i"
	include		"mydev.i"
	include		"scsi.i"

	Public		SCSIDirectCmd

; In params:
;	LU in d2
; 	Cmd ptr in a2
; 	Buffer ptr in a0
; 	Buffer length in d0
;
; Out params:
;	IO_Status in d0
;	SCSI_Status in d7

SCSIDirectCmd:
	bset.b	#3,NCR+4	;TM!!! EOP INTERRUPT bit is used for
	bne.s	SCSIDirectCmd	;TM!!! SCSI BUSY FLAG
	move.b	#$08,NCR+4	;TM!!!
	movem.l	d4-d6/a3-a5,-(sp)	;save regs
	clr.b	d7		;clear error flag ; HL
STILLbsy1:
	btst.b	#6,NCR+8	; TM BUSY check
	bne.s	STILLbsy1	; TM wait if still busy
Drive:
	moveq	#$1,d4
	lsl.l	d2,d4		;shift to address bit
	or.b	#$80,d4		;add addresses
	move.b	d4,NCR		;load addresses
	move.b	#$5,NCR+2	;assert BUS with address

Selection:
	bsr	SELph		;select the target

End:
	bclr.b	#3,NCR+4	;TM!!! clear SCSI BUSY FLAG
	movem.l	(sp)+,d4-d6/a3-a5	;restore regs
	rts			;return to caller

SELph:		;select the target
	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  #HFERR_SelTimeout,d0 ;set drive not ready error ; HL
	rts

SLECT:
	and.b	#$FB,NCR+2	;clr SEL
      
NextPhase:	;Check the SCSI bus phase
	move.b	#$0,NCR
	move.b	#$0,NCR+6	;clear TCR
	btst.b	#5,NCR+8	;test REQ
	bne.s	GotREQ		;if REQ it must be busy...
	btst.b	#6,NCR+8	;check BUSY
	beq	Done		;bus free
	bra	NextPhase	; still waiting for REQ
GotREQ:
	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      
	bne	MSGINph		;TM
;	bra.s	MSGOUTph	;TM
	bra	MSGOUTph	;TM		
Dat:		;check to see if it is data in or out
	btst.b	#2,NCR+8	;check I/O
;	bne.s	RDATph
	bne	RDATph		;TM
;	bra.s	SDATph		;TM
	bra	SDATph		;TM
CMDph:		;send command
	move.l	a2,a4		;set the cmd buffer add
	move.b	#$02,NCR+6	;set TCR to command phase
Send:		;send x characters to the target
	btst.b	#6,NCR+8	;TM busy check
	beq	Done		;TM busy check
	btst.b	#5,NCR+8	;test for REQ
	beq.s	Send		;wait for REQ
	btst.b	#3,NCR+10	;test phase match
;	beq.s	NextPhase
	beq	NextPhase	;TM
	move.b	(a4)+,NCR	;set the byte
	ori.b	#$10,NCR+2	;set ACK
CMDReq:
	btst.b	#6,NCR+8	;TM busy check
	beq	Done		;TM busy check
	btst.b	#5,NCR+8	; TM test for REQ
	bne.s	CMDReq		; TM wait for REQ deasserted
	andi.b	#$EF,NCR+2	;clr ACK
	bra	Send   

STATph:		;get status byte
	move.b	NCR,d7		;move STATUS into Stat     temp
	ori.b	#$10,NCR+2	;set ACK
STATReq:
	btst.b	#6,NCR+8	;TM busy check
	beq	Done		;TM busy check
	btst.b	#5,NCR+8	; TM test for REQ
	bne.s	STATReq		; TM wait for REQ deasserted
	andi.b	#$ef,NCR+2	;clr ACK
	bra	NextPhase

MSGINph:	;only msg supported is COMPLETE..so we just ack it
	ori.b	#$10,NCR+2	;set ACK   
MSGINReq:
	btst.b	#6,NCR+8	;TM busy check
	beq	Done		;TM busy check
	btst.b	#5,NCR+8	; TM test for REQ
	bne.s	MSGINReq	; TM wait for REQ deasserted
	and.b	#$EF,NCR+2	;clr ACK
STILLbsy:
	btst.b	#6,NCR+8	; TM BUSY check
	bne.s	STILLbsy	; TM wait if still busy
Done:		;did we end normally ?
	move.b	d7,d6
	and.b	#$0e,d6 ; For normal SCSI devices, use this ; HL
;;;	and.b	#$0c,d6 ; For (older) adaptec cards, use this ; HL
	cmp.b	#$00,d6
	beq	StatOk
	cmp.b	#$04,d6
	beq	StatOk
	move.b	#HFERR_BadStatus,d0
	rts	;do a clean end
StatOk:
	move.b	#0,d0
	rts	;do a clean end

MSGOUTph:	;send message to target
	bra	NextPhase	;error try again

SDATph:		;send data to target
	move.l	a0,a4		;set the data buffer add
	move.b	#$00,NCR+6	;set TCR to send data
SendData:	;send x characters to the target
	btst.b	#6,NCR+8	;TM busy check
	beq	Done		;TM busy check
	btst.b	#5,NCR+8	;test for REQ
	beq.s	SendData	;wait for REQ
	btst.b	#3,NCR+10	;test phase match
;	beq.s	NextPhase
	beq	NextPhase	;TM
;	move.b	#$02,NCR+4	;Set DMAMODE
	bset.b	#1,NCR+4	;TM!!!
	move.b	#$00,NCR+12	;start DMA recieve
	move.l  d0,d4
	and.l	#511,d4		;Check if length is even 512b
	bne	UnevenSend
	moveq	#64,d4		;load counter..we do 512 byte blocks
LoopTop:
	move.b	(a4)+,DMA	;set byte 0
	move.b	(a4)+,DMA	;set byte 1
	move.b	(a4)+,DMA	;set byte 2
	move.b	(a4)+,DMA	;set byte 3
	move.b	(a4)+,DMA	;set byte 4
	move.b	(a4)+,DMA	;set byte 5
	move.b	(a4)+,DMA	;set byte 6
	move.b	(a4)+,DMA	;set byte 7
	subq	#1,d4
	bne.s	LoopTop
SendLast:
;	move.b	#$0,NCR+4	;clear DMAMODE
	bclr.b	#1,NCR+4	;TM!!!
	bra	SendData

UnevenSend:
	move.l	d0,d4		;load counter.. we do bufsize bytes
UnevenSendLoop:			
	move.b	(a4)+,DMA	;set byte 
	subq	#1,d4		;decrement counter
	bne.s	UnevenSendLoop	;done with block?
	bra.s	SendLast

RDATph:		;receive data fron target
	move.l	a0,a4		;set the data buffer add
	lea	DMA+12,a5	;set DMA recieve Base
	move.b	#$01,NCR+6	;set TCR to receive data
RecData:
;	move.b	#$02,NCR+4	;Set DMAMODE
	bset.b	#1,NCR+4	;TM!!!
	move.b	#$00,NCR+14	;start DMA recieve
	move.l  d0,d4
	and.l	#511,d4		;Check if length is even 512b
	bne	UnevenRec
	moveq	#63,d4		;load counter..we do 512 byte blocks
RecLoop:
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	subq	#1,d4		;decrement counter
	bne.s	RecLoop		;done with block?
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
	move.b	(a5),(a4)+
RecLast:
;	move.b	#$0,NCR+4	;disable ack/req
	bclr.b	#1,NCR+4	;TM!!!
	move.b	(a5),(a4)+	;read last byte of block
WRec:
	btst.b	#5,NCR+8	;test REQ
	bne.s	RReq		;Got it
	btst.b	#6,NCR+8	;check BUSY
	beq	Done		;Not Busy? must be Done.
	bra.s	WRec		;wait for REQ

UnevenRec:
	move.l	d0,d4		;load counter.. we do bufsize bytes
	subq	#1,d4		;decrement counter
UnevenRecLoop:			
	move.b	(a5),(a4)+
	subq	#1,d4		;decrement counter
	bne.s	UnevenRecLoop	;done with block?
	bra.s	RecLast

RReq:
	btst.b	#3,NCR+10	;test for phase match
	beq	NextPhase
	bra.s	RecData
;
	END
