briana@tau-ceti.isc-br.com (Brian Who?) (10/06/90)
Posting-number: Volume 15, Issue 3 Submitted-by: briana@tau-ceti.isc-br.com (Brian Who?) Archive-name: st-01_scsi/part02 Here is part two... Submitted-by: briana@tau-ceti.isc-br.com Archive-name: ST01SCSI.12/part02 #!/bin/sh # This is part 02 of ST01SCSI.12 # ============= struct.inc ============== if test -f 'struct.inc' -a X"$1" != X"-c"; then echo 'x - skipping struct.inc (File already exists)' else echo 'x - extracting struct.inc (Text)' sed 's/^X//' << 'SHAR_EOF' > 'struct.inc' && X; X; Structures for SCSI commands X; Xio_cmd struc Xio_cmd_op db ? ;Opcode X if extended_io Xio_cmd_lun db ? Xio_cmd_lba_b3 db ? ;Logical Block Address Xio_cmd_lba_b2 db ? Xio_cmd_lba_b1 db ? Xio_cmd_lba_b0 db ? Xio_cmd_dummy1 db ? Xio_cmd_cnt_b1 db ? ;Block Count Xio_cmd_cnt_b0 db ? Xio_cmd_dummy2 db ? X else Xio_cmd_lba_b2 db ? ;Logical Block Address / Lun Xio_cmd_lba_b1 db ? Xio_cmd_lba_b0 db ? Xio_cmd_cnt_b0 db ? ;Block Count Xio_cmd_dummy1 db ? X endif Xio_cmd ends X Xtio_cmd struc Xtio_cmd_op db ? ;Opcode Xtio_cmd_lun db ? ;Lun Xtio_cmd_cnt_b2 db ? ;Block Count Xtio_cmd_cnt_b1 db ? Xtio_cmd_cnt_b0 db ? Xtio_cmd_dummy1 db ? Xtio_cmd ends X X; X; Format the Unit X; Xfmt_cmd struc Xfmt_cmd_op db ? ;Opcode Xfmt_cmd_type db ? ;Format Type Xfmt_cmd_dummy1 db ? Xfmt_cmd_il_b1 db ? ;Interleave (MSB) Xfmt_cmd_il_b0 db ? ;Interleave (LSB) Xfmt_cmd_dummy3 db ? Xfmt_cmd ends X X; X; Verify Sectors X; Xver_cmd struc Xver_cmd_op db ? ;Opcode Xver_cmd_lun db ? ;Lun Xver_cmd_lba_b3 db ? ;Logical Block Address MSB Xver_cmd_lba_b2 db ? Xver_cmd_lba_b1 db ? Xver_cmd_lba_b0 db ? ;Logical Block Address LSB Xver_cmd_dummy1 db ? Xver_cmd_len_b1 db ? ;Length MSB Xver_cmd_len_b0 db ? ;Length LSB Xver_cmd_dummy2 db ? Xver_cmd ends X X; X; Load / Unload a Tape X; Xload_cmd struc Xload_cmd_op db ? ;Opcode Xload_cmd_lun db ? ;Lun Xload_cmd_dummy1 db 2 dup (?) Xload_cmd_type db ? ;Load / Unload Xload_cmd_dummy2 db ? Xload_cmd ends X X; X; Write Filemarks on a Tape X; Xfm_cmd struc Xfm_cmd_op db ? ;Opcode Xfm_cmd_lun db ? ;Lun Xfm_cmd_cnt_b2 db ? ;Filemark MSB Xfm_cmd_cnt_b1 db ? Xfm_cmd_cnt_b0 db ? ;Filemark LSB Xfm_cmd_dummy db ? Xfm_cmd ends X X; X; Space a Tape X; Xspace_cmd struc Xspace_cmd_op db ? ;Opcode Xspace_cmd_code db ? Xspace_cmd_cnt2 db ? ;Count Xspace_cmd_cnt1 db ? Xspace_cmd_cnt0 db ? Xspace_cmd_dummy db ? Xspace_cmd ends X X; X; Structure returned by the sense command X; Xsense struc X if extended_sense Xsense_ccs db ? ;0x70 for Extended Sense Xsense_dummy1 db ? Xsense_sense db ? ;Sense (Error) Group Xsense_lba_b3 db ? ;Failed Block Address Xsense_lba_b2 db ? Xsense_lba_b1 db ? Xsense_lba_b0 db ? X else Xsense_sense db ? ;Sense (Error) code Xsense_lba_b2 db ? ;Failed Block Address Xsense_lba_b1 db ? Xsense_lba_b0 db ? X endif Xsense ends X X; X; Structure returned by the unit inquiry command X; Xinq struc Xinq_dev_type db ? ;Device Type Xinq_dev_qual db ? ;Device Qualifier Xinq_stand_rev db ? ;Standard Revision Level Xinq_format db ? ;Response Format Xinq_length db ? ;Length of Extra Data Xinq_reserv1 db ? Xinq_reserv2 db ? Xinq_reserv3 db ? Xinq_manufact db 8 dup (?) ;Manufacture Xinq_product db 16 dup (?) ;Product Xinq ends X X; X; Structure returned by the read drive capacity command X; Xcap struc Xcap_sectors_b3 db ? ;MSB of sector count Xcap_sectors_b2 db ? Xcap_sectors_b1 db ? Xcap_sectors_b0 db ? ;LSB of sector count Xcap_size_b3 db ? ;MSB of sector size Xcap_size_b2 db ? Xcap_size_b1 db ? Xcap_size_b0 db ? ;LSB of sector size Xcap ends X X; X; Structure Definitions For Our Device Driver X; Xbpb struc Xbpb_ss dw ? ;Sector Size Xbpb_au db ? ;Cluster Size in Sectors Xbpb_rs dw ? ;Reserved Sectors Xbpb_nf db ? ;Number of Fats Xbpb_de dw ? ;Number of Root Directory Entries Xbpb_ts dw ? ;Total Number Of Sectors Xbpb_md db ? ;Media Descriptor Xbpb_fs dw ? ;Number of Sectors in each Fat Xbpb_st dw ? ;Number of Sectors per Track Xbpb_nh dw ? ;Number of Heads Xbpb_hs_lsw dw ? ;Hidden Sectors (Least Sig Word) Xbpb_hs_msw dw ? ;Hidden Sectors (Most Sig Word) Xbpb_ts_large dd ? ;Large Total Sector Count Xbpb_res db 6 dup (?) ;Reserved Xbpb ends X X; X; ioctl function 42h X; Xioctl_fmt struc Xioctl_fmt_spec db ? ;Special Flags Xioctl_fmt_head dw ? ;Head to Format Xioctl_fmt_cyl dw ? ;Cylinder to Format Xioctl_fmt ends X X; X; ioctl function 60h X; Xdpb struc Xdpb_special db ? ;Special Flags Xdpb_type db ? ;Device Type Xdpb_attr dw ? ;Device Attributes Xdpb_cyl dw ? ;Device Cylinder Count Xdpb_media db ? ;Device Media Type if Diskette Xdpb_bpb db size bpb dup (?) Xdpb_sectors dw ? ;Sectors in Track Xdpb_track dd SECT_TRACK dup (?) Xdpb ends X X; X; The internal control structure for a SCSI device X; Xunit struc Xunit_1st_drv db ? ;DOS Drive Numbers Xunit_num_drv db ? ;DOS Drive Count Xunit_select db ? ;SCSI Select Bit Xunit_mcheck db ? ;Media Check Byte Xunit_inq_buf db size inq dup (?) Xunit_inq_term db ? Xunit_cap_buf db size cap dup (?) Xunit_sense_buf db size sense dup (?) Xunit ends X X; X; Ioctl Commands X; Xioc struc Xioc_command dw ? ;Command Xioc_param1 dw ? ;Command Dependent Data Xioc_param2 dw ? ;Command Dependent Data Xioc ends X X; X; DOS requests X; Xrh struc Xrh_len db ? ;Length of Packet Xrh_unit db ? ;Unit Code (Block Only) Xrh_cmd db ? ;Command Code Xrh_status dw ? ;Returned Status Xrh_res db 8 dup (?) ;Reserved Xrh ends X Xrh0 struc ;INITIALIZATION Xrh0_rh db size rh dup (?) ;Fixed Portion Xrh0_nunits db ? ;Number of units (Block Only) Xrh0_brk_ofs dw ? ;Break Address (Offset) Xrh0_brk_seg dw ? ;Break Address (Segment) Xrh0_bpb_tbo dw ? ;Pointer to BPB Array (Offset) Xrh0_bpb_tbs dw ? ;Pointer to BPB Array (Segment) Xrh0_drv_ltr db ? ;First Available Drive (DOS 3+, Block Only) Xrh0 ends X Xrh1 struc ;MEDIA CHECK Xrh1_rh db size rh dup (?) ;Fixed Portion Xrh1_media db ? ;Media Descriptor from DPB Xrh1_md_stat db ? ;Media Status returned by Device Driver Xrh1_volid_ofs dw ? ;Offset of Volume ID String (DOS 3+) Xrh1_volid_seg dw ? ;Segment of Volume ID String (DOS 3+) Xrh1 ends X Xrh2 struc ;GET BPB Xrh2_rh db size rh dup (?) ;Fixed Portion Xrh2_media db ? ;Media Descriptor from DPB Xrh2_buf_ofs dw ? ;Offset of Data Transfer Area Xrh2_buf_seg dw ? ;Segment of Data Transfer Area Xrh2_pbpbo dw ? ;Offset of Pointer to BPB Xrh2_pbpbs dw ? ;Segment of Pointer to BPB Xrh2 ends X Xrh4 struc ;INPUT Xrh4_rh db size rh dup (?) ;Fixed Portion Xrh4_media db ? ;Media Descriptor from DPB Xrh4_buf_ofs dw ? ;Offset of Data Transfer Area Xrh4_buf_seg dw ? ;Segment of Data Transfer Area Xrh4_count dw ? ;Transfer Count (Sectors) Xrh4_start dw ? ;Start Sector Number Xrh4 ends X Xrh8 struc ;OUTPUT Xrh8_rh db size rh dup (?) ;Fixed Portion Xrh8_media db ? ;Media Descriptor from DPB Xrh8_buf_ofs dw ? ;Offset of Data Transfer Area Xrh8_buf_seg dw ? ;Segment of Data Transfer Area Xrh8_count dw ? ;Transfer Count (Sectors) Xrh8_start dw ? ;Start Sector Number Xrh8 ends X Xrh9 struc ;OUTPUT VERIFY Xrh9_rh db size rh dup (?) ;Fixed Portion Xrh9_media db ? ;Media Descriptor from DPB Xrh9_buf_ofs dw ? ;Offset of Data Transfer Area Xrh9_buf_seg dw ? ;Segment of Data Transfer Area Xrh9_count dw ? ;Transfer Count (Sectors) Xrh9_start dw ? ;Start Sector Number Xrh9 ends X Xrh12 struc ;OUTPUT IOCTL Xrh12_rh db size rh dup (?) ;Fixed Portion Xrh12_media db ? ;Media Descriptor from DPB Xrh12_buf_ofs dw ? ;Offset of Data Transfer Area Xrh12_buf_seg dw ? ;Segment of Data Transfer Area Xrh12_count dw ? ;Transfer Count (Sectors) Xrh12_start dw ? ;Start Sector Number Xrh12 ends X Xrh19 struc ;IOCTL Xrh19_rh db size rh dup (?) ;Fixed Portion Xrh19_major db ? ;Major Code Xrh19_minor db ? ;Minor Code Xrh19_si dw ? ;Caller SI Register Xrh19_di dw ? ;Caller DI Register Xrh19_buf_ofs dw ? ;Caller Buffer Offset Xrh19_buf_seg dw ? ;Caller Buffer Segment Xrh19 ends SHAR_EOF chmod 0644 struct.inc || echo 'restore of struct.inc failed' Wc_c="`wc -c < 'struct.inc'`" test 7166 -eq "$Wc_c" || echo 'struct.inc: original size 7166, current size' "$Wc_c" fi # ============= subs.asm ============== if test -f 'subs.asm' -a X"$1" != X"-c"; then echo 'x - skipping subs.asm (File already exists)' else echo 'x - extracting subs.asm (Text)' sed 's/^X//' << 'SHAR_EOF' > 'subs.asm' && X; X; Data storage for local subroutines X; Xcmd_ready db SCSI_TESTREADY,0,0,0,0,0 Xcmd_rewind db SCSI_REWIND,0,0,0,0,0 Xcmd_sense db SCSI_REQSENSE,0,0,0,size sense,0 Xcmd_format db SCSI_FORMATUNIT,0,0,0,0,0 Xcmd_space db SCSI_SPACE,1,0,0,0,0 X if extended_io Xcmd_read db SCSI_READBLK,0,0,0,0,0,0,0,1,0 Xcmd_write db SCSI_WRITEBLK,0,0,0,0,0,0,0,1,0 X else Xcmd_read db SCSI_READBLK,0,0,0,1,0 Xcmd_write db SCSI_WRITEBLK,0,0,0,1,0 X endif Xcmd_tread db SCSI_READBLK,1,0,0,0,0 Xcmd_twrite db SCSI_WRITEBLK,1,0,0,0,0 Xcmd_twritefm db SCSI_WRITEFM,0,0,0,1,0 Xcmd_inquire db SCSI_INQUIRY,0,0,0,size inq,0 Xcmd_erase db SCSI_ERASE,1,0,0,0,0 Xcmd_load db SCSI_LOAD,0,0,0,0,0 Xcmd_capacity db SCSI_READSIZE,0,0,0,0,0,0,0,0,0 Xcmd_verify db SCSI_VERIFYBLK,0,0,0,0,0,0,0,SECT_TRACK,0 X X even Xdocmd_cmd dw ? Xdocmd_buf dw ? Xdocmd_buf_seg dw ? Xdocmd_len dw ? Xdocmd_status db ? Xdocmd_tempb db ? X X if dump_sense Xsense_msg db 0dh,07h,'SCSI Unit: 0x' Xsense_unit db 'xx, Sense Status: 0x' Xsense_code db 'xx, Block Address: 0x' X if extended_sense Xsense_addr3 db 'xx' X endif Xsense_addr2 db 'xx' Xsense_addr1 db 'xx' Xsense_addr0 db 'xx',0dh,0ah,'$' X endif X X; X; Reset the SCSI Bus X; Xscsi_reset proc near X pusha X X mov ax,SCSI_CARD_SEG ;Point at the command port X mov es,ax X mov si,SCSI_CMD_PORT X X mov al,CMDBASE or CMDENABLE or CMDRST X mov es:[si],al ;Reset the bus X call wait1ms X mov al,CMDBASE X mov es:[si],al ;All done X mov cx,250 ;Wait 250ms Xreset_loop: call wait1ms X loop reset_loop X X popa X ret Xscsi_reset endp X X; X; Test the Ready Status of a unit X; X; al = return code, 'C' error X; Xscsi_ready proc near X lea di,cmd_ready ;Command X call docmd X ret Xscsi_ready endp X X; X; Request Sense data from a unit and display the result X; Called after every SCSI command with the exit code in 'al' X; Xscsi_sense proc near X pushf X pusha X mov di,cur_unit ;Unit X lea bx,[di].unit_sense_buf ;Buffer Offset X push ds ;Buffer Segment X pop es X mov cx,size sense ;Buffer Size X lea di,cmd_sense ;Command X call docmd X if dump_sense X jc sense_exit X mov di,cur_unit X mov dl,[di].unit_select X if reserve_addr X and dl,07Fh ;Remove Cards Bit X endif X lea bx,sense_unit ;Unit X call hex2asc2 X mov dl,[di].unit_sense_buf.sense_sense X lea bx,sense_code ;Sense X call hex2asc2 X if extended_sense X mov dl,[di].unit_sense_buf.sense_lba_b3 X lea bx,sense_addr3 ;Address X call hex2asc2 X endif X mov dl,[di].unit_sense_buf.sense_lba_b2 X lea bx,sense_addr2 X call hex2asc2 X mov dl,[di].unit_sense_buf.sense_lba_b1 X lea bx,sense_addr1 X call hex2asc2 X mov dl,[di].unit_sense_buf.sense_lba_b0 X lea bx,sense_addr0 X call hex2asc2 X lea dx,sense_msg X call puts X endif Xsense_exit: popa X popf X ret Xscsi_sense endp X X; X; Inquire about the type of a unit X; X; al = return code, 'C' error indicates an error X; Xscsi_inquire proc near X push cx X mov di,cur_unit ;Unit X lea bx,[di].unit_sense_buf ;Buffer Offset X push ds ;Buffer Segment X pop es X mov cx,size sense ;Buffer Size X lea di,cmd_sense ;Command X call docmd ;Always ask first X jc inquire_exit X mov di,cur_unit ;Unit X lea bx,[di].unit_inq_buf ;Buffer Offset X push ds ;Buffer Segment X pop es X mov cx,size inq ;Buffer Size X lea di,cmd_inquire ;Command X call docmd X jnc inquire_exit X call scsi_sense Xinquire_exit: pop cx X ret Xscsi_inquire endp X X; X; Determine the size of a disk X; X; al = return code, 'C' error indicates an error X; Xscsi_capacity proc near X push cx X mov di,cur_unit ;Unit X lea bx,[di].unit_cap_buf ;Buffer Offset X push ds ;Buffer Segment X pop es X mov cx,size cap ;Buffer Size X lea di,cmd_capacity ;Command X call docmd X jnc capacity_exit X call scsi_sense Xcapacity_exit: pop cx X ret Xscsi_capacity endp X X; X; Verify the Track given in an IOCTL Request X; X; al = return code, 'C' indicates an error X; Xscsi_verify proc near X mov di,es:[bx].rh19_buf_ofs ;Command Offset X mov ax,es:[bx].rh19_buf_seg ;Command Segment X mov es,ax X mov ax,es:[di].ioctl_fmt_cyl ;Track X shl ax,SECT_2_CYL ;Convert to Sector X X mov di,cur_bpb ;Add to Drive Offset X mov dx,[di].bpb_hs_msw X X lea di,cmd_verify ;Command X mov [di].ver_cmd_lba_b3,dh ;Insert Sector X mov [di].ver_cmd_lba_b2,dl ; into Command X mov [di].ver_cmd_lba_b1,ah ;Insert Sector X mov [di].ver_cmd_lba_b0,al ; into Command X call docmd X jnc verify_exit X call scsi_sense Xverify_exit: ret Xscsi_verify endp X X; X; Read Some Blocks from the disk given X; the request header in es:bx X; X; al = return code, 'C' indicates an error X; Xdisk_read proc near X mov di,bx X mov cx,es:[di].rh4_count ;Sector Count X mov dx,es:[di].rh4_start ;Starting Sector X mov bx,es:[di].rh4_buf_ofs ;Buffer Offset X mov ax,es:[di].rh4_buf_seg ;Buffer Segment X mov es,ax X X mov si,cur_bpb X lea di,cmd_read ;Command X mov ax,[si].bpb_hs_msw ;Drive Sector Offset X if extended_io X mov [di].io_cmd_lba_b3,ah ;Insert Sector X endif X mov [di].io_cmd_lba_b2,al ;Into the Command X X if multi_sector X mov ax,cx ;Get Sector Count X and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk X jnz disk_r_cok1 ;Check for Boundary X mov ax,CHUNK_MAX Xdisk_r_cok1: shl ax,9 ;Convert to Buffer Size X add ax,bx ;Check for Wrap X else X mov ax,bx ;Check for Wrap X add ax,P_SECT ;The First Time X endif Xdisk_r_loop: jnc disk_r_nowrap X mov ax,bx ;Normalize the X shr ax,4 ;Segment and X mov si,es ;Offset so that X add si,ax ;It dosn't Wrap X mov es,si X and bx,000Fh Xdisk_r_nowrap: push cx X mov [di].io_cmd_lba_b1,dh ;Insert Sector X mov [di].io_cmd_lba_b0,dl ;Into the Command X if multi_sector X and cx,CHUNK_MAX-1 ;Mask Off the I/O Chunk X jnz disk_r_cok2 ;Check for Boundary X mov cx,CHUNK_MAX Xdisk_r_cok2: X if extended_io X mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count X endif X mov [di].io_cmd_cnt_b0,cl ;Into the Command X shl cx,9 ;Convert to Buffer Size X else X mov cx,P_SECT ;Buffer Size X endif X call docmd X pop cx X jc disk_r_exit X if multi_sector X mov ax,cx ;Get Sector Count X and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk X jnz disk_r_cok3 ;Check for Boundary X mov ax,CHUNK_MAX Xdisk_r_cok3: sub cx,ax ;Dec Sector Count X jz disk_r_exit X add dx,ax ;Bump to next Sector X shl ax,9 ;Convert to Buffer Size X add bx,ax X jmp short disk_r_loop X else X inc dx ;Bump to next Sector X add bx,P_SECT X loop disk_r_loop X clc X endif Xdisk_r_exit: jnc disk_r_exit2 ;If no error occured X call scsi_sense ;Display Sense Status Xdisk_r_exit2: mov es,rh_seg X mov bx,rh_off X pushf X mov ax,es:[bx].rh4_count ;Update the Count X sub ax,cx X mov es:[bx].rh4_count,ax X popf X ret Xdisk_read endp X X; X; Write Some Blocks to the disk given X; the request header in es:bx X; X; al = return code, 'C' indicates an error X; Xdisk_write proc near X mov di,bx X mov cx,es:[di].rh8_count ;Sector Count X mov dx,es:[di].rh8_start ;Starting Sector X mov bx,es:[di].rh8_buf_ofs ;Buffer Offset X mov ax,es:[di].rh8_buf_seg ;Buffer Segment X mov es,ax X X mov si,cur_bpb X lea di,cmd_write ;Command X mov ax,[si].bpb_hs_msw ;Drive Sector Offset X if extended_io X mov [di].io_cmd_lba_b3,ah ;Insert Sector X endif X mov [di].io_cmd_lba_b2,al ;Into the Command X X if multi_sector X mov ax,cx ;Get Sector Count X and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk X jnz disk_w_cok1 ;Check for Boundary X mov ax,CHUNK_MAX Xdisk_w_cok1: shl ax,9 ;Convert to Buffer Size X add ax,bx ;Check for Wrap X else X mov ax,bx ;Check for Wrap X add ax,P_SECT ;The First Time X endif Xdisk_w_loop: jnc disk_w_nowrap X mov ax,bx ;Normalize the X shr ax,4 ;Segment and X mov si,es ;Offset so that X add si,ax ;It dosn't Wrap X mov es,si X and bx,000Fh Xdisk_w_nowrap: push cx X mov [di].io_cmd_lba_b1,dh ;Insert Sector X mov [di].io_cmd_lba_b0,dl ;Into the Command X if multi_sector X and cx,CHUNK_MAX-1 ;Mask Off the I/O Chunk X jnz disk_w_cok2 ;Check for Boundary X mov cx,CHUNK_MAX Xdisk_w_cok2: X if extended_io X mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count X endif X mov [di].io_cmd_cnt_b0,cl ;Into the Command X shl cx,9 ;Convert to Buffer Size X else X mov cx,P_SECT ;Buffer Size X endif X call docmd X pop cx X jc disk_w_exit X if multi_sector X mov ax,cx ;Get Sector Count X and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk X jnz disk_w_cok3 ;Check for Boundary X mov ax,CHUNK_MAX Xdisk_w_cok3: sub cx,ax ;Dec Sector Count X jz disk_w_exit X add dx,ax ;Bump to next Sector X shl ax,9 ;Convert to Buffer Size X add bx,ax X jmp short disk_w_loop X else X inc dx ;Bump to next Sector X add bx,P_SECT X loop disk_w_loop X clc X endif Xdisk_w_exit: jnc disk_w_exit2 ;If no error occured X call scsi_sense ;Display Sense Status Xdisk_w_exit2: mov es,rh_seg X mov bx,rh_off X pushf X mov ax,es:[bx].rh8_count ;Update the Count X sub ax,cx X mov es:[bx].rh8_count,ax X popf X ret Xdisk_write endp X X; X; Read Some Blocks from the Tape X; Xtape_read proc near X mov write_flag,FALSE ;Cancel if READ seen X mov di,bx X mov cx,es:[di].rh4_count ;Byte Count X mov ax,cx ;Test for invalid X and ax,P_SECT-1 ;Byte Count X jz tape_r_ok X mov es:[di].rh4_count,0 ;Nothing Read X stc ;Oops X ret Xtape_r_ok: mov bx,es:[di].rh4_buf_ofs ;Buffer Offset X mov ax,es:[di].rh4_buf_seg ;Buffer Segment X mov es,ax X mov ax,bx ;Normalize the X shr ax,4 ;Segment and X mov si,es ;Offset so that X add si,ax ;It dosn't Wrap X mov es,si X and bx,000Fh X lea di,cmd_tread X mov ax,cx ;Convert Bytes X shr ax,9 ;to Blocks X mov [di].tio_cmd_cnt_b1,ah ;Insert into Command X mov [di].tio_cmd_cnt_b0,al X call docmd X jnc tape_r_exit X call scsi_sense Xtape_r_exit: ret Xtape_read endp X X; X; Write Some Blocks to the Tape X; Xtape_write proc near X mov write_flag,TRUE ;Write Done X mov di,bx X mov cx,es:[di].rh8_count ;Byte Count X mov ax,cx ;Test for invalid X and ax,P_SECT-1 ;Byte Count X jz tape_w_ok X mov es:[di].rh8_count,0 ;Nothing Write X mov write_flag,FALSE ;Cancel if ERROR! X stc ;Oops X ret Xtape_w_ok: mov cx,es:[di].rh8_count ;Byte Count X mov bx,es:[di].rh8_buf_ofs ;Buffer Offset X mov ax,es:[di].rh8_buf_seg ;Buffer Segment X mov es,ax X mov ax,bx ;Normalize the X shr ax,4 ;Segment and X mov si,es ;Offset so that X add si,ax ;It dosn't Wrap X mov es,si X and bx,000Fh X lea di,cmd_twrite X mov ax,cx ;Convert Bytes X shr ax,9 ;to Blocks X mov [di].tio_cmd_cnt_b1,ah ;Insert into Command X mov [di].tio_cmd_cnt_b0,al X call docmd X jnc tape_w_exit X mov write_flag,FALSE ;Cancel if ERROR! X call scsi_sense Xtape_w_exit: ret Xtape_write endp X X; X; Do a command X; X; bx => buffer for returned information X; cx = buffer len X; di => command string X; es = buffer segment for returned information X; X; al = return code, 'C' indicates an error X; Xdocmd proc near X pusha X push es X X mov docmd_buf,bx ;Save our arguments X mov docmd_buf_seg,es X mov docmd_len,cx X mov docmd_cmd,di X X mov ax,SCSI_CARD_SEG ;Point at the Card X mov es,ax X mov si,SCSI_CMD_PORT ;Command Port X X; X; Wait for the Bus to become free X; X mov cx,65535 Xidle_loop: mov al,es:[si] ;Get the Status X and al,FREE_MASK X jz try_sel X loop idle_loop X X call scsi_reset X mov al,CBUSBUSY ;Bus still BUSY? X jmp docmd_exit X Xtry_sel: mov al,CMDBASE ;Try to select target X mov es:[si],al X X mov di,cur_unit X mov al,[di].unit_select ;Get our Select Bit X mov di,SCSI_DATA_PORT ;Data Port X mov es:[di],al X X call wait100us ;Spec says wait 90us here X mov al,CMDBASE or CMDENABLE or CMDSEL X mov es:[si],al X X; X; Wait 250 ms for the Target to be SELected X; X mov cx,2500 Xsel_loop: test byte ptr es:[si],STBSY ;Look for BSY bit X jnz cmd_xfer X call wait100us X loop sel_loop X X mov al,CMDBASE or CMDSEL ;Release the data BUS X mov es:[si],al X call wait100us ;Spec says wait 290us X call wait100us ;to abort selection phase X call wait100us X test byte ptr es:[si],STBSY ;Look one final time X jnz cmd_xfer ;Device did answer X mov al,CNOCONNECT ;Nothing Answered X jmp docmd_exit X X; X; Start the Command X; Xcmd_xfer: call wait100us ;Spec say wait 90us here X mov al,CMDBASE or CMDENABLE ;Drop SEL and begin talking X mov es:[si],al Xxfer_loop: mov al,es:[si] X test al,STBSY ;Look for BSY bit X jz xfer_error X test al,STREQ ;And REQ bit X jz xfer_loop X X and al,REQ_MASK ;Look at REQ type X X cmp al,REQ_DATAOUT ;Is it Data Out? X jnz try_datain X call send_data X jmp short xfer_loop X Xtry_datain: cmp al,REQ_DATAIN ;Is it Data In? X jnz try_cmdout X call receive_data X jmp short xfer_loop X Xtry_cmdout: cmp al,REQ_CMDOUT ;Is it Command Out? X jnz try_statin X call send_cmd X jmp short xfer_loop X Xtry_statin: cmp al,REQ_STATIN ;Is it Status In? X jnz try_msgout X mov al,es:[di] ;Get the Status Byte X mov docmd_status,al X jmp short xfer_loop X Xtry_msgout: cmp al,REQ_MSGOUT ;Is it Message Out? X jnz try_msgin X call send_nop X jmp short xfer_loop X Xtry_msgin: cmp al,REQ_MSGIN ;Is it Message In? X jnz xfer_error X X mov al,es:[di] ;Get Message Byte X cmp al,MSG_COMPLETE ;Are We All Done? X jnz short xfer_loop X mov al,docmd_status X or al,al ;Did we have an error? X mov al,COK ;Preload OK code X jz docmd_exit X Xxfer_error: mov al,CERROR ;Command Failed Somehow X Xdocmd_exit: mov docmd_tempb,al X mov al,CMDBASE ;Release the BUS X mov es:[si],al X pop es X popa X mov al,docmd_tempb X cmp al,COK X jz docmd_exit_ok X stc Xdocmd_exit_ok: ret Xdocmd endp X X; X; Receive a Data Stream from the card X; On entry es:[di] points at the data port X; es:[si] points at the command port X; Xreceive_data proc near X mov dx,es ;Save ES X X mov bx,si X mov ax,es X mov cx,docmd_len ;Length X mov di,docmd_buf ;Dest Offset X mov es,docmd_buf_seg ;Dest Segment X mov si,SCSI_DATA_PORT ;Source Offset X mov ds,ax ;Source Segment X mov al,STREQ X mov ah,STBSY X cld X Xreceive_loop: movsb X if multi_sector X dec si ;Don't blow the card buffer X endif X dec cx X jz receive_exit Xreceive_wait: test byte ptr [bx],al ;Ready? X jnz receive_loop X test byte ptr [bx],ah ;Busy? X jz receive_exit X jmp short receive_wait X Xreceive_exit: mov si,SCSI_CMD_PORT ;Restore the Environment X mov di,SCSI_DATA_PORT X mov ax,cs X mov ds,ax X mov es,dx X ret Xreceive_data endp X X; X; Send a Command to the card X; On entry es:[di] points at the data port X; es:[si] points at the command port X; Xsend_cmd proc near X mov bx,docmd_cmd ;Get Command Pointer X mov al,[bx] ;Get a Command Byte X mov es:[di],al ;Send it to Card X inc bx ;Bump for Next Time X mov docmd_cmd,bx X ret Xsend_cmd endp X X; X; Send a Data Stream to the card X; On entry es:[di] points at the data port X; es:[si] points at the command port X; Xsend_data proc near X mov bx,si X mov cx,docmd_len ;Get the Data Count X mov si,docmd_buf ;Source Offset X mov ds,docmd_buf_seg ;Source Segment X mov al,STREQ X mov ah,STBSY X cld X Xsend_loop: movsb X if multi_sector X dec di ;Don't blow the card buffer X endif X dec cx X jz send_exit Xsend_wait: test byte ptr es:[bx],al ;Ready? X jnz send_loop X test byte ptr es:[bx],ah ;Busy? X jz send_exit X jmp short send_wait X Xsend_exit: mov si,SCSI_CMD_PORT ;Restore the Environment X mov di,SCSI_DATA_PORT X mov ax,cs X mov ds,ax X ret Xsend_data endp X X; X; Send a NOP Message X; Xsend_nop proc near X mov al,MSG_NOP ;Oops, send a nop X mov es:[di],al X mov al,CMDBASE or CMDENABLE X mov es:[si],al X ret Xsend_nop endp X X; X; Wait One Milli second X; X; The value of 'cx' is computed for an 8 Mhz Clock X; Xwait1ms proc near X push cx ; (3) = 375ns X mov cx,798 ; (2) = 250ns Xwait_m_loop: loop wait_m_loop ; (10) = 1250ns * X X pop cx ; (5) = 625ns X ret ; (11+) = 1375ns Xwait1ms endp X X; X; Wait One Hundred Micros Seconds X; X; The value of 'cx' is computed for an 8 Mhz Clock X; Xwait100us proc near X push cx ; (3) = 375ns X mov cx,78 ; (2) = 250ns Xwait_u_loop: loop wait_u_loop ; (10) = 1250ns * X X pop cx ; (5) = 625ns X ret ; (11+) = 1375ns Xwait100us endp SHAR_EOF chmod 0644 subs.asm || echo 'restore of subs.asm failed' Wc_c="`wc -c < 'subs.asm'`" test 15830 -eq "$Wc_c" || echo 'subs.asm: original size 15830, current size' "$Wc_c" fi # ============= units.asm ============== if test -f 'units.asm' -a X"$1" != X"-c"; then echo 'x - skipping units.asm (File already exists)' else echo 'x - extracting units.asm (Text)' sed 's/^X//' << 'SHAR_EOF' > 'units.asm' && X; X; target information/control structures X; X even Xunit0 db size unit dup (-1) X even Xunit1 db size unit dup (-1) X even Xunit2 db size unit dup (-1) X even Xunit3 db size unit dup (-1) X even Xunit4 db size unit dup (-1) X even Xunit5 db size unit dup (-1) X even Xunit6 db size unit dup (-1) X ife reserve_addr X even Xunit7 db size unit dup (-1) X endif X X even Xbpb0 db size bpb dup (-1) X even Xbpb1 db size bpb dup (-1) X even Xbpb2 db size bpb dup (-1) X even Xbpb3 db size bpb dup (-1) X even Xbpb4 db size bpb dup (-1) X even Xbpb5 db size bpb dup (-1) X even Xbpb6 db size bpb dup (-1) X even Xbpb7 db size bpb dup (-1) X even Xbpb8 db size bpb dup (-1) X even Xbpb9 db size bpb dup (-1) X even XbpbA db size bpb dup (-1) X even XbpbB db size bpb dup (-1) X even XbpbC db size bpb dup (-1) X even XbpbD db size bpb dup (-1) X even XbpbE db size bpb dup (-1) X even XbpbF db size bpb dup (-1) X X even Xunit_array dw unit0 X dw unit1 X dw unit2 X dw unit3 X dw unit4 X dw unit5 X dw unit6 X ife reserve_addr X dw unit7 X endif X X even Xbpb_array dw bpb0 ;BPB Array for DOS X dw bpb1 X dw bpb2 X dw bpb3 X dw bpb4 X dw bpb5 X dw bpb6 X dw bpb7 X dw bpb8 X dw bpb9 X dw bpbA X dw bpbB X dw bpbC X dw bpbD X dw bpbE X dw bpbF Xbpb_hw_mark dw bpb_array X Xtape_unit dw -1 Xcur_unit dw unit0 Xcur_bpb dw bpb0 X X; X; Given the request header in es:bx X; Return a pointer in ds:di to the unit entry X; or 'C' if no such unit exists. X; X; Do not destroy es:bx !!! X; Xfind_unit proc near X pusha X mov ah,es:[bx].rh_unit ;What drive did they want X lea di,unit_array X lea si,bpb_array X mov cx,MAXUNIT ;How many to search Xfind_loop: mov bx,[di] ;Point at a unit X mov al,[bx].unit_num_drv ;Does this SCSI device X or al,al ;Have any Drives Defined? X jz find_next X mov dh,[bx].unit_1st_drv ;Get First Drive Number Xfind_unit_loop: cmp ah,dh ;Is this the correct drive? X jz find_match X inc si ;Bump to next BPB X inc si X inc dh ;Bump Drive Number X dec al ;Dec Drive count X jnz find_unit_loop ;Try next Drive X jmp short find_next ;Try next SCSI device Xfind_match: mov cur_unit,bx ;Found a match X mov ax,[si] X mov cur_bpb,ax X clc X jmp find_exit Xfind_next: inc di X inc di X loop find_loop X stc ;No More units, Error Xfind_exit: popa X ret Xfind_unit endp X X; X; Given the data in a unit entry, X; create the bpb for the unit. X; Xmake_bpb proc near X mov di,cur_bpb ;Get the current BPB X mov bx,cur_unit ;Get the current Unit X mov [di].bpb_ss,P_SECT X mov [di].bpb_au,CLUSTSIZE X mov [di].bpb_rs,1 X mov [di].bpb_nf,2 X mov [di].bpb_de,512 X mov ah,[bx].unit_cap_buf.cap_sectors_b3 X mov al,[bx].unit_cap_buf.cap_sectors_b2 X or ax,ax X jz make_bpb_last ;Use up the last few sectors X dec ax ;Use up 65536 Sectors X mov [bx].unit_cap_buf.cap_sectors_b3,ah X mov [bx].unit_cap_buf.cap_sectors_b2,al X mov dx,65535 ;Max of 32 Meg X jmp short make_bpb_ts Xmake_bpb_last: mov dh,[bx].unit_cap_buf.cap_sectors_b1 X mov [bx].unit_cap_buf.cap_sectors_b1,0 X mov dl,0 ;Round to nearest Cyl X mov [bx].unit_cap_buf.cap_sectors_b0,0 X dec dx ;Make it zero relative Xmake_bpb_ts: mov [di].bpb_ts,dx X mov [di].bpb_md,0F8h X shr dx,SECT_2_FS X inc dx ;Allow for round-off X mov [di].bpb_fs,dx X mov [di].bpb_st,SECT_TRACK X mov [di].bpb_nh,1 X mov [di].bpb_hs_lsw,0 X mov [di].bpb_hs_msw,0 X ret Xmake_bpb endp SHAR_EOF chmod 0644 units.asm || echo 'restore of units.asm failed' Wc_c="`wc -c < 'units.asm'`" test 3322 -eq "$Wc_c" || echo 'units.asm: original size 3322, current size' "$Wc_c" fi exit 0