PAGE 55,132
TITLE Adaptec AIC-6360 BIOS Code
NAME ATSBIOS
.286p

;****************************************************************************;
;                                                                            ;
;   Module Name:  AIC-6360 BIOS Code                                         ;
;                                                                            ;
;   Basecode:     557302-00                                                  ;
;                                                                            ;
;   Author:       Tom Shea/Arlen Young                                       ;
;                                                                            ;
;   History:      10/28/88  First Revision Coded                             ;
;                 02/21/89  Fixed Bug in WaitIdl Routine which               ;
;                           was causing a hang at power up                   ;
;                 02/21/89  Fixed Bug in all Wait Routines which             ;
;                           prevented Timeout from occurring when            ;
;                           above hang occurred.                             ;
;                  06/26/89 Modified for AHA-1520/Sparrow                    ;
;                  09/20/89 debug                                            ;
;                  06/20/91 J.P. - Added floptical support, restructured     ;
;                           module to eliminate translation layer            ;
;                           inherited from old 1540 BIOS, added              ;
;                           pass-thru, support for new 255/63 BIOS           ;
;                           translation scheme, support for new identify     ;
;                           SCSI devices (AH=06) function                    ;
;                  09/28/92 R. Maranon                                       ;
;                           Eliminated new Function AH=06 for Floptical.     ;
;                           Added support for new AIC-6360 features.         ;
;                           Added BIOS rerouter.                             ;
;                           Added support for TEAC SCSI/Floppy.              ;
;                           Moved all Floptical/SCSI Floppy functions to     ;
;                           separate module.				     ;
;		   04/01/93 YWL
;			    Modified Basecode Number for V 1.01L release.
;                                                                            ;
;   Description:  This module contains the SCSI interface code which         ;
;                 is specific to the AIC-6360 SCSI protocol controller chip. ;
;                                                                            ;
;                 The SCSI BIOS allows Adaptec host adapters to support      ;
;                 up to 2 SCSI CCS hard drives under DOS without a device    ;
;                 driver.  The system may have a standard hard disk          ;
;                 controller running concurrently with the host adapter      ;
;                 BIOS with the total drive count limited to 2.              ;
;                 Booting capability is provided from the first hard         ;
;                 drive in the system.                                       ;
;                                                                            ;
;                 09/28/92 R. Maranon                                        ;
;                                                                            ;
;                 The SCSI BIOS will aslo support up to two Floptical/SCSI   ;
;                 floppy drives.                                             ;
;                                                                            ;
;****************************************************************************;

;;***************************************************************************;
;                                                                            ;
;   Copyright 1988-1993 Adaptec, Inc.  All rights reserved. This software contains;
;   the valuable trade secrets of Adaptec.  The software is protected under  ;
;   copyright laws as an unpublished work of Adaptec.  Notice is for infor-  ;
;   mational purposes only and does not imply publication.  The user of this ;
;   software may make copies of the software for use with parts manufactured ;
;   by Adaptec or under license from Adaptec and for no other use.           ;
;                                                                            ;
;;***************************************************************************;


PAGE

include sbios.inc
include biosequs.inc
include global.inc
include int4b.inc

CODE SEGMENT PUBLIC 'CODE'
ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING

SUBTTL External Routines and Definitions
PAGE

;  External Routines

EXTRN   ECDTBL:near			;sbios.asm
EXTRN   CSNMAX:ABS			;sbios.asm
EXTRN   DspStr:near			;sbios.asm
EXTRN   DspErr:near			;sbios.asm
extrn	chk_rr:near			;sbios.asm

EXTRN   CDFMSG:near			;1520.asm
EXTRN	DspMsg3:NEAR			;sbios.asm
EXTRN	Get_Jumpers:NEAR		;biosdrvr.asm
EXTRN	bios_driver:near		;biosdrvr.asm
EXTRN	bios_init:NEAR			;biosdrvr.asm
EXTRN	HA_Return_Config_Cmd:NEAR	;biosdrvr.asm
EXTRN	Check_Bus:NEAR			;biosdrvr.asm
EXTRN	DspMsg:NEAR			;options module
EXTRN	DspErr$:NEAR			;options module

EXTRN	ChkForLockedState:near		;floppy.asm

;************************************************************************
;  External Data
;		Progress and Error messages in B636OPT.ASM
;************************************************************************


EXTRN	targ_0:BYTE
EXTRN	targ_1:BYTE
EXTRN	targ_x:BYTE
EXTRN	targ_n:BYTE

EXTRN	vidmsg0:BYTE
EXTRN	vidmsg1:BYTE
EXTRN	vidmsg2:BYTE
EXTRN	vidmsg3:BYTE
EXTRN	vidmsg4:BYTE
EXTRN	vidmsg5:BYTE
EXTRN	vidmsg6:BYTE
;EXTRN	vidmsg7:BYTE
EXTRN	vidmsg8:BYTE
EXTRN	vidmsg9:BYTE
EXTRN	vidmsg10:BYTE
EXTRN	vidmsg11:BYTE


;******************************************************************************
;
;	Sparrow device port definitions
;
;******************************************************************************

	EXTRN	BasePort:ABS		;base port address

dmacntrl1 EQU	BasePort+13h		;dma control 1		  (write/read)
sparstack EQU	BasePort+1Dh		;16 byte stack in Sparrow (write/read)

; *** miscellaneous ***
HEADCNT = 64        			;Default to 64 head BIOS

SUBTTL Code Segment: Do_DiskIO Routine
PAGE

;  *** Do_DiskIO - Perform Single threaded disk I/O Operation
;
;       Entry:  DS -> SysBioData
;               ES -> Segment of user Buffer
;		BP -> SCB structure on local stack
;
;       Exit:   AH - Status of Operation
;               C set if Status is Nonzero
;

        ASSUME DS:SysBioData

        Public  Do_diskIO
Do_diskIO       proc    near

	; test if rerouter in place
	call	TestRR
	jz	ddio_0000
	call	AltSCSIProc
	jmp	short ddio_0100
ddio_0000:
	call	bios_driver		;execute pc command
