;******************************************************* ; ; SCSI Driver Management Routines. ; ; Written by Matt Gulick. Started May 16,1988 ; ; Copyright Apple Computer, Inc. 1988,89 ; ;******************************************************* ;******************************************************* ; ; This file contains the subroutines needed by the ; SCSI Driver for things such as Getting RAM, Building ; data areas, calling outside routines for DIB ; management, as well as other generic routines that ; are used to make life easier for the driver. Also ; included in this file is the record definition for ; the DIB structure including all it's extensions. ; ;******************************************************* ;******************************************************* ; ; Revision History: ; ;******************************************************* ; May 16, 1988 File started. ; May 17, 1988 DIB Record defined. ; June 6, 1988 Main Driver Written. ; Jun 20, 1988 Update Input/Output Data in Comments ; Apr 14, 1989 Added Conditional Logic to remove ; block routines from character device ; assemblies. STRING PASCAL BLANKS OFF PAGESIZE 70 PRINT NOGEN PRINT NOMDIR MACHINE M65816 IMPORT stat_cont IMPORT master_uid IMPORT scsi_uid IMPORT scsi_mgrnum IMPORT rout2_s_disp IMPORT hndl_offset IMPORT buff_len IMPORT page_cnt IMPORT dpi_overide IMPORT call_type IMPORT main_drvr IMPORT internal ; IMPORT disk_switch IMPORT ram_page_cnt IMPORT internal_buff IMPORT default_dib IMPORT first_time IMPORT only_one IMPORT part_cnt IMPORT t_dvc_blocks IMPORT f_partition IMPORT part_num IMPORT vPart_cnt IMPORT rebuild IMPORT trash_it IMPORT direct_page IMPORT exit_dpage IMPORT gsos_dpage IMPORT saved_zp IMPORT valid IMPORT dvc_ram IMPORT sense_data IMPORT dvc_count IMPORT result IMPORT divend IMPORT divsor IMPORT max_blk_cnt IMPORT tot_dib_cnt IMPORT dib_data_struct IMPORT main_caller IMPORT curr_hndl IMPORT new_dib IMPORT scratch0 IMPORT scratch1 IMPORT scratch2 IMPORT scratch3 IMPORT killer_blk IMPORT auto_sense_data IMPORT temp_acc IMPORT pdi_flag IMPORT new_list IMPORT new_dib_cnt IMPORT new_dib_list IMPORT real_unit ;************************* IMPORT m_blk_size IMPORT m_blk_cnt IMPORT m_rslt ENTRY zero_mem ENTRY get_space ENTRY make_dib ENTRY find_empty ENTRY chk_ram ENTRY rebld_dibs ENTRY dibicise_new_ram ENTRY dibicise_new_dib ENTRY set_link_ptrs ENTRY major_update ENTRY minor_update ENTRY fix_unit_1 ENTRY add_dib_ptr ENTRY do_post_install ENTRY read_pm_blk ENTRY rpm_blk_num ; ENTRY wpm_blk_num ENTRY chk_map ENTRY no_partition ENTRY check_map_entry ENTRY c_strt_buffer ENTRY c_strt_rqst_cnt ENTRY c_strt_blk_num ENTRY cache_valid ENTRY put_in_cache ENTRY get_from_cache ENTRY test_unit_rdy ENTRY read_capacity ENTRY mode_sense ENTRY mode_sense2 ENTRY start_unit ENTRY stop_unit ENTRY set_512_mode ENTRY notify_me ENTRY set_disk_sw ENTRY trash_volume ENTRY save_dp ENTRY restore_dp ENTRY set_our_dp ENTRY check_532_rw ENTRY munge_532 ENTRY divide PRINT OFF INCLUDE 'scsihd.equates' INCLUDE 'M16.MEMORY' INCLUDE 'M16.UTIL' INCLUDE 'M16.MISCTOOL' PRINT ON EJECT ;____Mem_Manager_____ ;******************************************************* ; ; This routine is used to Get a User ID from the ; memory manager for the SCSI Driver. This is ; required to get a userID for access reference. ; ; Inputs: None. ; ; Outputs: SCSID_uID = userID. ; Registers = Scrambled ; ; Errors: $0207 iderr Invalid userID. ; ;******************************************************* EXPORT get_mm_id get_mm_id PROC ; ; Get userID. ; pushword #$0000 pushword #scsi_duid _GetNewID pla sta |master_uid sta |scsi_uid @rts rts ENDP EJECT ;******************************************************* ; ; This routine is used to get the SCSI Manager Number ; from the Supervisory Dispatcher at startup time. ; ; Inputs: None. ; ; Outputs: scsi_mgrnum = SCSI Manager Number ; All Registers = scrambled ; ; Errors: None. ; ;******************************************************* EXPORT get_scsimgr get_scsimgr PROC ; ; Get userID. ; lda #$0000 ; Supervisor Driver Number (Unknown at this time) tax ; Supervisor Call Number ($0000) ldy #$0002 ; Spervisor ID for SCSI Manager ($0002) jsr |rout2_s_disp stx |scsi_mgrnum ; Preserve SCSI Driver Number for later use. rts ENDP EJECT ;******************************************************* ; ; 'zero_mem' ; ; This routine will fill a section of memory with ; $00s. ; ; Inputs: Acc = Buffer Size ; X = Low Byte of new RAM Address ; Y = High Byte of new RAM Address ; ; Outputs: scsi_zp0 = Long Pointer to new RAM ; Address ; Acc = Scrambled ; ; Errors: None. ; ;******************************************************* EXPORT zero_mem zero_mem PROC ; ; Save the buffer size. ; sta @buff_size ; ; Setup MOVE_INFO call for a ; non-incrementing source and an ; incrementing destination. ; pushlong #null_buff ;Source phy ;Destination High Word phx ;Destination Low Word ; ; Restore buffer size. If = 0 then ; we are to do an entire bank or at ; least 64k bytes. This may cross ; banks. ; lda @buff_size beq @do_64k pea $0000 pha bra @move_type @do_64k pea $0001 pea $0000 @move_type pea #move_scon_dinc jsl move_info @rts rts ; ; Data for this call ; @buff_size dc.w null null_buff dc.w null ENDP EJECT ;******************************************************* ; ; This routine is used to request a section of RAM from ; the memory manager for use by the driver. This ; routine allocates space for as requested by the byte ; count in the Acc. ; ; Inputs: Acc = Number of bytes requested. ; 0 = 1 bank ; ; Y = Offset to where the Handle ; should be stored within ; the allocated structure. ; ; Outputs: X = Low Word of new RAM Address ; Y = High Word of new RAM Address ; scsi_zp0 = Long Pointer to new RAM ; Address ; Acc = Scrambled ; ; Errors: Not enough memory if carry set. ; ;******************************************************* EXPORT get_space get_space PROC ; ; Request Acc bytes of RAM from ; Memory Manager. ; sty |hndl_offset pushlong #00000000 ;Space for result handle cmp $0000 ;Is it Null? beq @null ;Yes. Request 1 bank pushword #0000 ;Size in bytes of requested memory. bra @stuff_a @null pushword #0001 ;Request 1 bank @stuff_a sta |buff_len pha pushword scsi_uid ;Our User ID ;Attributes of requested mem. pea attrfixed++\ attrnospec++\ attrpage pushlong #00000000 ;Location Pointer. Unused. _newhandle plx ; Get handle ply bcs @rts ; Exit if an error. ; ; Save Handle for later ; phy phx ; ; DEREF the Handle and get a ; pointer for the new RAM. ; stx smgr_pl_ptr,x lda #^get_dev_lst sta >smgr_pl_ptr+2,x ; ; Load registers with their ; required values. ; lda |scsi_mgrnum ldx #cmd_get_dvc jsr |rout2_s_disp @rts_long bcs @rts ; ; Restore our direct page Device List ; lda |dvc_buff sta dvc_list,x lda dvc_list+2,x txa sta |direct_page sta |exit_dpage ; ; Undocumented feature. Store the SCSI ; Managers Direct Page in the Default DIB ; for external Access. ; clc adc #$0100 sta >default_dib+dib.handle ; ; Set our Direct Page with the first ; 'x' Bytes equal to the GS/OS DP ; settings. ; ; clc ; Calculate Source Address of GS/OS tdc ; Direct Page that we want. sta |gsos_dpage ; Preserving GS/OS DP for later use. adc #dev_num pea $0000 pha ; clc ; Calculate Destination Address of lda |direct_page ; our Direct Page that we want. adc #dev_num pea $0000 pha pushlong #dib_ptr+4 ;Length of the move pushword #move_sinc_dinc jsl move_info ;Move the data ; ; Restore the Direct Page that we ; borrowed until this was done. ; jsr restore_dp ; ; Set our Direct Page. ; lda |direct_page tcd ; ; Check for zero Devices. ; @we_did_it ldy #$0002 lda [dvc_list],y beq @no_devices ; ; Ensure that device count is ; in range. ; cmp #$0100+1 ;No more than 256 devices blt @count_ok lda #max_dvc_cnt ;Max Count @count_ok sta |dvc_count jsr |make_dib stx Low cmp #max_partitions+1 blt @cnt_ok @force_max lda #max_partitions @cnt_ok sta |part_cnt cmp #$0002+1 blt @non_linked dec @linked @non_linked dec |part_cnt bpl @main ; ; No valid entry. Set as if no ; partitions. ; @single jsr no_partition ;Marks DIB as online and switched also. jsr trash_volume ;Trash the volume if caller wishes. ;See |trash_it flag in trash_volume lda #null clc rts ; ; Check validity of partiton map. ; @main jsr check_map_entry bcc @chk_pdos ; ; It was undefined or unusable ; ; Is the Pointer good? ; ; Is it a cold DIB? ; ldy #dib.dvcflag lda [add_dib_here],y and #cold_dib beq @over_cold ;No. Skip clear code. ; ; Mark DIB to the Default. ; ldy #dib.dvcflag lda #wait_mode++\ ; Wait Mode is default cold_dib ; and they start cold. sta [add_dib_here],y ; ; Must set Head Link Ptr, Forward ; Device Link Ptr, and DIB Device ; Number to Null. ; lda #null ldy #dib.devnum sta [add_dib_here],y ldy #dib.headlnk sta [add_dib_here],y ldy #dib.fdvclnk sta [add_dib_here],y ; ; And skip it. ; Is there more to do? ; @over_cold dec |part_cnt bmi @do_dpi ;No! jmp @main_loop ;Yes! ; ; Check to see if the post driver install ; list contains any entries. ; @do_dpi jsr do_post_install ; ; Check the only one flag. If true ; then unlink it. ; lda |only_one bne @done ldy #dib.dvcchar lda [rebuild_zp],y and #linked_dvc--\ $ffff sta [rebuild_zp],y ; ; Clean exit. ; @done ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ IF scsi_dtype = mcd_40\ OR scsi_dtype = direct_acc THEN jsr mode_sense lda |internal_buff+1 bpl @write_enable @write_protect ldy #dib.dvcchar lda [dib_ptr],y and #write_allow--\ $ffff bra @wp_chk @write_enable ldy #dib.dvcchar lda [dib_ptr],y ora #write_allow @wp_chk sta [dib_ptr],y lda #$0000 ENDIF ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ clc @rts rts ; ; Check the Overflow bit. If it is set, ; then this is a ProDOS Partition and we ; need to set the correct bit in the DIB. ; @chk_pdos bvc @over_1 ; ; Set the ProDOS Bit. ; ldy #dib.dvcflag lda [dib_ptr],y ora #pdos_part sta [dib_ptr],y ; ; Issue call to fix unit 1. This will ; guarantee that the first unit is also ; the first ProDOS Partition on the disk. ; jsr fix_unit_1 ; ; Get the Block Count for this ; Partition and store it in the ; DIB. The count as it exists ; in the partition data is stored ; High byte to Low byte. We will ; need to alter this to Low --> High ; format. ; @over_1 ldy #dib.blkcnt lda |pm.PartBlkCnt+2\ +internal_buff xba sta [dib_ptr],y ldy #dib.blkcnt+2 lda |pm.PartBlkCnt\ +internal_buff xba sta [dib_ptr],y ; ; Now we need to get the starting ; location for this partition. This ; will be added to the requested ; block to generate a real block ; address. Also in High --> Low format. ; ldy #dib.start_blk+2 lda |pm.PyPartStart+2\ +internal_buff sta [dib_ptr],y ldy #dib.start_blk lda |pm.PyPartStart\ +internal_buff sta [dib_ptr],y ; ; Get Location of this partition on disk. ; ldy #dib.part_blk lda |rpm_blk_num sta [dib_ptr],y ; ; Mark DIB as online and switched. ; ldy #dib.dvcflag lda [dib_ptr],y and #dvc_hardofl--\ $ffff ora #dvc_switch++\ dvc_online sta [dib_ptr],y ;------------------------------------------------------------------------------- IF scsi_dtype = direct_acc THEN ; ; Set the Write Allow/Read Allow ; Mask byte to allow all bits to pass. ; ; This is used to filter or strip out the ; Write Enable bit in the case where the ; DIB Status says that the partition is ; write enabled but the disk is physically ; write protected. This can happen with a ; Partitioned Syquest Drive. ; lda #$ffff sta @mask_flag ; ; Is the device Removable? ; ldy #dib.dvcchar lda [dib_ptr],y and #removable beq @non_remove ;No. ; ; Issue the MODE SENSE Call to see if ; Write Protected. ; jsr mode_sense2 ;Issue call to use Sense Buffer bcs @non_remove ; ; Check the Write Protected Bit. ; lda |sense_data+\ mode.w_protect-1 ;But bit in Hi Byte bpl @non_remove ; ; Set the Write Allow/Read Allow ; Mask byte to filter the Write Allow out. ; lda #write_allow--\ $ffff sta @mask_flag ; ; Set the Characteristics to Match the ; Read and Write Enables in the Partition ; Status Field. ; @non_remove lda |pm.PartStatus+2\ +internal_buff xba and #vconf_wr_enable++\ vconf_rd_enable asl a sta @temp ldy #dib.dvcchar lda [dib_ptr],y and #write_allow++\ read_allow--\ $ffff ora @temp and @mask_flag sta [dib_ptr],y ENDIF ;------------------------------------------------------------------------------- ; ; Mark DIB as Linked. ; lda @linked bpl @skip_link ldy #dib.dvcchar lda [dib_ptr],y ora #linked_dvc sta [dib_ptr],y ; ; Inc the ONLY_ONE Flag. If it is ; null then save the dib_ptr. On ; exit we will check this flag and ; if = 0 we will use this pointer ; to clear the linked flag. ; inc |only_one bne @skip_link lda Low cmp #max_partitions+1 blt @cnt_ok @force_max lda #max_partitions @cnt_ok sta |part_cnt dec |part_cnt bpl @main ; ; No valid entry. Set as if no ; partitions. ; jsr no_partition clc rts ; ; Check validity of partiton map. ; @main jsr check_map_entry bcc @chk_pdos ; ; It was undefined or unusable ; Mark DIB to the Default. ; ldy #dib.dvcflag lda #wait_mode++\ ; Wait Mode is default cold_dib ; and they start cold. sta [next_dib],y ; ; Must set Head Link Ptr, Forward ; Device Link Ptr, and DIB Device ; Number to Null. ; lda #null ldy #dib.devnum sta [next_dib],y ldy #dib.headlnk sta [next_dib],y ldy #dib.fdvclnk sta [next_dib],y ; ; And skip it. ; Is there more to do? ; dec |part_cnt bpl @main_loop ; ; Clean exit. ; @done clc @rts rts ; ; Check the Overflow bit. If it is set, ; then this is a ProDOS Partition and we ; need to set the correct bit in the DIB. ; @chk_pdos bvc @over ; ; Set the ProDOS Bit. ; ldy #dib.dvcflag lda [next_dib],y ora #pdos_part sta [next_dib],y ; ; Issue call to fix unit 1. This will ; guarantee that the first unit is also ; the first ProDOS Partition on the disk. ; jsr fix_unit_1 ; ; Get the Block Count for this ; Partition and store it in the ; DIB. The count as it exists ; in the partition data is stored ; High byte to Low byte. We will ; need to alter this to Low --> High ; format. ; @over ldy #dib.blkcnt lda |pm.PartBlkCnt+2\ +internal_buff xba sta [next_dib],y ldy #dib.blkcnt+2 lda |pm.PartBlkCnt\ +internal_buff xba sta [next_dib],y ; ; Now we need to get the starting ; location for this partition. This ; will be added to the requested ; block to generate a real block ; address. Also in High --> Low format. ; ldy #dib.start_blk+2 lda |pm.PyPartStart+2\ +internal_buff sta [next_dib],y ldy #dib.start_blk lda |pm.PyPartStart\ +internal_buff sta [next_dib],y ; ; Get Location of this partition on disk. ; ldy #dib.part_blk lda |rpm_blk_num sta [next_dib],y ; ; Set this device to ONLINE. ; ldy #dib.dvcflag lda [next_dib],y ora #dvc_online sta [next_dib],y ;------------------------------------------------------------------------------- IF scsi_dtype = direct_acc THEN ; ; Set the Characteristics to Match the ; Read and Write Enables in the Partition ; Status Field. ; lda |pm.PartStatus+2\ +internal_buff xba and #vconf_wr_enable++\ vconf_rd_enable asl a sta @temp ldy #dib.dvcchar lda [next_dib],y and #write_allow++\ read_allow--\ $ffff ora @temp sta [next_dib],y ENDIF ;------------------------------------------------------------------------------- ; ; Increment the partition count. ; inc |part_num beq @chk_ram ; ; Update the High seven bits of the ; unit number checking for the max ; value of 'max_partitions'. ; ldy #dib.unitnum lda [next_dib],y tax and #max_p_mask cmp #max_p_mask beq @all_done txa clc adc #p_mask_adder sta [next_dib],y inc |vPart_cnt ; ; All done with the DIB Update now ; do we have any more DIBs, and if ; so, do we have any more RAM left ; to build further DIBs? ; @chk_ram dec |part_cnt bmi @all_done dec |main_caller jsr chk_ram bcs @bad_call ;ERROR? jmp @main_loop ;No. Do the next one. @bad_call cmp #drvr_no_dev ;Yes. Then Exit bne @sec clc rts @sec sec rts ; ; Clean Exit ; @all_done clc rts ; ; Data Area ; @temp dc.w null ELSE ;------------------------------------------------------------------------------- ; ; Clean Exit ; lda #null clc rts ENDIF ;------------------------------------------------------------------------------- ENDP EJECT ;******************************************************* ; ; 'dibicise_new_ram' ; ; This routine takes the DIB located at [last_dib] and ; copies it into the new ram space. It does this ; while preserving the handle at offset 'dib.handle'. ; By so doing, it will be possible to free this ram ; space at some later time if that is deemed correct. ; ; Inputs: Low format *** ; lda |rpm_blk_num xba inc a xba sta |rpm_blk_num ; ; Set internal command flag ; @block_set stz |stat_cont ;We used the flag, now clear it. dec |internal ; ; Set the Partition call flag ; dec |f_partition ; ; Set the Call Type and Issue the ; READ BLOCK Command. ; lda #scsit_stat sta |call_type ; ; Issue the call. ; jsr check_532_rw @rts rts ; ; Data for the READ BLOCK Command ; @read_part dc.b $08 dc.b null EXPORT rpm_blk_num rpm_blk_num dc.w null dcb.b 10,null ENDP EJECT ;******************************************************* ; ; 'write_pm_blk' ; ; ; ; Inputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; ; Outputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; ; Errors: Carry set if operation could not be ; completed. Out of memory for example. ; ;******************************************************* EXPORT write_pm_blk write_pm_blk PROC ; ; Tell the Main Driver where ; our command structure resides. ; lda #@write_part sta > 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 ldy #dib.blkcnt sta [dib_ptr],y lda |block.count\ +internal_buff xba adc #null ldy #dib.blkcnt+2 sta [dib_ptr],y @over_0 ldy #dib.start_blk lda #null sta [dib_ptr],y ldy #dib.start_blk+2 sta [dib_ptr],y ; ; Set Read and Write Enables ; lda >default_dib+dib.dvcchar ;Get Default Settings for and #write_allow++\ ;Write Enable read_allow++\ ;Read Enable format_allow ;And Format Allowed ldy #dib.dvcchar ora [dib_ptr],y ;Combine with the current sta [dib_ptr],y ;Settings for this device ; ; Mark DIB as online and switched. ; ldy #dib.dvcflag lda [dib_ptr],y and #dvc_hardofl--\ $ffff ora #dvc_switch++\ dvc_online sta [dib_ptr],y sec rts ENDP EJECT ;******************************************************* ; ; 'check_map_entry' ; ; Check the Partition Map Entry currently loaded in ; the internal buffer. If it is of type ; 'Apple_partition_map', 'Apple_Driver', 'Apple_Free', ; or 'Apple_Scratch', then this routine will return ; with the carry set. Any other type will return ; with the carry clear. In addition, 'Apple_ProDOS' ; will return with the overflow flag set. ; ; Inputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; ; Outputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; ; Errors: Carry set if Partition Map Entry is not ; for a valid Volume. Overflow set if the ; Partition is a ProDOS Partition. ; ;******************************************************* EXPORT check_map_entry check_map_entry PROC ; ; This routine runs in ; 8 bit m and x only. ; short ; ; Is it ProDOS? ; ldx #@p_map-@prodos-2 ldy #null @loop lda |pm.PartType\ +internal_buff,y beq @over_0 ;Yes or null. Either way we do the rest. cmp @prodos,y beq @next eor #'A'--'a' cmp @prodos,y bne @over_0 ;No. Continue on. @next iny dex bpl @loop brl @pdos_part ;Skip over 8 bit code area to 16 bit area. ; ; Is it the Partition Map? ; @over_0 ldx #32-1 ldy #null @loop_0 lda |pm.PartType\ +internal_buff,y beq @skip ;Yes or null. Either way we skip it. cmp @p_map,y beq @next_0 eor #'A'--'a' cmp @p_map,y bne @over_1 ;No. Continue on. @next_0 iny dex bpl @loop_0 bra @skip ;Yes. Skip it. ; ; Is it a FREE Partition? ; @over_1 ldx #32-1 ldy #null @loop_1 lda |pm.PartType\ +internal_buff,y beq @skip ;Yes or null. Either way we skip it. cmp @free,y beq @next_1 eor #'A'--'a' cmp @free,y bne @over_2 ;No. Continue on. @next_1 iny dex bpl @loop_1 bra @skip ;Yes. Skip it. ; ; Is it a SCRATCH Partition? ; @over_2 ldx #32-1 ldy #null @loop_2 lda |pm.PartType\ +internal_buff,y beq @skip ;Yes or null. Either way we skip it. cmp @scratch,y beq @next_2 eor #'A'--'a' cmp @scratch,y bne @over_3 ;No. Continue on. @next_2 iny dex bpl @loop_2 ; ; Is it a Driver Partition? ; @over_3 ldx #32-1 ldy #null @loop_3 lda |pm.PartType\ +internal_buff,y beq @skip ;Yes or null. Either way we skip it. cmp @driver,y beq @next_3 eor #'A'--'a' cmp @driver,y bne @over_4 ;No. Continue on. @next_3 iny dex bpl @loop_3 ; ; At this point the Current Partition ; Type matched one of the three types ; checked for. Exit with the carry ; set. ; @skip longmx sec rts ; ; At this point the Current Partition ; Type did not match one of the three ; types checked for and it was not a ; ProDOS Partition.. Exit with the ; Carry and Overflow bits clear. ; @over_4 longmx clc clv rts ; ; At this point the Current Partition ; Type is a ProDOS Partition. Exit with ; the Carry clear and Overflow set. ; @pdos_part longmx clc sep #%01000000 ;Set the v flag rts ; ; Inactive Partion Types to check for. ; STRING ASIS @prodos dc.b 'Apple_ProDOS' dc.b $00 @driver dc.b 'Apple_Driver' dc.b $00 @p_map dc.b 'Apple_partition_map' dc.b $00 @free dc.b 'Apple_Free' dc.b $00 @scratch dc.b 'Apple_Scratch' dc.b $00 STRING PASCAL ENDP EJECT ELSE ;part_suprt = true ;------------------------------------------------------------------------------- EXPORT read_pm_blk read_pm_blk PROC EXPORT check_map_entry check_map_entry lda #null clc clv rts EXPORT rpm_blk_num rpm_blk_num dc.w null EXPORT chk_map chk_map ; ; We can't have a valid partition ; map, so this device will be ; treated as a single non-partitioned ; device. ; EXPORT no_partition ; ; Issue the READ CAPACITY Command. ; no_partition jsr read_capacity bcs @over_0 ;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 ldy #dib.blkcnt sta [dib_ptr],y lda |block.count\ +internal_buff xba adc #null ldy #dib.blkcnt+2 sta [dib_ptr],y @over_0 ldy #dib.start_blk lda #null sta [dib_ptr],y ldy #dib.start_blk+2 sta [dib_ptr],y ; ; Mark DIB as online and switched. ; ldy #dib.dvcflag lda [dib_ptr],y and #dvc_hardofl--\ $ffff ora #dvc_switch++\ dvc_online sta [dib_ptr],y sec rts ENDIF ;part_suprt = true ;------------------------------------------------------------------------------- ;____Cache_Suport____ ;------------------------------------------------------------------------------- IF cache_blks = true THEN ;******************************************************* ; ; 'r_all_in_cache' ; ; This routine is used to check if the entire ; requested block count is in the cache. This routine ; will check each block individually, incrementing the ; block count and subtracting the block size from the ; request count until either a block is found that is ; not in the cache (Exit Carry Set) or request count ; has been exausted (Exit Carry Clear). ; ; On entry this routine clears some values to indicate ; it's starting point for this call. As it goes ; throughthe cache looking for blocks, it will fetch ; the block from the cache and advance the starting ; point. What this does is eliminate double searches ; throughthe cache and if a read is needed, these ; blocks will not have to be transfered. When this ; routine exits, the caller will think that the first ; block that we found that was not in the cache was ; the first block requested. For this reason, any ; code that uses this call will need to preserve those ; values so that they can be restored on exit. ; ; If we receive a Read Call for 256 blocks and the ; first 128 are in the cache, then we don't want to ; re-read them, and we don't want to do a find again ; later when we fetch them. let's fetch them now and ; advance our pointers. ; ; Inputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; 0 if any other error occurs. ; Error code is in Acc. ; ;******************************************************* EXPORT r_all_in_cache r_all_in_cache PROC ; ; Switch Direct Pages. ; lda |gsos_dpage tcd ; ; Get the requested count and devide ; by block size to get the loop counter. ; If Count = 0, then exit. ; lda buff_ptr,x sta |c_strt_buffer lda buff_ptr+2,x sta |c_strt_buffer+2 lda rqst_cnt,x sta |c_strt_rqst_cnt lda rqst_cnt+2,x sta |c_strt_rqst_cnt+2 lda block_num,x sta |c_strt_blk_num lda block_num+2,x sta |c_strt_blk_num+2 ; ; Validate Flag for the Read Cache ; Routines ; dec |cache_valid txa tcd plp pla rts ; ; Internal Data ; @blk_cnt dc.l null ; ; The following values are used to advance ; the starting point of the cache calls. ; EXPORT c_strt_buffer EXPORT c_strt_rqst_cnt EXPORT c_strt_blk_num EXPORT cache_valid c_strt_buffer dc.l null ;Starting Buffer Pointer c_strt_rqst_cnt dc.l null ;Starting Request Count c_strt_blk_num dc.l null ;Starting Block Number cache_valid dc.w null ENDP EJECT ;******************************************************* ; ; 'w_update_cache' ; ; This routine is used when writting data to the disk ; with a cache priority of $0000. If the block is in ; the cache, then the cache will be updated. If not, ; then nothing will happen. ; ; Inputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; Carry Clear = Always place in cache ; Carry set = Only place in cache if ; already there. ; ; Outputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; ; Errors: Carry set if requested block is not ; added to the cache. ; ;******************************************************* EXPORT w_update_cache w_update_cache PROC ; ; Zero Deferred Write failed flag. ; stz @deferred ; ; Preserve Carry Flag for later. ; php ; ; Set GS/OS Direct Page ; lda |gsos_dpage tcd ; ; Preserve Block Number and request ; count. Set count to 1 block per ; call. ; lda mcd_40 THEN jsr set_512_mode ENDIF ;------------------------------------------------------------------------------- ; ; Issue the READ CAPACITY Command. ; jsr read_capacity bcs @over_0 ;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 sta |t_dvc_blocks lda |block.count\ +internal_buff xba adc #null sta |t_dvc_blocks+2 @over_0 stz |trash_it ;DO NOT TRASH THIS DISK. pei 3 = Carry set ; ; Restore the Direct Page Values. ; @restore_dp php jsr set_our_dp plp ; ; Restore Auto Sensing Pointer. ; ldy #dib.rslt_ptr+2 pla sta [dib_ptr],y ldy #dib.rslt_ptr pla sta [dib_ptr],y rts ; ; AUDIO STATUS Command Packet ; @chk_play dc.b $cc ;Command Number dc.b null ;SCSI Command Flags dcb.b 10,null ;Reserved ; ; Data received for this call ; @play_data dcb.b 6,null ENDP ENDIF ;------------------------------------------------------------------------------- EJECT ;******************************************************* ; ; The REQUEST SENSE Call is used to request any ; information from the target device that might tell ; us something about the way that the last call ; competed. This call should always be issued if any ; SCSI Command returns from the SCSI Manager with a ; CHECK CONDITION in the status result field. The ; data returned will be kept until the next REQUEST ; SENSE Command is issued. A flag however will be set ; if any other commands are received by the SCSI Driver ; indicating that this data is outdated. ; ; Inputs: Acc = Unspecified ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; ; Outputs: Acc = Error Code if any ; |sense_data = Data returned by the device ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = Ours ; Data Bank = Ours ; ; Errors: Carry set if Unit no ready. ; ;******************************************************* EXPORT rqst_sense rqst_sense PROC ; ; Set Internal Command Flag ; dec |internal ; ; Set Parm Pointer. ; lda #@rqst_sens_p sta dev_num,x pha lda >dib_ptr,x pha lda >dib_ptr+2,x pha lda dev_num,x lda dib_ptr,x lda dib_ptr+2,x txa tcd jsl set_disksw tay lda |direct_page tcd ldx |gsos_dpage pla sta >dib_ptr+2,x pla sta >dib_ptr,x pla sta >dev_num,x stz leave_switched ;Clear this flag *** MSG 12/12/91 *** tya cmp #$0001 rts ; ; Data for this call ; EXPORT leave_switched leave_switched dc.w null ; *** MSG 12/12/91 *** ELSE ;------------------------------------------------------------------------------- lda #null clc rts ENDIF ;------------------------------------------------------------------------------- ENDP EJECT ;******************************************************* ; ; TRASH_VOLUME ; ; This routine write a non-formatted pattern to block ; 2 of the volume whose DIB is [dib_ptr]. This is to ; force the OS to re-format or lay down the OS data for ; that volume rather than using what is already there ; and appears to be valid. ; ; Inputs: