
;*******************************************************
;
;	SCSI Driver 'Status' filter.
;
;	Written by Matt Gulick.		Started August 12,1988
;
;	Copyright Apple Computer, Inc. 1988-90
;
;*******************************************************

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

;*******************************************************
;
;	Revision History:
;
;*******************************************************

;	Aug 12,		1988	File started.

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

				IMPORT		call_type
				IMPORT		main_drvr
				IMPORT		f_partition
				IMPORT		test_unit_rdy
				IMPORT		rqst_sense
				IMPORT		mode_sense
				IMPORT		read_capacity
				IMPORT		t_dvc_blocks
				IMPORT		set_512_mode
				IMPORT		open_flag
				IMPORT		set_our_dp
				IMPORT		disk_switch
				IMPORT		set_disk_sw
				IMPORT		rebld_dibs
				IMPORT		trash_it
				IMPORT		uses_dc
				IMPORT		dib_data_struct
				IMPORT		lst_rslt_ec		;Status
				IMPORT		lst_rslt_id		;Status
				IMPORT		lst_rslt_stat	;Status
				IMPORT		lst_rslt_skey	;Status
				IMPORT		lst_rslt_info	;Status
				IMPORT		lst_rslt_rqlen	;Status
				IMPORT		lst_rslt_scode	;Status
				IMPORT		sense_data
				IMPORT		auto_sense_data
				IMPORT		internal_buff
				IMPORT		display_cnt
				IMPORT		current_fmt
				IMPORT		opt1_blk_cnt
				IMPORT		opt1_blk_siz
				IMPORT		opt1_med_siz
				IMPORT		opt2_blk_cnt
				IMPORT		opt2_blk_siz
				IMPORT		opt2_med_siz
				IMPORT		opt3_blk_cnt
				IMPORT		opt3_blk_siz
				IMPORT		opt3_med_siz
				IMPORT		format_options
				IMPORT		check_532_rw

				ENTRY		dvc_status
				ENTRY		g_config_parms
				ENTRY		wait_status
				ENTRY		fmt_options
				ENTRY		read_p_map
				ENTRY		g_last_rslt

				PRINT		OFF

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

				EJECT
			
;*******************************************************
;
;	Main Entry point to the 'Status' filter.  This
;	"Filter" is called when a Status Command comes in.
;	See the headers of the seperate sections for the
;	details of the commands.
;
;	Inputs:		[dib_ptr]	=	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
;
;	Outputs:	Acc			=	DRVR_BUSY
;				Carry		=	1
;						unless we have no more dibs then
;				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	status
status			PROC
												;
												; Zero out the Data Chaining Flag
												;
				stz		|uses_dc
												;
												; Clear transfer count.
												;
				lda		#null
				ldy		#dib.trx_len
				sta		[dib_ptr],y
				ldy		#dib.trx_len+2
				sta		[dib_ptr],y
												;
												; Entry to the Status Call Filter.
												; This filter acts as a mini driver.
												; It examines the Status Code sent
												; and calls the appropriate routines.
												; If the Command is $8000 or greater,
												; then it will be routed to the device
												; specific section.
												;
				lda		<stat_code
				bmi		@do_dvc_spec			;Device Specific Code.
												;
												; Check the range of the command.
												;
				cmp		#max_s_cmd+1
				bge		@error
												;
												; Convert to an index
												;
				asl		a
				tax
				jsr		(@ncmd_tbl,x)
				rts
												;
												; Bad Command Error.
												;
@error			lda		#drvr_bad_req
				sec
				rts
												;
												; Normal Command Table.
												;
@ncmd_tbl		dc.w	dvc_status
				dc.w	g_config_parms
				dc.w	wait_status
				dc.w	fmt_options
				dc.w	read_p_map
				dc.w	g_last_rslt
												;
												; Device Specific Code handling
												; starts here.
												;
												; Check version of data structure
												;
@do_dvc_spec	lda		[buff_ptr]
				beq		@version_0
				cmp		#$0001
				bne		@error
												;
												; Version 1.  Preserve the data pointer
												; currently used in the DIB and replace
												; it with a pointer to the USER supplied
												; Data Chaining instructions.
												;
				clc
				ldy		#dib.trx_ptr
				lda		[dib_ptr],y
				sta		|dib_data_struct

				lda		<buff_ptr
				adc		#ds.DCcode				;Offset to first D.C. Data
				sta		[dib_ptr],y

				ldy		#dib.trx_ptr+2
				lda		[dib_ptr],y
				sta		|dib_data_struct+2

				lda		<buff_ptr+2
				adc		#^ds.DCcode
				sta		[dib_ptr],y
												;
												; Set flag to indicate that D.C. Commands
												; were used and that we need to restore
												; the pointer in the DIB to the normal
												; data descriptor.
												;
				dec		|uses_dc
												;
												; Do the rest normally and check the above
												; flag later.
												;
