
;*******************************************************
;
;	SCSI Driver 'Startup' filter.
;
;	Written by Matt Gulick.		Started July 1,1988
;
;	Copyright Apple Computer, Inc. 1988,89
;
;*******************************************************

;*******************************************************
;
;	This file contains the 'Startup' filter as defined
;	in the ERS.
;
;*******************************************************

;*******************************************************
;
;	Revision History:
;
;*******************************************************
;
;	July 1,		1988	File started.
;	July 21,	1988	reworked logic and added
;						a few new subroutines.
;	April 10,	1989	Started to add code for
;						character devices for the
;						Scanner.

				STRING		PASCAL
				BLANKS		OFF
				PAGESIZE	70
				PRINT		NOGEN
				PRINT		NOMDIR
				MACHINE		M65816

				IMPORT		wake_me_up
				IMPORT		get_mm_id
				IMPORT		get_dvc_ram
				IMPORT		set_512_mode
				IMPORT		select_page_num
				IMPORT		test_unit_rdy
				IMPORT		start_unit
				IMPORT		mode_sense
				IMPORT		read_capacity
				IMPORT		default_dib
				IMPORT		rebld_dibs
				IMPORT		dpi_overide
				IMPORT		set_our_dp
				IMPORT		direct_page
				IMPORT		gsos_dpage
				IMPORT		main_drvr
				IMPORT		internal
				IMPORT		internal_buff
				IMPORT		get_scsimgr
				IMPORT		call_type
				IMPORT		fre_dvc_ram
				IMPORT		dvc_count
				IMPORT		rpm_blk_num
				IMPORT		rebuild
				IMPORT		part_num
				IMPORT		do_part_dib
				IMPORT		first_time
				IMPORT		part_cnt
				IMPORT		chk_ram
				IMPORT		dibicise_new_ram
				IMPORT		dibicise_new_dib
				IMPORT		main_caller
				IMPORT		active_starts
				IMPORT		tot_dib_cnt
				IMPORT		t_dvc_blocks
				IMPORT		auto_sense_data

				ENTRY		do_inq_parms
				ENTRY		do_mode_parms
				ENTRY		do_read_cap
				ENTRY		do_partition
				ENTRY		get_nxt_dvc

				PRINT		OFF

				INCLUDE		'scsihd.equates'
				INCLUDE		'M16.MEMORY'
				INCLUDE		'M16.UTIL'
				PRINT		ON

				EJECT
			
;*******************************************************
;
;	Main Entry point to the 'Startup' filter.  This
;	'Filter' is called after the driver is loaded.  The
;	code that follows sets up the drivers environment,
;	then calls 'get_dvc_ram'.  On return from the
;	'get_dvc_ram' call, the following structure are in
;	place if no error ocured.
;
;		dvc_list	=	Long Pointer to device List
;		next_dib	=	Long Pointer to First DIB
;		first_dib	=	Long Pointer to the beginning
;						of the RAM Allocated for the
;						new DIBs.
;
;			This contains enough RAM for one DIB for
;			each device in the device list.  If more
;			space is needed due to partitioning, then
;			the startup filter will be responsible for
;			getting that space from the memory manager.
;
;	From this point, we need to build the DIB for each
;	device. 
;		
;	Inputs:		None.
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	GS/OS Direct Page
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT	startup
startup			PROC

;-------------------------------------------------------------------------------

				IF		warm_ss_suprt = true		THEN

											;
											; Check to see if this is a WARM STARTUP
											; Call.  If it is, we will need to handle
											; this a lot differently than a normal
											; startup.  First of all our DIBs are, for
											; the most part, already built.  The only
											; possible changes might be in respect to
											; removable media.  In any case we will
											; call the warm start routine in the Driver
											; Mgmt file to take care of this for us.
											;
											; Is it a COLD STARTUP?
											;
				lda		>warm_cold_flag
				and		#$0001
				bne		@do_warm			;It's Warm
@no_warm_start	jmp		@chk_dflt			;It's Cold
											;
											; Check to see if this is for the
											; 'default_dib'.  If it is, then we need
											; to exit with an error.  The error is so
											; that our default DIB is purged from the
											; startup list.
											;
@do_warm		lda		<dib_ptr
				cmp		#default_dib
				bne		@not_dflt

				lda		<dib_ptr+2
				cmp		#^default_dib
				bne		@not_dflt

				lda		#drvr_io			;Error Out.
				sec
				rts
											;
											; Yeah, so it's a WARM STARTUP.  But
											; does this device know what that
											; means?  We'll see!
											;
@not_dflt		ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#restartable
				beq		@no_warm_start		;Not restartable.
											;
											; Yeah, so it knows what that means!
											; But first let's see if it is a new
											; DIB.
											;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				tax
											;
											; Compare to default value.
											;
				cmp		#wait_mode++\
						cold_dib
				beq		@in_valid_dib		;Unused DIB.  Reject it.
											;
											; One last check. Is it partitioned
											; and if so, does it also have a valid
											; block offset?
											;
				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#linked_dvc
				beq		@valid_dib			;Used DIB.  Start it.

				ldy		#dib.start_blk
				lda		[dib_ptr],y
				ldy		#dib.start_blk+2
				ora		[dib_ptr],y
				bne		@valid_dib			;Used DIB.  Start it.
											;
											; Zero out the Device Number and
											; remove link.
											;
@in_valid_dib	lda		#null
				ldy		#dib.devnum
				sta		[dib_ptr],y

				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#linked_dvc--\
						$ffff
				sta		[dib_ptr],y

				lda		#drvr_no_dev		;Error Out.
				sec
				rts
											;
											;
@valid_dib		txa
				and		#cold_dib
				bne		@no_warm_start		;New DIB and Awake.  Do Cold Start
											;
											; Old DIB.  But is it asleep?
											;
				txa
				and		#relaxing
				beq		@over_wake_up		;Not asleep.
											;
											; Call the Warm Restart Routine.
											;
				jsr		wake_me_up
											;
											; The device is now awake.  If it is
											; removable we need to see if the
											; disk has been changed.
											;
@over_wake_up	ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#removable
				beq		@bra_been_had		;Not removable.
											;
											; Rebuild the DIBs for this device if
											; this is the first partition for this
											; device.
											;
				ldy		#dib.unitnum
				lda		[dib_ptr],y
				and		#max_p_mask
				bne		@bra_been_had		;Not the head.  They've been done already
											;
											; Current pointer is the first.
											;
				lda		<dib_ptr+2
				ldx		<dib_ptr
@set_pointer	stx		<scsi_zp0
				sta		<scsi_zp0+2
											;
											; Set the Flags.
											;
				ldy		#dib.dvcflag
				lda		[scsi_zp0],y
				and		#dvc_hardofl--\
						$ffff
				ora		#dvc_switch++\
						dvc_online
				sta		[scsi_zp0],y
											;
											; If there is a forward device
											; pointer than get it.
											;
				ldy		#dib.fdvcptr
				lda		[scsi_zp0],y
				tax
				ldy		#dib.fdvcptr+2
				lda		[scsi_zp0],y
				bne		@set_pointer

				jsr		set_512_mode
				lda		#$ffff				;Don't Do Post Driver Installs
				sta		|dpi_overide
				jsr		rebld_dibs			;Rebuild DIBs and Issue a DISK_SW for each
				php
				stz		|dpi_overide		;Clear the Overide
											;
											; Restore the origonal Direct Page values.
											;
				jsr		set_our_dp
				plp
				bcc		@bra_been_had
				jsr		test_unit_rdy
				bcc		@bra_been_had
											;
											; For some reason, we cannot talk to the
											; device.  It must be offline.
											;
@chk_switch		ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#dvc_online--\
						$ffff
				sta		[dib_ptr],y

;@bra_been_had	jmp		@links_done
@bra_been_had	bra		@ive_been_had

 				ENDIF

;-------------------------------------------------------------------------------

											;
											; Check to see if this is for the
											; 'default_dib'.  If it is, then we need
											; to build all the devices that we can and
											; exit with an error.  The error is so that
											; our default DIB is purged from the startup
											; list.  The device dispatcher will then
											; call us for the DIB pointed to in the
											; 'default_dib's link pointer.  This and any
											; further 'STARTUP' calls will exit with no
											; error, except that no action will be taken
											; other than to increment the startup call
											; count to be used as a balance for the
											; shutdown calls that will eventually be
											; issued.
											;
@chk_dflt		lda		<dib_ptr
				cmp		#default_dib
				bne		@ive_been_had

				lda		<dib_ptr+2
				cmp		#^default_dib

;-------------------------------------------------------------------------------

				IF			part_suprt = false	Then

				beq		@im_a_virgin

@ive_been_had									;
												; Mark the device as started and
												; as online.
												;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#cold_dib--\
						$ffff

;===============================================================================

				IF			character_dvc = true	Then

				ora		#dvc_online

				ENDIF

;===============================================================================

				sta		[dib_ptr],y

				ELSE

;-------------------------------------------------------------------------------

				bne		@ive_been_had

				jmp		@im_a_virgin

@ive_been_had
												;
												; Clear the Cold Start Flag.
												;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#cold_dib--\
						$ffff
				sta		[dib_ptr],y

												;
												; Check the Partition Bits.  If they
												; are all clear, then we will set the
												; head device link to this device.
												;
				ldy		#dib.unitnum
				lda		[dib_ptr],y
				cmp		#$0001
				beq		@jmp_links_done

				and		#max_p_mask
				bne		@not_head
												;
												; Too far to branch to.
												;
@jmp_links_done	jmp		@links_done
												;
												; This is not the first or boot device,
												; nor is it the first or only logical
												; device on this physical device.  That
												; means that it is probably partitioned.
												; This means we need to set the head and
												; forward links.  The following code will
												; do this for us.
												;
												; Get the Device Number for setting as
												; a forward link.  Also save the unit
												; number (less the partition bits) to
												; match the other DIBs from this device.
												;
@not_head		ldy		#dib.devnum
				lda		[dib_ptr],y
				sta		@current_dev

				ldy		#dib.unitnum
				lda		[dib_ptr],y
				and		#max_p_mask\
						--$ffff
				sta		@our_unit

				ldy		#dib.slotnum
				lda		[dib_ptr],y
				sta		@our_slot
												;
												; Start pointer out at the default DIB.
												;
				lda		#default_dib
				sta		<scsi_zp4

				lda		#^default_dib
				sta		<scsi_zp4+2
												;
												; Main Search loop.
												;
												; Advance pointer to the next DIB.  If
												; link is = to zero, then exit loop.
												;
@links_loop		ldy		#dib.linkptr+2
				lda		[scsi_zp4]
				tax
				ora		[scsi_zp4],y
				bne		@non_zero

				jmp		@links_done

@non_zero		lda		[scsi_zp4],y

@advance		sta		<scsi_zp4+2
				stx		<scsi_zp4
											;
											; Check unit number to see if it is the same.
											;
				ldy		#dib.unitnum
				lda		[scsi_zp4],y
				and		#max_p_mask\
						--$ffff
				cmp		@our_unit			;Is it ours?
				bne		@links_loop			;No. Check the next one.
											;
											; Check Slot number to see if it is the same.
											;
				ldy		#dib.slotnum
				lda		[scsi_zp4],y
				cmp		@our_slot			;Is it ours?
				bne		@links_loop			;No. Check the next one.
											;
											; They are equal.  Is the forward link = zero?
											;
				ldy		#dib.fdvclnk
				lda		[scsi_zp4],y
;				beq		@found_end
;				cmp		@current_dev
				bne		@links_loop			;No. Check the next one.
											;
											; Yes.  This DIB has no forward device link.
											; We will volunteer the users DIB for the Job.
											; Set the head Link in the DIB called and the
											; forward link in ours.
											;
@found_end		lda		@current_dev
				sta		[scsi_zp4],y

				ldy		#dib.headlnk
				lda		[scsi_zp4],y

				beq		@stuff_head
											;
											; Set Head Pointer to scsi_zp4
											;
				pha

				ldy		#dib.headptr
				lda		[scsi_zp4],y
				sta		[dib_ptr],y
				ldy		#dib.headptr+2
				lda		[scsi_zp4],y
				sta		[dib_ptr],y

				pla
				bra		@do_head
											;
											; Set head Pointer to the same as
											; in scsi_zp4
											;
@stuff_head		ldy		#dib.headptr
				lda		<scsi_zp4
				sta		[dib_ptr],y
				ldy		#dib.headptr+2
				lda		<scsi_zp4+2
				sta		[dib_ptr],y

				ldy		#dib.devnum
				lda		[scsi_zp4],y

@do_head		ldy		#dib.headlnk
				sta		[dib_ptr],y
											;
											; Also set the Forward Device Ptr.
											;
				ldy		#dib.fdvcptr
				lda		<dib_ptr
				sta		[scsi_zp4],y
				ldy		#dib.fdvcptr+2
				lda		<dib_ptr+2
				sta		[scsi_zp4],y
											;
											; And the forward link.
											;
				ldy		#dib.devnum
				lda		[dib_ptr],y

				ldy		#dib.fdvclnk
				sta		[scsi_zp4],y
											;
											; Is it a COLD STARTUP?
											;
				lda		>warm_cold_flag
				and		#$0001
				bne		@links_done			;It's Warm.  Skip the links
											;
											; Set the linked bit in both DIBs.
											;
				ldy		#dib.dvcchar

				lda		[scsi_zp4],y
				ora		#linked_dvc
				sta		[scsi_zp4],y

				lda		[dib_ptr],y
				ora		#linked_dvc
				sta		[dib_ptr],y

				ENDIF

;-------------------------------------------------------------------------------

											;
											; Not the first one, so increment the counter
											; if we are not beyond what we have for an
											; active dib count.
											;
@links_done		lda		|active_starts
				cmp		|tot_dib_cnt
				beq		@over_inc
				inc		|active_starts
@over_inc		clc
				rts
											;
											; Local Data storage here.
											;
@current_dev	dc.w	null				;Device Number for this DIB
@our_unit		dc.w	null				;His unit number less the partition bits.
@our_slot		dc.w	null				;His slot number
											;
											; Check to see if we've been called before.
											; If not then we need to get the gs/os
											; direct page address.
											;
@im_a_virgin	lda		|direct_page
				bne		@we_have_it
											;
											; Where is GS/OS Direct Page?
											;
				tdc
				sta		|gsos_dpage
											;
											; We also need to get the SCSI Managers
											; ID for the S_DISPATCHER.
											;
				jsr		get_scsimgr
				bcs		@rts
											;
											; Get ID from the memory manager.  All that
											; this does is request a new ID.
											;
@we_have_it		jsr		get_mm_id
											;
											; Call the get_dvc_ram subroutine.
											; This will allocate the space
											; that we need for the device list
											; returned by the SCSI Manager.
											; It then calculates a DIB count
											; (Max 256) and allocates RAM for
											; those structures.  This can be
											; increased later if it is needed.
											; This can occur if some of the
											; devices contain more than one
											; partition.
											;
				jsr		get_dvc_ram
				bcc		@do_dflt_dib		;Check for errors.

				jsr		fre_dvc_ram			;Dump Get Devices Ram

				lda		#drvr_no_dev		;Exit
				sec
@rts			rts
											;
											; Now we need to build the DIBs for
											; these devices.  The first one will
											; not be built in the default_dib
											; area.  The default_dib will be 
											; copied first to the new memory that
											; has been allocated.  It is here
											; that the first DIB will be built.
											; After this the last DIB built will
											; be copied into the space for the
											; next DIB to be built and then
											; updated accordingly.  We do not use
											; the default_dib because this will
											; serve to keep this driver active
											; even if no devices are present at
											; boot time.  Just in case a drive
											; does come online later.
											;
@do_dflt_dib	lda		<dvc_list			;Advance pointer to the first entry.
				adc		#$0004				;Pass Direct page pointer and
				sta		<dvc_list			;device count. Carry was CLEAR!!!!
				lda		<dvc_list+2
				adc		#$0000
				sta		<dvc_list+2

				lda		#default_dib
				sta		<last_dib
				lda		#^default_dib
				sta		<last_dib+2

				stz		|main_caller		;tell the link setter that he was called
				clc							;Do Links Also
				jsr		dibicise_new_ram	;by the main loop
				bra		@over

@over			jsr		do_mode_parms		;Do MODE SENSE supplied parms

				jsr		do_inq_parms		;Do INQUIRY supplied parms

;-------------------------------------------------------------------------------

				IF			block_dvc = true	Then

				jsr		do_read_cap			;Do READ CAPACITY supplied parms

				ENDIF

;-------------------------------------------------------------------------------

				IF			part_suprt = true	Then

				jsr		do_partition		;Do partition DIBs

				ENDIF

;-------------------------------------------------------------------------------

				jsr		get_nxt_dvc			;Go to the next physical device

				bne		@over				;But only if they exist.
											;
											; This SEC is extremely important.  At
											; this point the startup call was issued
											; to the default DIB.  We took this
											; opertunity to build all of our DIBs
											; and we have a count of how many we did
											; build.  We do not want the device manager
											; to keep the default DIB as an active
											; device and so we exit with the carry
											; set.  He will then check the link
											; pointer and if it is not zero, he will
											; call the startup routine for that dib.
											; At that time we will exit with the carry
											; clear.
											;
											; Free Get Devices Ram first.
											;
				jsr		fre_dvc_ram

				lda		#drvr_io
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_inq_parms'
;
;	This routine issues an INQUIRY call to the device and
;	then uses the data returned to fill in some of the blank
;	holes in the DIB.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	unchanged			(LONG)
;				[next_dib]	=	INQUIRY values set	(PTR)
;									Removable bit
;									Command bitmap
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	do_inq_parms
do_inq_parms	PROC
										;
										; Set internal command flag
										;
				dec		|internal
										;
										; Tell the Main Driver where
										; our command structure resides.
										;
				lda		#@start_inq
				sta		<scsi_mdrvr
				lda		#^@start_inq
				sta		<scsi_mdrvr+2
										;
										; And our buffer
										;
				lda		#internal_buff
				sta		<buff_ptr
				lda		#^internal_buff
				sta		<buff_ptr+2
										;
										; And our length 0f $40 Bytes
										;
				lda		#$0040
				sta		<rqst_cnt
				stz		<rqst_cnt+2
										;
										; Stuff the pointer to the dib
										; that we are building into the
										; Direct Page locations.  The
										; main driver will use this to
										; build the SCSI INQUIRY Command
										; that we will issue.
										;
				lda		<next_dib
				sta		<dib_ptr
				lda		<next_dib+2
				sta		<dib_ptr+2
										;
										; Set the Call Type and Issue the
										; INQUIRY Command.
										;
				lda		#scsit_stat
				sta		|call_type
				jsr		|main_drvr
				bcc		@over_0			;Was there an error?

				rts						;Yes.
										;
										; Is the device removable?
										;
@over_0			lda		|inq.removable\
						+internal_buff
				and		#bit_7
				beq		@non_remove
										;
										; Yes.  Set the bit in the
										; characteristics field.
										;
				ldy		#dib.dvcchar
				lda		[next_dib],y
				ora		#removable
				sta		[next_dib],y
				bra		@over_1
										;
										; No.  Clear the bit in the
										; characteristics field.
										;
@non_remove		ldy		#dib.dvcchar
				lda		[next_dib],y
				and		#removable--\
						$ffff
				sta		[next_dib],y
										;
										; Set a ZP pointer to where the
										; command bitmap information will
										; be placed.
										;
@over_1			clc
				lda		<next_dib
				adc		#dib.group0
				sta		<scsi_zp0
				lda		<next_dib+2
				adc		#^dib.group0
				sta		<scsi_zp0+2
										;
										; Not all devices conform to the
										; Apple Command Command Set.  We
										; need to check if the Command
										; Bitmap is available.  If not
										; then we will stuff the default
										; bitmap and then clear bits as
										; the device indicates.  This will
										; be done elsewhere in response to
										; a command not supported error.
										;
										; First check the return length.
										;

				ldy		#dib.trx_len
				lda		[dib_ptr],y
				cmp		#inq.group+5-1	;End of first group - 1
				blt		@do_default
										;
										; We got those bytes. Are they 0?
										;
				short					;5 Bytes to check.  Best done 8 bit

				sec						;The Carry will be our flag
				lda		|inq.group\
						+internal_buff
				bne		@chk_carry		;Must Start w/ Group Zero.

				clc						;The Carry will be our flag
				ldx		#$0005
@chk_bm_loop	lda		|inq.group\
						+internal_buff,x
				bne		@chk_carry
				dex
				bpl		@chk_bm_loop
				sec
@chk_carry		longmx
				bcs		@do_default
										;
										; There are some devices out there
										; that return bogus bitmaps.  They
										; look correct, but are not.  We will
										; check the first 4 bytes of the
										; Bitmap to see if they support the
										; Mandatory Commands.  If not, then
										; we will use our default bitmap.
										;
				lda		|inq.group\
						+internal_buff+1
				and		@min_cmnds
				cmp		@min_cmnds
				bne		@do_default

				lda		|inq.group\
						+internal_buff+3
				and		@min_cmnds+2
				cmp		@min_cmnds+2
				bne		@do_default
										;
										; Zero out the current data in the
										; dib.  If there are any holes in
										; the information then we are sure
										; that those holes are null.
										;
				ldy		#dib.group7\
						-dib.group0\
						+2
				lda		#null
@loop_0			sta		[scsi_zp0],y
				dey
				dey
				bpl		@loop_0
										;
										; Get the group number for the next
										; four bytes of bitmap.
										;
										;	Group x			(BYTE)
										;	Bitmap			(LONG)
										;	Group y			(BYTE)
										;	Bitmap			(LONG)
										;	Group z			(BYTE)
										;	Bitmap			(LONG)
										;	Group '$FF		(BYTE)
										;
				ldx		#null
@loop_1			lda		|inq.group\
						+internal_buff,x

				and		#$00ff			;Real Code
				cmp		#$00ff
				beq		@over_2

				cmp		#$0007+1
				bge		@do_default
										;
										; Convert group number into an
										; index into the group table in
										; the dib.
										;
				asl		a
				asl		a
				tay
				inx
										;
										; Transfer the bitmap.
										;
				lda		|inq.group\
						+internal_buff,x
				sta		[scsi_zp0],y
				inx
				inx
				iny
				iny
				lda		|inq.group\
						+internal_buff,x
				sta		[scsi_zp0],y
				inx
				inx
				bra		@loop_1
										;
										; The device did not support
										; the Command Bitmap in the
										; INQUIRY Parms.  We need to
										; put the default bitmap in
										; place.
										;
@do_default		ldy		#dib.group7\
						-dib.group0\
						+2
@dflt_loop		lda		default_dib\
						+dib.group0,y
				sta		[scsi_zp0],y
				dey
				dey
				bpl		@dflt_loop
										;
										; Clean exit when done.
										;
@over_2			clc
				rts
										;
										; Data Area.
										;
										; Inquiry Command Packet.
										;
@start_inq		dc.b	$12
				dcb.b	11,$00
										;
										; Data of Minimum Command set that
										; must be supported.
										;
@min_cmnds

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	Then
										;
										; It is a Direct-Access Device.
										;
				dc.B	$98,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = seq_acc	THEN
										;
										; It is a Sequential-Access Device.
										;
				arl						;Cause error if used.  Force definition
				dc.B	$D0,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = seq_acc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = appl_laser	THEN
										;
										; It is an Apple LaserWriter Device.
										;
				dc.B	$98,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = appl_laser

;-------------------------------------------------------------------------------

				IF		scsi_dtype = proc_dvc	THEN
										;
										; It is a Processor Device.
										;
				arl						;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = proc_dvc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = worm_dvc	THEN
										;
										; It is a Write-once Read-multiple Device.
										;
				arl						;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = worm_dvc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = read_dacc	THEN
										;
										; It is a Read-only Direct-Access Device.
										;
				dc.B	$90,$00,$23,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = read_dacc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = scanner	THEN
										;
										; It is a Scanner Device.
										;
				dc.B	$90,$00,$23,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = scanner

;-------------------------------------------------------------------------------

				IF		scsi_dtype = optic_mem	THEN
										;
										; It is a Optical Memory Device.
										;
				arl						;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = optic_mem

;-------------------------------------------------------------------------------

				IF		scsi_dtype = changer	THEN
										;
										; It is a Changer Device.
										;
				dc.B	$98,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = changer

;-------------------------------------------------------------------------------

				IF		scsi_dtype = comm_dvc	THEN
										;
										; It is a Communication Device.
										;
				arl						;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00	; Group 0 Commands

				ENDIF					;scsi_dtype = comm_dvc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = mcd_40	THEN
										;
										; It is a Direct Access Magnetic
										; Tape Device.
										;
				dc.B	$DF,$77,$FF,$7C	; Group 0 Commands

				ENDIF					;scsi_dtype = mcd_40

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_mode_parms'
;
;	This routine issues an MODE SENSE call to the device and
;	then uses the data returned to fill in some of the blank
;	holes in the DIB.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	unchanged			(LONG)
;				[next_dib]	=	MODE SENSE vals set	(PTR)
;									Write Protect bit
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	do_mode_parms
do_mode_parms	PROC
										;
										; Stuff the pointer to the dib
										; that we are building into the
										; Direct Page locations.  The
										; main driver will use this to
										; build the SCSI MODE SENSE
										; Command that we will issue.
										;
				lda		<next_dib
				sta		<dib_ptr
				lda		<next_dib+2
				sta		<dib_ptr+2
										;
										; Start the Unit
										;

;-------------------------------------------------------------------------------

				IF			scsi_dtype <> scanner	THEN

				jsr		start_unit
		
				ENDIF
		
;-------------------------------------------------------------------------------

				IF			scsi_dtype = mcd_40\
				OR			scsi_dtype = apple_cd\
				OR			scsi_dtype = changer		THEN

										;
										; Check for no-media
										;
				bcc		@cd_tape_ok
										;
										; Check for No Media Error
										;
				lda		|auto_sense_data+\
						rqst_sens.sense_key
				beq		@cd_tape_ok

				and		#$00ff
				cmp		#$0002			;Is there Media?
				bne		@cd_tape_ok		;Yes.
										;
										; No Media.  Mark the DIB Hard Ofline also.
										;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				ora		#dvc_hardofl
				sta		[dib_ptr],y


@cd_tape_ok

				ENDIF

;-------------------------------------------------------------------------------

										;
										; Check if unit Ready
										;
				jsr		test_unit_rdy
										;
										; Issue MODE SENSE Call
										;
				jsr		mode_sense
				bcs		@rts			;Was there an error?

;-------------------------------------------------------------------------------

				IF		scsi_dtype <> apple_cd\
				AND		scsi_dtype <> changer\
				AND		scsi_dtype <> scanner	THEN

										;
										; Is the device writable?  If CD-ROM
										; then don't even bother with this
										; code.
										;
				lda		|mode.w_protect\
						+internal_buff
				and		#bit_7
				beq		@over_1			;No.
										;
										; Yes.  Set the bit in the
										; characteristics field.
										;
				ldy		#dib.dvcchar
				lda		#write_allow
				ora		[next_dib],y
				sta		[next_dib],y
		
				ENDIF
		
;-------------------------------------------------------------------------------

@over_1									;Label must always be available.
		
;-------------------------------------------------------------------------------

				IF		scsi_dtype <> mcd_40\
				AND		scsi_dtype <> scanner\
				AND		scsi_dtype <> appl_laser	THEN
										;
										; Check to see if the device supports
										; the page discriptors.
										;
				lda		|mode.blk_disc\
						+internal_buff
				and		#$00ff
				beq		@clc
										;
										; Ensure that the device is in
										; 512 mode if possible and send
										; data from page 1 back to the
										; device.
										;
				lda		|mode.page_number\
						+internal_buff
				and		#$ff3f			;Clear the invalid bits.
				sta		|select_page_num
				lda		|mode.page_number\
						+internal_buff+2
				ora		#bit_6++\		;Set AWRE and ARRE bits.
						bit_7
				sta		|select_page_num+2
				lda		|mode.page_number\
						+internal_buff+4
				sta		|select_page_num+4
				lda		|mode.page_number\
						+internal_buff+6
				sta		|select_page_num+6

				jsr		set_512_mode
				bcs		@rts

@clc

				ENDIF

;-------------------------------------------------------------------------------

										;
										; Exit
										;
				clc
@rts			rts
										;
										; Data for the MODE SENSE Command
										;
@start_mode		dc.b	$1a
				dc.b	$00
				dc.b	$01
				dcb.b	9,$00

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_read_cap'
;
;	This routine issues an READ CAPACITY call to the
;	device and then uses the data returned to fill in
;	some of the blank holes in the DIB.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	unchanged			(LONG)
;				[next_dib]	=	READ CAP.. vals set	(PTR)
;									Block Count
;									Block Size
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	do_read_cap
do_read_cap		PROC
		
;-------------------------------------------------------------------------------

				IF		scsi_dtype <> scanner	THEN
										;
										; Stuff the pointer to the dib
										; that we are building into the
										; Direct Page locations.  The
										; main driver will use this to
										; build the SCSI READ CAPACITY
										; Command that we will issue.
										;
				lda		<next_dib
				sta		<dib_ptr
				lda		<next_dib+2
				sta		<dib_ptr+2
										;
										; Issue the READ CAPACITY Command.
										;
				jsr		read_capacity
				bcc		@over_0			;Was there an error?

				rts						;Yes.
										;
										; Get the Block Count (Stored
										; High >> Low.  Must be switched
										; to Low >> High).  This is the last
										; readable block number.  Add 1 to
										; it for comparison reasons.
										;
@over_0			lda		|block.count\
						+internal_buff\
						+2
				xba
				adc		#$0001
				sta		|t_dvc_blocks
				lda		|block.count\
						+internal_buff
				xba
				adc		#null
				sta		|t_dvc_blocks+2

;-------------------------------------------------------------------------------

				IF		block_dvc = true	THEN

				beq		@over_mo
										;
										; Some devices do not return a bitmap
										; of the commands that they support.
										; For these devices we use a default
										; minimum command set.  If the Block
										; Count is > $ffff, then we need to
										; update this to support the exrended
										; read and write commands.
										;
				ldy		#dib.group1
				lda		[next_dib],y
				ora		#$b000			;Bit 15 = Extended Read
										;Bit 13 = Extended Write
										;Bit 12 = Extended Seek
				sta		[next_dib],y

@over_mo

				ENDIF

;-------------------------------------------------------------------------------

										;
										; Get the devices block size (This
										; also needs to be switched from
										; High >> Low to Low >> High) and
										; place it in the dib.
										;
				lda		|block.size\
						+internal_buff\
						+2
				xba
				ldy		#dib.blksize
				sta		[next_dib],y
				sta		<blk_size		;Place on direct page.
				lda		|block.size\
						+internal_buff
				xba
				ldy		#dib.blksize+2
				sta		[next_dib],y
				sta		<blk_size+2		;Place on direct page.
										;
										; Clean exit.
										;
				clc
				rts

				ELSE

;-------------------------------------------------------------------------------

				clc
				rts

				ENDIF

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_partition'
;
;	This routine issues a READ call to the device and
;	then uses the data returned to check for any
;	partitions on the media.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	last DIB Built		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************
										;
										; Start of the code segment for this.
										;
				EXPORT	do_partition
do_partition	PROC

;-------------------------------------------------------------------------------

				IF			part_suprt = true	Then

										;
										; Initialize a few values.
										;
				lda		#$ffff			;The following values will be incrimented
				sta		|first_time		;with zero indication special action.
				sta		|part_num		;This is set to $ffff so that it will only
										;occur on the first pass through.

				stz		|part_cnt
				stz		|rpm_blk_num
				stz		|rebuild
										;
										; MAIN LOOP OF CODE SEGMENT.
										;
				jsr		do_part_dib
				rts

				ELSE

;-------------------------------------------------------------------------------

				clc
				rts

				ENDIF

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	'get_nxt_dvc'
;
;	This routine checks to see if there are any
;	remaining devices in the list handed to us by the
;	GET_DEVICES Call to the SCSI Manager.  If there are
;	devices, then we advance our pointers and exit with
;	the Z flag set.  The caller can the do a BNE to
;	continue his loop ( Z(ero) indicates that there are
;	no devices left ). 
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	last DIB Built		(LONG)
;				Carry		=	1
;					Acc		=	Error
;				Carry		=	0
;					Acc		=	ram_page_cnt
;							=	0	no more devices
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;								Z=1 if more devices
;								Z=0 if no more devices
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	get_nxt_dvc
get_nxt_dvc		PROC
									;
									; Are there any more devices?
									;
				dec		|dvc_count
				bne		@we_have_more
				clc
				rts					;Z Flag set here.
									;
									; Advance the Device Data Pointer
									; in the device list from the SCSI
									; Manager
									;
@we_have_more	clc
				lda		<dvc_list
				adc		#$0004
				sta		<dvc_list
				lda		<dvc_list+2
				adc		#null
				sta		<dvc_list+2
									;
									; Call Check Ram routine.  This will
									; check to see if there is room for an
									; additional DIB.  If not then room
									; will be made for enough DIBs to cover
									; the remaining partitions and devices.
									; From this caller, there should be no
									; partitions to account for.
									;
				stz		|main_caller
				jmp		chk_ram

				ENDP

				END

				EJECT