ddio_0100:
	mov	al,[bp].dtst
	and	al,1eh			;mask out reserved and V.U. bits
	cmp	al,stat08		;target busy?
	jne	Do_diskIO_cont
	mov	word ptr [bp].dhst,0	;clear return status fields

        push    cx
        push    bx                      ;Push Timeout value
        push    dx                      ;Push Target ID
	mov	bx,CmdTmo		;inter-command delay
	call	SetTmo
InterCmnd_Delay:
	call	CheckTmo
	jnc	InterCmnd_Delay
	pop	dx
	pop	bx
	pop	cx
	jmp	Do_diskIO		;try command again

Do_diskIO_Cont:

        jmp	CvtStat                 ;Check for error

CvtStat_done:
        ret


diskIOFld:

        mov     ah,BERHNG               ;If there was a problem
        stc                             ;sending the command, return
        ret                             ;with controller failure

Do_diskIO       endp




;  Wait_For  subroutine -
;
;	This subroutine is called by the Sparrow BIOS Driver when a substantial
;	delay is anticipated.  It returns the CPU to the system via INT 15.
;	INT 15 will return to this subroutine on its own accord or when prompt-
;	ed by a Sparrow interrupt.
;

	PUBLIC	Wait_For
Wait_For	PROC	NEAR

	mov	ah,90h
	mov	al,00h
	int	15h
	ret

Wait_For	ENDP


SUBTTL  disk I/O Error Handling routines
PAGE

;  *** CvtStat - Convert Error (if any) to BIOS Status
;
;       Entry:  AL - Adapter return status
;
;       Exit:   AH - BIOS Status of Operation
;		CY set if error
;

	PUBLIC Cvtstat
CvtStat proc    near


	mov	al,err00		;host adapter error, or
	mov	ah,stat00		;target problem?
	cmp	WORD PTR [bp].dhst,ax
	jne	CvtStat_Err
CvtStat_NoErr:
	clc
	jmp	CvtStat_Done

CvtStat_Err:

	mov	al,[bp].dtst		;target status error?
	cmp	al,err00
	jne	Target_Err		;  must be Host adapter error if no
HA_Error:

	mov	al,[bp].dhst		;host status byte in al
	cmp	al,SCB_SELTMO		;Selection timeout?
        mov     ah,BERHNG       	;Set Device Timeout status
	je	CstDone			;  jump if yes
	cmp	al,SCB_OVERRUN		;data overrun?
	mov	ah,BEROVR 		;Return Data Overrun error
	je	CstDone   		;  jump if yes

	cmp	al,SCB_BUSFREE		;unexpected bus free?
        mov     ah,BERCNT       	;Set controller error
	je	CstDone   		;  jump if yes
	cmp	al,SCB_BUSPHE		;scsi bus sequence error?
        mov     ah,BERCNT       	;Set controller error
	je	CstDone   		;  jump if yes
	cmp	al,SCB_BADCMD		;invalid command code?
        mov     ah,INVCMD        	;Set invalid command status
	je	CstDone   		;  jump if yes
	cmp	al,SCB_BADPARAM		;invalid command parameter?
        mov     ah,INVCMD        	;Set invalid command status
	je	CstDone   		;  jump if yes

	; set controller error for remaining errors (bus reset, request
	; aborted, and request/target aborted)

        mov     ah,BERCNT       	;Set controller error
	jmp	CstDone   	

Target_Err:
	mov	al,[bp].dtst		;non-zero target completion status
	and	al,1eh			;mask out reserved & V.U. bits
        cmp     al,TARGERR      	;Was error from Target ?
        jne     Try_ResConflict

        jmp	GetSense        	;If so, do a Sense operation

GetSense_done:

	cmp	ah,0			;no error status?
	je	CvtStat_NoErr
	stc
	jmp	CvtStat_done

Try_ResConflict:
        cmp     al,RESERR               ;If Reserved Address
        jne     Unknown_TargetStatus
        mov     ah,BERDNR               ;Return Drive not Ready
	jmp	CstDone
Unknown_TargetStatus:
        mov     ah,BERUND               ;If none of above,
CstDone:

        stc
	jmp	CvtStat_done

CvtStat endp




;  *** GetSense - Get Adapter Sense Data and convert to BIOS Status
;
;
;       Exit:   AH - BIOS Status of Operation
;

	public GetSense
GetSense        proc    near

	mov	CmdByte,cmd03		;Request Sense opcode
	mov	ax,bp
	add	ax,paralist		;overlay SCSI CDB and CDB length
	mov	Xfer_Offset,ax
	mov	ax,ss			;inquiry data -> 2000:0
	mov	es,ax
	mov	ax,14			;get 14 bytes of request sense data
	call	set000			;set up pass-in for bios_driver

	; test if rerouter in place
	call	TestRR
	jz	gs_0000
	call	AltSCSIProc
	jmp	short gs_0100
gs_0000:
	call	bios_driver		;execute pc command
gs_0100:
	mov	al,err00		;host adapter error, or
	mov	ah,stat00		;target problem?
	cmp	WORD PTR [bp].dhst,ax
	je	SnsPsd			;  jump if no
SnsFld:

        mov     ah,BERSNS	;request sense failed
	jmp	GetSense_done


SnsPsd:
	mov	al,byte ptr [bp].paralist+12 ;extended sense code byte in al
	cmp	byte ptr [bp].paralist+7,5   ;if sense byte 7 (additional sense length)
	jae	pcsn2		    	;  not > = 5, byte 12 is not valid.
	mov	al,0
pcsn2:	
					;special check for Quantum Q280 -
	mov	cl,byte ptr [bp].paralist+2
	and	cl,0fh			;sense key in cl
	cmp	cl,02			;sense key = 02 (Drive Not Ready)?
	jne	SnsPs0			;  if yes, replace Additional Error
	mov	al,04			;  Code with 04 (Drive Not Ready)