@version_0		clc
				lda		<buff_ptr
				adc		#$0002
				sta		<scsi_mdrvr

				lda		<buff_ptr+2
				adc		#null
				sta		<scsi_mdrvr+2
				
				ldy		#$000C
				lda		[scsi_mdrvr],y
				sta		<buff_ptr
				ldy		#$000C+2
				lda		[scsi_mdrvr],y
				sta		<buff_ptr+2
												;
												; Call Main Driver
												;
				lda		#scsit_stat
				sta		|call_type
				jsr		|main_drvr
				bcs		@exit
												;
												; Save transfer count.
												;
				ldy		#dib.trx_len
				lda		[dib_ptr],y
				sta		@call_trns_cnt
				ldy		#dib.trx_len+2
				lda		[dib_ptr],y
				sta		@call_trns_cnt+2
												;
												; Check to see if we need to handle
												; a Disk Switched Event.  If not,
												; then exit.
												;
				lda		|disk_switch
				bpl		@exit
												;
												; Don't Trash the Volumes.
												;
				jsr		rebld_dibs				;Issues a DISK_SW for each rebuilt DIB.
												;
												; Restore Direct Page Values.
												;
@exit			pha
				php
												;
												; Check the D.C. Flag
												;
				lda		|uses_dc
				beq		@set_our_zp

				ldy		#dib.trx_ptr
				lda		|dib_data_struct
				sta		[dib_ptr],y

				ldy		#dib.trx_ptr+2
				lda		|dib_data_struct+2
				sta		[dib_ptr],y
				
				stz		|uses_dc				;Reset Flag

@set_our_zp		jsr		set_our_dp
												;
												; Set transfer count.
												;
				lda		@call_trns_cnt
				sta		<trans_cnt
				lda		@call_trns_cnt+2
				sta		<trans_cnt+2
												;
												; Exit.
												;
				plp
				pla
				rts
												;
												; Data Area.
												;
@call_trns_cnt	dc.l	null					;Transfer count befor we steped on it.

				ENDP

				EJECT
			
;*******************************************************
;
;	
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	dvc_status
dvc_status		PROC
												;
												; Get Device Status Call
												;
				lda		<rqst_cnt+2
				bne		@do_max
				lda		<rqst_cnt
				cmp		#$0007
				blt		@no_odds
@do_max			lda		#$0006
@no_odds		lsr		a						;0 --> Bit 15, Bit 0 --> Carry
				bcs		@bad_rqst_cnt			;No odd byte transfers
				asl		a						;Carry <-- Bit 15, Bit 0 <-- 0
				sta		<trans_cnt
				stz		<trans_cnt+2
				bne		@at_least_2
				jmp		@clc
												;
												; Bad Request Count.
												;
@bad_rqst_cnt	lda		#drvr_bad_cnt
				rts
												;
												; Init Status to $0000
												;
@at_least_2		stz		@dvc_stat
												;
												; Is the Device Linked?
												;
				ldy		#dib.dvcchar

				lda		[dib_ptr],y
				and		#linked_dvc
				beq		@no_link				;No.

				lda		#bit_14					;Yes. Set the bit
				tsb		@dvc_stat
												;
												; Is the device busy with a pending call?
												;
@no_link		ldy		#dib.dvcflag

				lda		[dib_ptr],y
				and		#int_busy
				beq		@not_busy				;No.

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

				IF		character_dvc = true	THEN

												;
												; If the device is a character device,
												; and it's busy, then also set the Buffer
												; Not Empty Flag.
												;
				lda		#bit_13\
						++bit_5					;Yes. Set the bits
				tsb		@dvc_stat

				ENDIF

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

				IF		block_dvc = true	THEN

				lda		#bit_13					;Yes. Set the bit
				tsb		@dvc_stat

				ENDIF

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

												;
												; Is the Device Online?
												;
@not_busy		ldy		#dib.dvcflag

				lda		[dib_ptr],y
				and		#dvc_online
				beq		@not_online2			;No. Skip Switch flag.

				lda		[dib_ptr],y				;Also Check Hard Offline
				and		#dvc_hardofl			;Is it hard offline.
				bne		@not_online				;Yes. Do switch flag

				lda		#bit_4					;Yes. Set the bit
				tsb		@dvc_stat

				lda		[dib_ptr],y				;Clear Switch Flag.
				and		#dvc_switch--\
						$ffff
				sta		[dib_ptr],y

				bra		@online					;Skip the following mess.

@not_online
												;
												; If the device's Online Flag is set
												; and it's Hard Offline Flag is also
												; set, then we will treat this as a
												; disk switch.
												;
				lda		#bit_0
				tsb		@dvc_stat

				lda		[dib_ptr],y
				and		#dvc_online++\
						dvc_switch--\
						$ffff
				sta		[dib_ptr],y

@not_online2

@online

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

				IF		block_dvc = true	THEN

												;
												; If the device is a block device, is
												; the Device Write Protected?
												;
				ldy		#dib.dvcchar

				lda		[dib_ptr],y
				and		#write_allow
				bne		@writeable				;No.

				lda		#bit_2					;Yes. Set the bit
				tsb		@dvc_stat

				ENDIF

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

@writeable

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

				IF		block_dvc = true	THEN

												;
												; If the device is a block device, has
												; the Device been switched?
												;
				jsr		rqst_sense
				bcc		@no_error
				jmp		@switch					;Yes!
												;
												; The following lines of code commented
												; by a '****' were added because of an
												; SCSI Device that returned no error when
												; there was no media on line.  This was
												; not the correct thing for the device to
												; do.  Shame on him.  What we needed to do
												; to correct this was to get the offline
												; flag, then check to see if the device
												; returned an error.  If an error is
												; returned, then we process it normally.
												; If no error was returned and the device
												; is still ofline, then we treat it as a
												; device not ready error.  The offline will
												; be cleared when the device returns an 06
												; in the sense key.
												;
@no_error		ldy		#dib.dvcflag
				lda		[dib_ptr],y				;****
				and		#dvc_hardofl			;****
				tax								;****
												;****
				lda		|sense_data+\
						rqst_sens.sense_key
				bne		@chk_sense_key			;****
				txa								;****
				beq		@too_far
				jmp		@opened					;****
@too_far		jmp		@its_back				;****

@chk_sense_key	and		#$00ff
				cmp		#$0002
				bne		@chk_for_6
				jmp		@chk_switch


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

				IF		scsi_dtype<>apple_cd	THEN

@chk_for_6		cmp		#$0006
				beq		@inserted

				ELSE

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

@chk_for_6		cmp		#$0006
				bne		@not_a_6

				lda		sense_data+\			;Was it a RESET?
						rqst_sens.addnl_sens_code
				and		#$00ff
				cmp		#$00b0					;Checking for $B0 (NO MEDIA)
				beq		@fixit
				and		#$00fe					;Checking for $28 (INSERTION)
				cmp		#$0028					;or $29 (RESET)
				beq		@inserted				;Yes it was.
@fixit			jmp		@chk_switch
												;
												; If the device is a CD_ROM device
												; then check to see if the SENSE KEY
												; = 5.  If so, then treat it as no
												; error.
												;
@not_a_6		cmp		#$0005
				bne		@its_bs
				jmp		@its_back
@its_bs
				ENDIF

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

				stz		<trans_cnt
				ora		#$ff00
				sec
				rts
												;
												; Rebuild the DIBs.
												;
@inserted
												;
												; Is this device linked?  If it is,
												; then we need to mark them all as
												; being online.
												;
												; Start at the headptr if non-zero.
												;
				ldy		#dib.headptr
				lda		[dib_ptr],y
				tax
				ldy		#dib.headptr+2
				lda		[dib_ptr],y
				bne		@set_pointer0			;Should not be bank 0
												;
												; Current pointer is the first.
												;
				lda		<dib_ptr+2
				ldx		<dib_ptr
												;
												; Set temp Zero Page Pointer
												;
@set_pointer0	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++\
						dvc_hard_sw
				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_pointer0

@turdy			jsr		test_unit_rdy				;Is it ready yet?
				bcc		@they_r_built				;Yes.
				lda		auto_sense_data+\			;Is there media in the drive?
						rqst_sens.addnl_sens_code
				and		#$00ff
				cmp		#$00b0						;Checking for $B0 (NO MEDIA)
				bne		@turdy						;No.

@they_r_built	jsr		set_512_mode
													;
													; Issue the READ CAPACITY Command.
													;
				jsr		read_capacity
				bcs		@no_capacity				;Was there an error?
													;
													; 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.
													;
				lda		|block.count\
						+internal_buff\
						+2
				xba
				adc		#$0001						;Carry is Clear as a result
				sta		|t_dvc_blocks				;of the 'READ CAPACITY' Call
				lda		|block.count\
						+internal_buff
				xba
				adc		#null
				sta		|t_dvc_blocks+2

@no_capacity	jsr		rebld_dibs					;Rebuild DIBs and Issue a DISK_SW
				php									;for each
													;
													; Restore the origonal Direct Page
													; values.
													;
				jsr		set_our_dp
				plp
				bcc		@set_switch
				jsr		test_unit_rdy
				bcc		@set_switch
													;
													; For some reason, we cannot talk to the
													; device.  It must be offline.
													;
@chk_switch		ldy		#dib.dvcflag
				lda		[dib_ptr],y
				tax

				and		#dvc_hardofl
				bne		@opened

				txa
				and		#dvc_online--\
						$ffff
				ora		#dvc_hardofl
				sta		[dib_ptr],y

				lda		#bit_4					;Clear the Online bit
				trb		@dvc_stat

				lda		#bit_0					;Set the Switch bit
				tsb		@dvc_stat

				bra		@opened
												;
												; Set Online Bit.  If dvc_hard_sw is
												; set, then clear it and return the
												; disk switch bit.
												;
@its_back		lda		[dib_ptr],y
				pha
				and		#dvc_hard_sw
				tax
				pla
				and		#dvc_hard_sw--\
						$ffff
				sta		[dib_ptr],y
				txa
				bne		@set_switch
				bra		@opened					;Back in business

@switch											;
												; Is this device linked?  If it is,
												; then we need to mark them all as
												; being offline.
												;
												; Start at the headptr if non-zero.
												;
				ldy		#dib.headptr
				lda		[dib_ptr],y
				tax
				ldy		#dib.headptr+2
				lda		[dib_ptr],y
				bne		@set_pointer2			;Should not be bank 0
												;
												; Current pointer is the first.
												;
				lda		<dib_ptr+2
				ldx		<dib_ptr
												;
												; Set temp Zero Page Pointer
												;
@set_pointer2	stx		<scsi_zp0
				sta		<scsi_zp0+2
												;
												; Set the Flags.
												;
				ldy		#dib.dvcflag
				lda		[scsi_zp0],y
				ora		#dvc_switch++\
						dvc_online++\
						dvc_hard_sw
				and		#dvc_online--\
						$ffff
				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_pointer2
				
												;
												; Set the Switched Bit in Status
												;
@set_switch		lda		#bit_0					;Yes. Set the bit
				tsb		@dvc_stat
												;
												; No forward pointer.  Continue on.
												;
				ENDIF

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

@opened

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

				IF		character_dvc = true	THEN
												;
												; If the device is a character device,
												; has the Device been opened?
												;
				lda		|open_flag
				beq		@not_open				;No.

				lda		#bit_0					;Yes. Set the bit
				tsb		@dvc_stat

@not_open

				ENDIF

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

												;
												; If it is switched, then call disk switch.
												;
				lda		@dvc_stat
				and		#bit_0+bit_4			;If Online Bit is set then
				cmp		#bit_0					;don't call disk switch
				bne		@no_call
				jsr		set_disk_sw
												;
												; Return the combined flags.
												; 
@no_call		lda		<rqst_cnt+2
				bne		@its_big
				lda		<rqst_cnt
				beq		@clc
				cmp		#$0007
				blt		@no_odds_1
@its_big		lda		#$0006
@no_odds_1		and		#$fffe					;No odd byte transfers
				sta		<trans_cnt
				stz		<trans_cnt+2

				tax
				lda		@dvc_stat
				sta		[buff_ptr]
												;
												; Return the Block Count.
												;
				dex
				dex
				beq		@clc

				ldy		#dib.blkcnt
				lda		[dib_ptr],y
				ldy		#$0002
				sta		[buff_ptr],y

				dex
				dex
				beq		@clc

				ldy		#dib.blkcnt+2
				lda		[dib_ptr],y
				ldy		#$0004
				sta		[buff_ptr],y
												;
												; Exit real nice like.
												;
@clc			clc
				rts
												;
												; Data for this call.
												;
@dvc_stat		dc.w	null

				ENDP

				EJECT
			
;*******************************************************
;
;	'g_config_parms'
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	g_config_parms
g_config_parms	PROC
												;
												; Get Config Parms Call
												;
				lda		#null
				sta		<trans_cnt
				sta		<trans_cnt+2
				clc
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	Get the current Wait/No Wait status of this device.
;	If it is a block device then no error will occur and
;	a $0000 (Wait Mode) will be returned.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				[buff_ptr]	=	Current Mode
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	wait_status
wait_status		PROC
												;
												; Check the parameters list.
												; Should contain a WORD
												;
				lda		<rqst_cnt
				cmp		#$0002
				bne		@bad_parm
				sta		<trans_cnt

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

				IF 		block_dvc = true	THEN
												;
												; If a Block Device then return Wait Mode.
												;
				lda		#null

				ENDIF

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

				IF 		character_dvc = true	THEN
												;
												; Check the Current Mode
												;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#wait_mode
				bne		@wait
												;
												; Return No Wait Mode.
												;
				lda		#bit_15
				bra		@exit
												;
												; Return Wait Mode.
												;
@wait			lda		#null

				ENDIF

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

												;
												; Save it and exit.
												;
@exit			sta		[buff_ptr]
				lda		#null					;Clear the Acc.
				clc
				rts
												;
												; Bad Parm Error
												;
@bad_parm		lda		#drvr_bad_parm
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	Get Format Options Call
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	fmt_options
fmt_options		PROC

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

				IF			block_dvc = true\
				AND			character_dvc = false		THEN

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

				IF			scsi_dtype = apple_cd		THEN
												;
												; If the device is a CD_ROM, then there
												; are no format options.
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#bad_dev_number
				sec
				rts

				ENDIF							;scsi_dtype = apple_cd

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

				IF			scsi_dtype = direct_acc	THEN
												;
												; Get Format Options Call
												;
												; If we are partitioned, then no data.
												;
				ldy		#dib.dvcchar

				lda		[dib_ptr],y
				and		#linked_dvc
				beq		@no_link				;No.
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts
												;
												; Set display count to 3
												;
@no_link		lda		#$0003
				sta		|display_cnt-2
				sta		|display_cnt
												; 
												; Issue MODE SENSE Call
												;
				jsr		mode_sense
												;
												; Check to see if the device supports
												; the page discriptors.
												;
				lda		|mode.blk_disc\
						+internal_buff
				and		#$00ff
				beq		@do_from_dib
												;
												; Not all device return the block count
												; in this call.  Shame on them.  If the
												; block count is missing, then get it
												; from the DIB.  This data is 3 bytes
												; MSB >> LSB formatted.
												;
				lda		|mode.blocks\			;High Byte
						+internal_buff\
						-1
				and		#$ff00
				ora		|mode.blocks\			;.OR.ed with the Low Word
						+internal_buff\
						+1
				beq		@do_from_dib
												;
												; MODE SENSE is legal.  Use it.
												;
												; Set Block Count in format
												; option list.
												;
				lda		|mode.blocks\
						+internal_buff\
						+1
				xba
				sta		|opt1_blk_cnt
				sta		|opt2_blk_cnt

				lda		|mode.blocks\
						+internal_buff\
						-1
				xba
				sta		|opt1_blk_cnt+2
				sta		|opt2_blk_cnt+2
												;
												; Set Block Size in format
												; option list.
												;
				lda		|mode.blk_size\
						+internal_buff\
						+1
				xba
				sta		|opt1_blk_siz
				sta		|opt2_blk_siz
				bra		@set_med_size
												;
												; Set Block Count in format
												; option list from DIB.
												;
@do_from_dib	ldy		#dib.blkcnt
				lda		[dib_ptr],y
				sta		|opt1_blk_cnt
				sta		|opt2_blk_cnt

				ldy		#dib.blkcnt+2
				lda		[dib_ptr],y
				sta		|opt1_blk_cnt+2
				sta		|opt2_blk_cnt+2
												;
												; Set Block Size in format
												; option list.
												;
				ldy		#dib.blksize
				lda		[dib_ptr],y
				sta		|opt1_blk_siz
				sta		|opt2_blk_siz
												;
												; Set Media Size in format
												; option list.
												;