SnsPs0:					;(Q280's code is different.)

        cmp     al,CSNMAX               ;Check if its in range
        jbe     SnsValOk
        mov     ah,BERUND               ;If not, set Undefined Error
	jmp	GetSense_done

SnsValOk:

        mov     bx,OFFSET ECDTBL        ;Translate Sense Value
        xlat    CS:[BX]                 ;to BIOS code with Table
        mov     ah,al
	push	ax

	cmp	byte ptr Disk_or_Flopt,Disk_req
	je	getsense_end
	
	cmp	ah,BER_MEDIA_CHANGE	;was this a media change error?
	jne	try_correctable_err	
	call	SetMediaChanged		;set media changed flag in sparrow
					;stack for this target
	jmp	short getsense_end

try_correctable_err:

	cmp	ah,BERCOR		;report no error if correctable
	jne	getsense_end		;error reported on floptical
	mov	ah,BERNUL

getsense_end:

	call	ChkForLockedState	;if initialization cmd required,
	pop	ax			;send it!
	jmp	GetSense_done

GetSense        endp

SUBTTL Check for Installed disk Routine
PAGE

; *** ChkDsk - Check if specified Device is an Installed disk, &
;		is ready to transfer data.
;
;       Entry:  DL - Target Id
;
;       Exit:   CY reset if Device is Present, Hard Drive, & ready to
;		transfer data
;		CY = 1 if error.  di = offset of error message displayed.
;			      (Required only for B636 motherboard option.)
;

        Public  ChkDsk
ChkDsk  proc    near

	push	bp
	sub	sp,SIZE scb_struct
	mov	bp,sp
	push	es		   	;just wait 2 seconds

	mov	bx,SlctTmo		;set up timeout for selection of target
	call	SetTmo

	call	Check_Bus		;check that scsi bus not clamped
	jz	ChkSel
	jmp	ChkDs6			;  jump if bus not free
					;(This check prevents a hang if a drive
					;is not powered up.  Do not expect
					;other devices to be active on bus at
					;this time.)
ChkSel:
        push    cx
        push    bx                      ;Push Timeout value
        push    dx                      ;Push Target ID

	mov	Target,dl		;Set up for an Inquiry command
	mov	CmdByte,cmd12
	mov	Xfer_Offset,0
	mov	bx,inqram		;inquiry data -> 2000:0
	mov	es,bx
	mov	ax,36			;get 36 bytes of inquiry data
	call	set000
	call	Do_diskIO		;Execute the command
	
	pop	dx
	pop	bx
	pop	cx
	jnc	chk_device_type
	jmp	ChkDs0			;  jump if error
chk_device_type:
	xor	bx,bx
	cmp	byte ptr es:[bx],0	;Inquiry data byte 0
	je	ChkLoo1		       	;Device Type = 0?
	jmp	ChkDs2			;    jump if no
ChkLoo1:
					;target is connected


	mov	Target,dl		;Send a start unit command for those
	mov	CmdByte,cmd1b		;drives which need it
	mov	Xfer_Offset,0
	mov	ax,0			;no data transfer
	call	set000
	mov	byte ptr ss:[bp].ddcb+4,1 ;start bit on
	push	dx			;save target ID
	call	Do_diskIO		;Execute the command
					;ignore result if failed
	pop	dx			;restore target ID
					;wait for target to come ready
					;Set up timer:
					;Wait long for targ 0.  Wait short for targ > 0.

	mov	Target,dl		;Send a start unit command for those
	mov	CmdByte,cmd1b		;drives which need it again
	mov	Xfer_Offset,0
	mov	ax,0			;no data transfer
	call	set000
	mov	byte ptr ss:[bp].ddcb+4,1 ;start bit on
	push	dx			;save target ID
	call	Do_diskIO		;Execute the command
					;ignore result if failed
	pop	dx			;restore target ID
					;wait for target to come ready
					;Set up timer:
					;Wait long for targ 0.  Wait short for targ > 0.

	cmp	dl,0
	mov	bx,LONGTMO
	je	ChkLoo0
	mov	bx,SHORTTMO
ChkLoo0:
	call	SetTmo			;Convert timeout variable bx to bx cx.

ChkLoop:
        push    cx
        push    bx                      ;Push Timeout value
        push    dx                      ;Push Target ID

	mov	Target,dl		;Set up for a Test Unit Ready command
	mov	CmdByte,cmd00		;test for ready & clear Unit Attn.
	mov	Xfer_Offset,0
	mov	ax,0			;no data transfer
	call	set000
	call	Do_diskIO		;Execute the command

        pop     dx
        pop     bx                      ;Restore regs
        pop     cx
	jc	ChkRdy			;jump if target is not ready

					;target is ready
	push	dx			;do Get disk Type command

	
	mov	Target,dl		;Set up for a Read Capacity command
	mov	CmdByte,cmd25	
	mov	bx,inqram		;read capacity data -> 2000:0
	mov	es,bx
	mov	Xfer_Offset,0
	mov	ax,8			;transfer 8 bytes
	call	set010
	mov	WORD PTR [bp].ddcb+7,0	
	call	Do_diskIO		;Execute the command

	pop	dx
	jc	j0
	xor	bx,bx
	cmp	byte ptr es:[bx]+6,02h	;disk formatted for 512 bytes/block?
	jne	j2
	jmp	ChkOK			;  jump if yes
j2:	jmp	ChkDs5			;  no:  error
j0:
					;Read Capacity scsi command failed
	mov	di,OFFSET vidmsg0	;
	call	DspMsg			;display error message on screen
	jmp	ChkErr
	

ChkDs0:					;error during initial Inquiry -
	cmp	ah,BERHNG		;selection timeout?
	je	ChkDs1			;  jump if yes

ChkDs4:
	mov	di,OFFSET vidmsg2	;target connected, but has fault
	call	DspMsg			;display error message on screen
	jmp	ChkErr
	
ChkDs1:					;selection timeout
	cmp	dl,0			;target = 0?
	jne	ChkDs6			;  jump if no:  Don't select again.
	call	CheckTmo		;loop timeout?
	jc	ChkDs6
	jmp	ChkSel			;  retry if no
ChkDs6:	mov	di,OFFSET vidmsg1	;  yes:  error
	jmp	SHORT ChkErr		;don't report error on Target 0 timeout


ChkRdy:					;check condition on Test Unit Ready
	cmp	ah,BER_FLOP_NOTRDY	;error = drive not ready?
	jne	ChkDs4			;  jump if other error:  drive fault

	call	CheckTmo		;timeout?
	jnc	ChkDs7			;  continue waiting for ready if no
	mov	di,OFFSET vidmsg4	;  yes.  display message.
	call	DspMsg			;display error message on screen
	jmp	ChkErr
	
ChkDs7:					;delay before issuing another scsi cmd
        push    cx
        push    bx                      ;Push Timeout value
        push    dx                      ;Push Target ID
	mov	bx,CmdTmo		;inter-command delay
	call	SetTmo
ChkDs8:	call	CheckTmo
	jnc	ChkDs8
	pop	dx
	pop	bx
	pop	cx
	jmp	ChkLoop			;send another Test Unit Ready command

ChkDs5: mov	di,OFFSET vidmsg5	;disk format not 512 bytes/block
	call	DspMsg			;display error message on screen
	jmp	ChkErr
	
ChkDs2:					;target connected, but not disk drive
	mov	di,OFFSET vidmsg3

ChkDs3:
	cmp	dl,0
	jne	ChkErr			;if target = 0,
	call	DspMsg			;display error message on screen
	
ChkErr:					;error return
	pop	es
	add	sp,SIZE scb_struct
	pop	bp
	stc				;pass out:  cf = 1
	ret


ChkOK:					;disk passed!
	push	dx
	call	Set_Xlat_Params		;see which translation to mode to use
	pop	dx

DspMsg2:				;display Message Class #2

	call	disp_inq_data		;display SCSI device info.
ChkOK0:
	pop	es
	add	sp,SIZE scb_struct
	pop	bp
	clc				;pass out:  cf = 0
	ret

ChkDsk  endp

;
;  clear_sparrow_stack
;
;  This routine clears bytes in the sparrow stack which the floptical
;  portion of the driver will subsequently use
;

	PUBLIC clear_sparrow_stack
clear_sparrow_stack	proc near

	mov	al,flpt0inf1
	mov	dx,dmacntrl1
	out	dx,al
	xor	al,al
	mov	dl,LOW sparstack
	mov	cx,6
clr_stack:
	out	dx,al	     		;clear 6 bytes starting at offset 0Ah
	loop	clr_stack		;in sparrow stack
	ret

clear_sparrow_stack	endp



;  display a string of ASCII characters from RAM.
;
;	pass in:  es:di = start address of string
;		  cx = number of characters

DspRam	proc	near			;(ref. DspStr)
	mov	ah,0eh
DspRa0:	mov	al,es:[di]
	push	ax
	int	10h
	pop	ax
	inc	di
	loop	DspRa0
	ret

DspRam	endp


;
;	DspMsg	-
;		di -> address of string to display
;

	PUBLIC DspMsg$
DspMsg$	proc	near			;  display error message on screen.

	push	di			;save pointer to message string

	IFDEF	Intel
	sub	di,7			;display message preamble
	call	DspErr
	mov	di,OFFSET targ_n
	call	DspStr
	ELSE		
	mov	di,OFFSET targ_n
	call	DspErr
	ENdiF

	xor	dh,dh
	mov	di,dx
	shl	di,1			;di = 2 * target #
	add	di,OFFSET targ_0
	call	DspStr

	mov	di,OFFSET targ_x
	call	DspStr

	pop	di
	PUBLIC DspMsg_short
DspMsg_short:
	call	DspStr
	cmp	dl,0
	je	DspMs0			;jump if target = 0

	mov	bx,SHORTTMO		;for target > 0, must provide
	call	SetTmo			;  display hold.
DspMs1:
	call	CheckTmo
	jnc	DspMs1

DspMs0:	

	ret

DspMsg$	endp


;
;	DspTarg
;	Displays Target # as preamble to message
;

	PUBLIC DspTarg
DspTarg	proc	near

	push	dx
	push	ax
	call	Get_Jumpers		;jumpered for Message Class #3?
	and	al,msgdsply0
	jz	dont_display
	cmp	al,msgdsply0
	jne	do_display
dont_display:	
	pop	ax			;  return if no
	pop	dx
	ret
do_display:
	pop	ax
	pop	dx

	IFDEF	Intel
	sub	di,7			;display message preamble
	call	DspErr
	mov	di,OFFSET targ_n
	call	DspStr
	ELSE		
	mov	di,OFFSET targ_n
	call	DspErr
	ENdiF

	xor	dh,dh
	mov	di,dx
	shl	di,1			;di = 2 * target #
	add	di,OFFSET targ_0
	call	DspStr

	mov	di,OFFSET targ_x
	call	DspStr

	ret

DspTarg	endp



;
;	disp_inq_data - display inquiry data for attached target
;
;	   dl -> target #
;	   2000:0 -> inquiry data
;

	PUBLIC disp_inq_data
disp_inq_data	proc	near


	push	dx			;Inquiry bytes -> host ram

	mov	Target,dl		;Set up for an Inquiry command
	mov	CmdByte,cmd12
	mov	Xfer_Offset,0
	mov	bx,inqram		;inquiry data -> 2000:0
	mov	es,bx
	mov	ax,32			;get 36 bytes of inquiry data
	call	set000
	call	Do_diskIO		;Execute the command
	jc	Dsp2M0
	xor	bx,bx
	cmp	word ptr es:[bx]+30,'F*'
	jne	after_star_check
	mov	word ptr es:[bx]+30,'  '
after_star_check:
	pop	dx			;dl = target #
	mov	di,OFFSET targ_n	;display target number
	call	DspErr
	xor	dh,dh
	mov	di,dx
	shl	di,1			;di = 2 * target #
	add	di,OFFSET targ_0
	call	DspStr
	mov	di,OFFSET targ_x
	call	DspStr

	mov	ax,inqram		;display Inquiry bytes
	mov	es,ax
	mov	bx,0
;	mov	al,es:[bx+3]		;Response Data Format > 0?
;	and	al,0fh
;	jz	Dsp2M1			;  jump if no:  Inquiry bytes unknown
	cmp	BYTE PTR es:[bx+4],35-4	;is Inquiry data list complete?
;	jb	Dsp2M1			;  jump if no:  error
	jnb	enough_data
	ret
enough_data:
	mov	di,8			;Vendor Identification -> screen
	mov	cx,8
	call	DspRam
	mov	di,OFFSET vidmsg8	;insert space
	call	DspStr
	mov	di,16			;Product Identification -> screen
	mov	cx,16
	call	DspRam
;	mov	di,OFFSET vidmsg8	;insert space
;	call	DspStr
;	mov	di,36			;Product Revision Level -> screen
;	mov	cx,4
;	call	DspRam
;	mov	di,OFFSET vidmsg9	;double linefeed
;	call	DspStr
Dsp2M2:
	mov	bx,SHORTTMO		;hold displayed line
	shr	bx,2			;adjust timeout
	call	SetTmo
Dsp2M3:	call	CheckTmo
	jnc	Dsp2M3
	ret

Dsp2M0:	pop	dx			;error during Inquiry command
	mov	di,OFFSET vidmsg6
	call	DspMsg
	ret

;Dsp2M1:	mov	di,OFFSET vidmsg7 ;can't display Inquiry bytes
;	call	DspStr
;	jmp	Dsp2M2


disp_inq_data	endp





;  set000 subroutine -
;
;  Create pass-in block for Sparrow BIOS Driver from the parameters passed
;  in to this subroutine.  The pass-in block to Driver may be altered by the
;  Driver subroutine.
;
;  CDB = 6 bytes, with logical address = 0
;  For commands returning parameter lists.
;
;  pass in:  40:42 - 40:48 = various parameters
;	     al = allocation length  [byte]
;	     bp = top of scb_struct on stack
;	     es = segment of data xfer
;	       	
	PUBLIC set000	
set000	proc	near

   	push	ax
	call	clear_scb			;clear scb structure
	mov	[bp].scb_cmd,Init_SCSI_Cmd	;Initiate SCSI command
	mov	al,Target			;target/lun
	shl	al,5
	mov	[bp].dlun,al
	mov	ax,es		
	mov	[bp].dseg,ax			;data destination segment
	mov	ax,Xfer_Offset			;data destination offset
	mov	[bp].doffset,ax
	mov	[bp].dcmdlen,6 			;cdb length:  6 bytes
	pop	ax				;retrieve allocation length
	mov	[bp].ddlen,ax			;byte count
	mov	BYTE PTR [bp].ddlen+2,0
						;scsi command
	mov	BYTE PTR [bp].ddcb+4,al		;byte 4 = allocation length
	mov	al,CmdByte
	mov	[bp].ddcb,al			;byte 0:  command opcode
	xor	ax,ax				;bytes 1,2 = 0
	mov	WORD PTR [bp].ddcb+1,ax
	mov	[bp].ddcb+3,al			;byte 3 = 0
	mov	[bp].ddcb+5,al			;byte 5 = 0
	ret

set000	endp

;  set010 subroutine -
;
;  Create pass-in block for Sparrow BIOS Driver from the parameters passed
;  in to this subroutine.  The pass-in block to Driver may be altered by the
;  Driver subroutine.
;
;  CDB = 10 bytes, with logical address = 0
;  For commands returning parameter lists.
;
;  pass in:  40:42 - 40:48 = various parameters
;	     ax = allocation length  [bytes]
;	     bp = top of scb_struct on stack
;	     es = segment of data xfer
;
	PUBLIC set010
set010 	proc	near


   	push	ax
	call	clear_scb			;clear scb structure
	mov	[bp].scb_cmd,Init_SCSI_Cmd	;Initiate SCSI command
	mov	al,Target			;target/lun
	shl	al,5
	mov	[bp].dlun,al
	mov	ax,es		
	mov	[bp].dseg,ax			;data destination segment
	mov	ax,Xfer_Offset
	mov	[bp].doffset,ax			;data destination offset
	mov	[bp].dcmdlen,10 	    	;cdb length:  10 bytes
	pop	ax				;retrieve allocation length
	mov	[bp].ddlen,ax			;byte count
	mov	BYTE PTR [bp].ddlen+2,0
						;scsi command
	xchg	ah,al
	mov	WORD PTR [bp].ddcb+7,ax		;bytes 7,8 = allocation length
	mov	al,CmdByte
	mov	[bp].ddcb,al			;byte 0:  command opcode
	xor	ax,ax				;bytes 1-6 = 0
	mov	WORD PTR [bp].ddcb+1,ax
	mov	WORD PTR [bp].ddcb+3,ax
	mov	WORD PTR [bp].ddcb+5,ax
	mov	[bp].ddcb+9,al			;byte 9 = 0
	ret


set010	endp


;  set_scb_10 subroutine -
;
;  Create pass-in block for Sparrow BIOS Driver from the parameters passed
;  in to this subroutine.  The pass-in block to Driver may be altered by the
;  Driver subroutine.
;
;  CDB = 10 bytes, with non-zero logical address
;
;  pass in:  40:42 - 40:48 = various parameters
;	     dh-cx = SCSI LBA
;	     al	   = num sectors
;	     es = segment of data xfer
;	     bp = top of scb_struct on stack
	
	PUBLIC set_scb_10
set_scb_10 	proc	near


   	push	ax
	push	cx
	push	dx
	call	clear_scb			;clear scb structure
	mov	[bp].scb_cmd,Init_SCSI_Cmd	;Initiate SCSI command
	mov	al,Target			;target/lun
	shl	al,5
	mov	[bp].dlun,al
	mov	ax,es		
	mov	[bp].dseg,ax			;data destination segment
	mov	ax,Xfer_Offset
	mov	[bp].doffset,ax			;data destination offset
	mov	[bp].dcmdlen,10 	    	;cdb length:  10 bytes
	pop	dx
	pop	cx				;retrieve SCSI LBA
	pop	ax				;retrieve allocation length
	xor	ah,ah
	push	ax
	push	cx
	push	dx
	xor	dx,dx
	mov	cx,512				;multiply by 512
	mul	cx				;byte count in dl-ax
	cmp	byte ptr CmdByte,cmd2f		;for verify command or
						;special read w/no xfer, leave
	je	fill_cdb			;transfer length at 0
	cmp	byte ptr CmdByte,cmdff
	jne	insert_byte_count
	mov	byte ptr CmdByte,cmd28		;read with no transfer
	jmp	fill_cdb
insert_byte_count:
	mov	[bp].ddlen,ax			;byte count
	mov	byte ptr [bp].ddlen+2,dl	 ;high byte of byte count

fill_cdb:					;scsi command

	pop	dx
	pop	cx
	pop	ax
	xchg	ah,al
	mov	WORD PTR [bp].ddcb+7,ax		;bytes 7,8 = allocation length
	mov	al,CmdByte
	mov	[bp].ddcb,al			;byte 0:  command opcode
	xchg	dh,dl
	mov	word ptr [bp].ddcb+2,dx		;fill in LBA (bytes 2-5)
	xchg	ch,cl
	mov	word ptr [bp].ddcb+4,cx	
	xor	ax,ax				
	mov	byte PTR [bp].ddcb+1,al
	mov	[bp].ddcb+9,al			;byte 9 = 0
	ret


set_scb_10	endp


;  clear_scb subroutine -
;
;  Clears pass-in block for Sparrow BIOS Driver.
;
;  pass in:
;	     bp = top of scb_struct on stack

   	PUBLIC	clear_scb
clear_scb 	proc	near


	push	es
	push	di
	mov	di,bp
	mov	ax,ss
	mov	es,ax
	xor	ax,ax
	mov	cx,SIZE scb_struct
	cld
	rep	stosb
	pop	di
	pop	es
	ret

clear_scb	endp




SUBTTL HardWare Interrupt Handler
PAGE

; *** CtlInt - Hardware Interrupt Handler
;
;       Entry:  Interrupts disabled
;

        public  CtlInt
CtlInt  proc    near

        push    ax
        mov     al,20h                  ;Acknowledge the interrupt
        out     20h,al                  ;to master controller
        jmp     $+2                     ;IO Delay
        out     0A0H,al                 ;then the slave
        sti                             ;Re-enable interrupts

        mov     ah,91H                  ;End Int 15H Busy Wait
        mov     al,00H
        Int     15H
        pop     ax

        iret

CtlInt  endp

SUBTTL Timer Routines
PAGE

SUBTTL EnableTimer - Enable Timer Tick
PAGE

; *** EnableTimer - Unmask Timer Tick Interrupt (IRQ0)
;
;       Entry: none
;
;       Exit:  none
;
;

        public  EnableTimer
EnableTimer     proc    near

        cli                             ;disable interrupts

        in      al,INTMMS               ;Read Interrupt Mask Register
        and     al,not IMSTMR           ;Unmask IRQ0
        jmp     $+2                     ;Let Chip play with itself
        out     INTMMS,al               ;Enable timer tick interrupt

        sti                             ;Enable interrupts

        ret

EnableTimer     endp

; *** PupDelay - Delay for Drives to recover from Reset
;
;       Entry: cx ->delay in 1/18 of a second
;
;       Exit:  none
;
;

        public  PupDelay
PupDelay     proc    near

	push	cx
;	mov	di,OFFSET prog45	;display progress message
;	call	DspMsg3
	pop	cx

        push    bx
        push    cx
        mov     bx,cx
        call    SetTmo

ChkAgn:

        call    CheckTmo
        jnc     ChkAgn
        pop     cx
        pop     bx
	ret
		
PupDelay     endp


; *** SetTmo - Setup a Timeout
;
;       Entry:  BX - Number of Timer ticks for Timeout
;
;       Exit:   BXCX - Time Out Time
;
;	Pass thru:  dx
;


        public SetTmo
SetTmo         proc    near

        push    ax

        mov     ax,bx
        mov     cx,CurTim                ;Calculate timeout time from time
        mov     bx,CurTim+2
        add     cx,ax
        adc     bx,0

        cmp     bx,18H                   ;Check if near or past Midnight roll
        jb      NotLate
        xor     bx,bx                    ;If so, set timeout from MN
        mov     cx,ax
        cmp     ax,TIMROL                ;Use greater of TIMROL and bx
        ja      TmoOk                    ;to prevent early timeout
        mov     cx,TIMROL+1

TmoOk:
NotLate:

        pop     ax
        ret

SetTmo       endp


; *** CheckTmo - Check for a Timeout
;
;       Entry:  BXCX - Time Out Time
;
;       This routine checks to see if a Timeout has occurred.
;

	PUBLIC CheckTmo
CheckTmo        proc    near

        cli
        cmp     bx,CurTim+2             ;Compare BX to High Time word
        ja      NoTmoFnd                ;If above, no timeout
        jb      PossTmoFnd              ;If below, possible timeout found

        cmp     cx,CurTim               ;If equal, check low word
        jae     NoTmoFnd                ;If CX has been passed, timeout!
        jmp     TmoFnd

PossTmoFnd:

        cmp     bx,0                    ;Make sure no recent midnight roll
        je      NoTmoFnd                ;If so, no timeout yet

TmoFnd:

        stc
        sti
        ret                             ;timeout occurred

NoTmoFnd:

        clc                             ;no timeout occurred
        sti
        ret

CheckTmo        endp


SUBTTL  Host Adapter Initialization Routine
PAGE

; *** HaInit - Initialize the host adapter Hardware
;
;       Entry:  DS points to System BIOS Data Area
;               ES points to Interrupt Vector Table
;
;       Exit:   C reset if initialization was successful
;

        public  HaInit
HaInit  proc    near

	call	bios_init		;reset scsi bus
					;run diagnostic of driver hardware
					;initialize driver hardware
	jc	HaIni0			;  jump if diagnostic error

	;Get hardware configuration from Sparrow BIOS driver.

	call	HA_Return_Config_cmd
					;DMA channel not used for BIOS
	mov	al,ah
	call	IntIch			;initialize the interrupt channel

	clc				;pass out:  cf = 0
	ret

HaIni0:					;self-test diagnostic error
	mov	di,OFFSET CDFMSG	;display message
	call	DspErr$

HaInErr:				;error return
	stc				;pass out:  cf = 1
	ret

HaInit  endp

SUBTTL  Host Adapter Initialization Cleanup
PAGE

; *** HaInitCleanup - Finish Init Housekeeping
;
;

        public  HaInitCleanup
HaInitCleanup  proc    near

	;calculate internal stack checksum
	call	stkchksum
	ret

HaInitCleanup  endp

SUBTTL Hardware Initialization Routines
PAGE

; *** IntIch - Initialize the interrupt channel
;
;       Entry: AL - The controller interrupt channel bit mask
;

IntIch  proc     near

        cli                            ;disable interrupts
        push    ax                     ;save interrupt channel
        shl     al,1                   ;Convert to interrupt mask
        mov     ah,al
        in      al,0A1H                ;Get mask from slave controller
        not     ah
        and     al,ah
        out     0A1H,al                ;Unmask the adapter interrupt
        pop     ax

        mov     si,-4                  ;Convert Interrupt channel bit mask to
                                       ;interupt vector index from base
IchLoop:

        add     si,4                   ;Bump si by one interrupt vector
        shr     al,1
        jnc     IchLoop                ;If no carry, try next bit


        ;If carry was set, we have found our channel
        ;and si contains offset of Int Vector from base fro Slave controller

        mov     es:(OFFSET Int71H)[si],OFFSET CtlInt
        mov     es:(OFFSET Int71H)[si][2],CS

        sti
        ret

IntIch  endp


;****************************************************************************
;
;  AIC-6360 Stack access routines
;
;****************************************************************************

;----------------------------------------------------------------------------
;
;	set_media_changed - sets media changed flag in sparrow stack
;
	
	PUBLIC SetMediaChanged
SetMediaChanged	proc near

	call	GetFloptByte		;get floptical byte from sparrow stack
	or	al,MC_Active		;set media changed bit
	call	SetFloptByte
	ret

SetMediaChanged	endp


;----------------------------------------------------------------------------
;
;	CheckDownFormat - check down format bit in sparrow stack
;
;	exit:	CY set if bit is set
;
	PUBLIC CheckDownFormat
CheckDownFormat	proc	near

	push	ax
	call	GetFloptByte
	and	al,Down_format		;down format bit on?
	pop	ax
	jz	not_on
	stc
	ret
not_on:
	clc
	ret	

CheckDownFormat	endp


;----------------------------------------------------------------------------
;
;	GetMediaType - Get media type from sparrow stack
;	
;	exit:	al contains media type

	PUBLIC GetMediaType
GetMediaType	proc near

	call	GetFloptByte
	and	al,Curr_Media
	shr	al,CurrMediaOffset
	ret

GetMediaType	endp


;----------------------------------------------------------------------------
;
;	clear_lastcmd16 - Clears lastcmd16 bit in sparrow stack
;			This bit is used to indicate that the last
;			BIOS function request was AH=16 (disk change
;			line status)

	PUBLIC clear_lastcmd16
clear_lastcmd16	proc	near

	push	ax
	call	GetFloptByte
	and	al,not LastCmd16	;mask off bit
	call	SetFloptByte
	pop	ax

	ret

clear_lastcmd16	endp


;----------------------------------------------------------------------------
;
;	Chk_MediaChange - Check for media change on last request
;
;       Entry: DL - SCSI ID
;
;       Exit:  CY clear if no change
;	       CY set if media changed
;

	PUBLIC Chk_MediaChange
Chk_MediaChange	proc near

	push	ax
	call	GetFloptByte
	and	al,MC_Active
	pop	ax
	jz	no_media_change
	stc
	ret
no_media_change:
	clc
	ret
	
Chk_MediaChange	endp

;----------------------------------------------------------------------------
;
;	GetFloptByte - read Floptical byte from sparrow stack
;
;	exit: floptical byte in al
;
	PUBLIC GetFloptByte
GetFloptByte	proc near

	push	dx			;must save this reg - many
	mov	al,flpt0inf1		;routines don't expect it to
	add	al,Floptical_DrvNum	;change!
	mov	dx,dmacntrl1
	out	dx,al
	mov	dl,LOW sparstack
	in	al,dx
	pop	dx
	ret	

GetFloptByte	endp	


;----------------------------------------------------------------------------
;
;	SetFloptByte - update Floptical byte from sparrow stack
;
;	entry: floptical byte in al
;
	PUBLIC SetFloptByte
SetFloptByte	proc near

	push	dx
	push	ax
	mov	al,flpt0inf1
	add	al,Floptical_DrvNum
	mov	dx,dmacntrl1
	out	dx,al
	mov	dl,LOW sparstack
	pop	ax
	out	dx,al
	pop	dx
	ret	

SetFloptByte	endp

;----------------------------------------------------------------------------
;
;	TestRR - tests if rerouter is installed
;
;	entry:	none
;	exit:	
;		Zero flag
;			Clear	rerouter installed
;			Set	rerouter not installed
;
	PUBLIC TestRR
TestRR	proc near
	mov	al,xcfg1 OR enstk32
	call	getstkbyte
	test	al, REROUTER_ON
	ret
TestRR	endp

;----------------------------------------------------------------------------
;
;	setstkbyte - sets stack element
;
;	Entry:			al	index of stack byte to store
;				ah	value to store
;	Registers Modified:	dx
;
	public setstkbyte
setstkbyte:
	mov	dx,dmacntrl1
	out	dx,al
	mov	dl,LOW sparstack
	mov	al,ah
	out	dx,al
	ret

;----------------------------------------------------------------------------
;
;	getstkbyte - gets stack element specified by al
;
;	Entry:			al	index of byte to retrieve from stack
;       Exit:			al 	contains byte from stack
;
;	Registers Modified:	dx
;
	public getstkbyte
getstkbyte:
	mov	dx,dmacntrl1
	out	dx,al
	mov	dl,LOW sparstack
	in	al,dx
	ret

;----------------------------------------------------------------------------
;
;	getxcfg1byte - get xcfg1 byte
;
;       Exit:			al 	contains byte in xcfg1
;
;	Registers Modified:	dx
;
	public	getxcfg1byte
getxcfg1byte:
	mov	al,xcfg1 OR enstk32
	call	getstkbyte
	ret

;----------------------------------------------------------------------------
;
;	setxcfg1byte - set xcfg1 byte
;
;       Entry:			al 	contains byte to write to xcfg1
;
;	Registers Modified:	ah,dx
;
	public	setxcfg1byte
setxcfg1byte:
	mov	ah,al
	mov	al,xcfg1 OR enstk32
	mov	dx,dmacntrl1
	out	dx,al
	mov	dx,sparstack
	mov	al,ah
	out	dx,al
	ret

;----------------------------------------------------------------------------
;
;	getxcfg2byte - get xcfg2 byte
;
;       Exit:			al 	contains byte in xcfg2
;
;	Registers Modified:	dx
;
	public	getxcfg2byte
getxcfg2byte:
	mov	al,xcfg2 OR enstk32
	call	getstkbyte
	ret

;----------------------------------------------------------------------------
;
;	setxcfg2byte - set xcfg2 byte
;
;       Entry:			al 	contains byte to write to xcfg2
;
;	Registers Modified:	ah,dx
;
	public	setxcfg2byte
setxcfg2byte:
	mov	ah,al
	mov	al,xcfg2 OR enstk32
	mov	dx,dmacntrl1
	out	dx,al
	mov	dx,sparstack
	mov	al,ah
	out	dx,al
	ret

;----------------------------------------------------------------------------
;
;	AllowRerouter - checks if BIOS should reroute all SCSI processing
;			to the ASPI
;
;       Entry:
;	Exit:
;		Carry Flag	
;			Clear		Allow installation of rerouter
;			Set		Do not allow installation of rerouter
;
;	Registers Modified:	al,dx
;
	public	AllowRerouter
AllowRerouter:
	;check for presence of SCSI-type floppies
	mov	dx,dmacntrl1
	mov	al,flpt0inf1
	out	dx,al
	mov	dl,LOW sparstack
	in	al,dx
	mov	ah,al
	in	al,dx
	test	ax,0606h
	jnz	AllowRR

	push	ds
	mov	ax,seg SysBioData
	mov	ds,ax
	test	DS:[INT_4B_Flag],INT4BH_SCSI_SUPP
	pop	ds
	jnz	AllowRR

	stc
	ret

AllowRR:
	clc
	ret

;----------------------------------------------------------------------------
;
;	GetXlatMode - Gets Secs per Trk/Heads translation mode bit
;			 from sparrow stack
;
;	entry:	DL = 0 or 1 (Target ID)
;	
;	exit:   carry clear if new xlat mode (255/63)
;		carry set if old xlat mode (64/32)
;

	PUBLIC GetXlatMode
GetXlatMode	proc near

	mov	cl,dl				; xcfg2 bits 1 and 2
	inc	cl
	call	getxcfg2byte
	shr	al,cl
	and	al,1
	sub	al,1
	ret	

GetXlatMode	endp	


;----------------------------------------------------------------------------
;
;	Set_Xlat_Params - Configure translation mode for 64/32 or 255/63
;
;	entry:   ES:BX point to read capacity data
;		 DL = Target ID (0 or 1)
;
;	exit:	 xlat mode bit in sparrow stack on if the drive capacity is
;		 greater than 1 gigabyte and 6360 compatibility mode is
;		 enabled.
;


	PUBLIC Set_Xlat_Params
Set_Xlat_Params	proc	near
	mov	ah,dl

	mov	al,portb$
	call	getstkbyte                      ;get PortB information in AL			

	test	al, XLATE_1GB                   ;greater than 1GB translation?
	jz	SXPRet                          ;=> no

	cmp	word ptr es:[bx], 2000h		; above 1 gigabyte ?
	jb	SXPRet				; done if not
	ja	SXG_Giiig
	test	word ptr es:[bx+2],0FFFFh	; test bits 15-0
	jz	SXPRet

SXG_Giiig:
	call	getxcfg2byte			; mark as > Giiiiig drive
	mov	cl,ah
	mov	ah,TGT0NEWGEOM
	shl	ah,cl
	or	al,ah
	call	setxcfg2byte
SXPRet:
	ret

Set_Xlat_Params	endp

;----------------------------------------------------------------------------
;
;	AltSCSIProc - alternate SCSI processor
;
;	entry:   SS:BP points to scb block
;	exit:	 scb pointed to by SS:BP modified

	public	AltSCSIProc
AltSCSIProc proc near
	push	bx
	push	cx

	push	ax
	push	dx
 	mov	dx,dmacntrl1
	mov	al,bios_rr_off or enstk32
	out	dx,al
	mov	dl,LOW sparstack
	in	al,dx
	mov	bl,al
	in	al,dx
	mov	bh,al			;standard handler offset in bx
	in	al,dx
	mov	cl,al
	in	al,dx
	mov	ch,al			;standard handler segment in cx
	pop	dx
	pop	ax


	; setup return from alternate SCSI processor

	pushf
	push	cs
	mov	dx,offset cs:ASPbackhere
	push	dx

	;set up to call ASP

	push	cx			;segment of ASP
	push	bx			;offset of ASP
	retf				;call ASP
ASPbackhere:
	pop	cx
	pop	bx
	ret

AltSCSIProc endp

;----------------------------------------------------------------------------
;
;	stkchksum - calculates internal stack checksum for integrity check
;
;	Registers Modified:	ax,bx,cx,dx
;	
;
stkchksum	proc near

	;add  0-2,	3
	;skip 3-B,	9
	;add  C-F,	4
	;skip 10-11	2
	;add  12-1E	13
	;skip 1F	1

	xor	bl,bl

	mov	al,enstk32		;point to stack beginning
	mov	dx,dmacntrl1
	out	dx,al
	mov	dl,LOW sparstack

	;0-2
	mov	cx,2-0+1
stkcs1:
	in	al,dx
	add	bl,al
	loop	stkcs1

	mov	al,enstk32 OR 0Ch	;point to C
	mov	dx,dmacntrl1
	out	dx,al
	mov	dl,LOW sparstack

	;C-F
	mov	cx,0Fh-0Ch+1
stkcs2:
	in	al,dx
	add	bl,al
	loop	stkcs2

	mov	al,enstk32 OR 012h	;point to 12h
	mov	dx,dmacntrl1
	out	dx,al
	mov	dl,LOW sparstack

	;12-1E
	mov	cx,01Eh-012h+1
stkcs3:
	in	al,dx
	add	bl,al
	loop	stkcs3

	not	bl
	mov	al,bl
	out	dx,al

	ret
stkchksum	endp

;****************************************************************************
;
; End of stack access routines.
;
;****************************************************************************

CODE ENDS

end