@set_med_size	lda		|opt1_blk_cnt+3
				and		#$00ff
				sta		@t_blocks
				lda		|opt1_blk_cnt+1
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				adc		#$0000
				sta		|opt1_med_siz
				sta		|opt2_med_siz
												;
												; Get Read Capacity
												;
				jsr		read_capacity
												;
												; Set Block Size in format
												; option list.
												;
				lda		|block.size\
						+internal_buff\
						+2
				xba
				sta		|opt3_blk_siz
				cmp		#$0200
				bne		@over
												;
												; Set display count to 2
												;
				lda		#$0002
				sta		|display_cnt-2
				sta		|display_cnt
												;
												; Set Block Count in format
												; option list.
												;
@over			lda		|block.count\
						+internal_buff\
						+2
				xba
				sta		|opt3_blk_cnt

				lda		|block.count\
						+internal_buff
				xba
				sta		|opt3_blk_cnt+2
												;
												; Set Media Size in format
												; option list.
												;
				lda		|block.count\
						+internal_buff\
						-1
				xba
				sta		@t_blocks
				lda		|block.count\
						+internal_buff\
						+1
				xba
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				adc		#$0000
				sta		|opt3_med_siz
												;
												; Restore Direct Page
												;
				jsr		set_our_dp
												;
												; Check Count range
												;
				lda		<rqst_cnt+2
				bne		@do_max
				lda		<rqst_cnt
				cmp		#opt3_med_siz-\
						format_options+\
						2
				blt		@this_many
@do_max			lda		#opt3_med_siz-\
						format_options+\
						2
												;
												; Send this many bytes of the list.
												;
@this_many		sta		<trans_cnt
				stz		<trans_cnt+2
				tay
				dey
				bmi		@exit
				short
@loop			lda		format_options,y
				sta		[buff_ptr],y
				dey
				bpl		@loop
				longmx
												;
												; Exit.
												;
@exit			lda		#null
				clc
				rts
												;
												; Data Area
												;
@t_blocks		dc.w	null

				ENDIF							;scsi_dtype = direct_acc

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

				ENDIF							;block_dvc = true

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

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
												;
												; If the device is a Character Device,
												; then there are no Format Options to
												; return.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF							;character_dvc = true

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

				ENDP

				EJECT
			
;*******************************************************
;
;	Most be the first device in a link!!!!
;
;	Entry point to the 'Read PMap' call.  This call
;	takes the information given by the caller on direct
;	page and builds the equivilent to a Read Status Call
;	to read request count bytes starting at physical
;	block number 1.  This is done by setting the high
;	bit of the partition call flag 'f_partition'.
;
;			Block Size				=	dib.blksize
;
;	We now Build the SCSI Main Driver Command and send
;	it.
;
;	The following will be validated by the Main Driver
;	when it builds the command. 
;
;			Request Count			=	Block Size * i
;			Block Number			=	Blk Num (No Offset)
;				This is for partitions.
;
;	After calling the Main driver and if no errors were
;	encountered, then the Transfer count will be
;	updated.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT	read_p_map
read_p_map		PROC

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

				IF			block_dvc = true\
				AND			character_dvc = false		THEN

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

				IF			scsi_dtype = apple_cd		THEN
												;
												; Exit No Error.
												;
				lda		#drvr_bad_code
				sec
				rts

				ENDIF							;scsi_dtype = apple_cd

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

				IF			scsi_dtype = direct_acc	THEN

				stz		@do_532
												;
												; Set the Block size on Direct Page.
												; It is not placed there for this call,
												; and we should not rely on it being
												; left behind by the last call.
												;
				lda		#block_size
				sta		<blk_size
												;
												; Check if first DIB in link if any.
												; If it is zero, then we are already
												; there.  If not then error out.
												;
				ldy		#dib.headptr+2
				lda		[dib_ptr],y
				ldy		#dib.headptr
				ora		[dib_ptr],y
				bne		@bad_dev_num
												;
												; Let's check the request count.  If
												; this is $00000000, then exit clean
												; with no data transfered.
												;
				lda		<rqst_cnt
				ora		<rqst_cnt+2
				bne		@cnt_non_zero
				jmp		@out_of_here
												;
												; Verify Block Size.
												;
@cnt_non_zero	ldy		#dib.blksize
				lda		[dib_ptr],y				;Block Size
				cmp		<blk_size
				bne		@chk_532

				ldy		#dib.blksize+2
				lda		[dib_ptr],y
				beq		@blk_size_ok

@bad_parm		lda		#drvr_bad_parm
				sec
				rts
												;
												; Check for 532 byte block size
												;
@chk_532		tax

				lda		<blk_size
				cmp		#block_size
				bne		@bad_parm

				cpx		#$0214
				bne		@bad_parm
				dec		@do_532

@blk_size_ok
												;
												; Build the (Read Data)
												; Status Command $8008
												;
				lda		#$0001					; Sent to me Low >> High.
				xba								; I Send it out High >> Low.
				sta		|c_block_num
												;
												; Set Main Driver Pointer to
												; our data for the command.
												;
				lda		#cmd_$8008
				sta		<scsi_mdrvr
				lda		#^cmd_$8008
				sta		<scsi_mdrvr+2
												;
												; Set the Partition call flag
												;
				dec		|f_partition
												;
												; Call Main Driver
												;
				lda		#scsit_stat
				sta		|call_type
												;
												; Issue the call.
												;
				jsr		check_532_rw
				bcs		@rts
												;
												; Update Transfer Count.
												;
@out_of_here	lda		<rqst_cnt
				sta		<trans_cnt
				lda		<rqst_cnt+2
				sta		<trans_cnt+2
												;
												; Exit No Error.
												;
				lda		#$0000
				clc
				rts


@bad_dev_num	lda		#bad_dev_number
				sec
@rts			rts
												;
												; Variables and storage for short call.
												;
@do_532			dc.w	null					;532 byte block flag
												;
												; Command Data for this call.
												;
cmd_$8008		dc.b	$08
				dc.b	$00
c_block_num		dc.w	$0000
c_block_cnt		dc.b	$00
				dcb.b	7,$00

				ENDIF							;scsi_dtype = direct_acc

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

				ENDIF							;block_dvc = true

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

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
												;
												; If the device is a Character Device,
												; then there are no Partitions to
												; read.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF							;character_dvc = true

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

				ENDP

				EJECT
			
;*******************************************************
;
;	'g_last_rslt'
;
;	This call returns the Error code result of the last
;	call.  This used to inquire about the result of a
;	call that may have been executed asyncronously.  If
;	the device is busy with a pending call when this call
;	is issued, a DEVICE_BUSY Error will be returned.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;			Users Buffer	=
;			|----------------------------------------|
;	WORD	+-			GS/OS Error Code			-+
;			|----------------------------------------|
;	WORD	+-			Device ID Number			-+
;			|----------------------------------------|
;	WORD	+-			SCSI Status Code			-+
;			|----------------------------------------|
;	WORD	+-		SCSI REQUEST SENSE sense key	-+
;			|----------------------------------------|
;	LONG	+-	MSB									-+
;			+-			Information Bytes			-+
;			+-									LSB	-+
;			|----------------------------------------|
;	WORD	+-		REQUEST SENSE data length		-+
;			|----------------------------------------|
;	WORD	+-				Reserved				-+
;			|----------------------------------------|
;
;	Errors:		Device Busy.  Only if the target device
;				currently has a call pending.
;
;*******************************************************

				EXPORT	g_last_rslt
g_last_rslt		PROC
												;
												; Is this the same device?
												;
				lda		<dev_num
				cmp		|lst_rslt_id
				bne		@bad_dvc_num
												;
												; Check if the device has a call
												; pending.
												;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#int_busy
				bne		@device_busy
												;
												; Update Transfer Count.
												;
				lda		<rqst_cnt+2
				bne		@rslt_all
				lda		<rqst_cnt
				and		#$fffe					;No odd byte transfers
				beq		@exit
				cmp		#lst_rslt_scode+2-\
						lst_rslt_ec
				blt		@set_rslt

@rslt_all		lda		#lst_rslt_scode+2-\
						lst_rslt_ec
@set_rslt		sta		<trans_cnt
				tay
				lda		#null
				sta		<trans_cnt+2
												;
												; Move the Data.
												;
				dey
				dey

@loop			lda		|lst_rslt_ec,y
				sta		[buff_ptr],y
				dey
				dey
				bpl		@loop
												;
												; Exit No Error.
												;
@exit			lda		#$0000
				clc
				rts
												;
												; Errors.
												;
@device_busy	lda		#drvr_busy
				sec
@rts			rts

@bad_dvc_num	lda		#bad_dev_number
				sec
				rts

				ENDP

				EJECT

				END
