procedure tape_transfer(pSB:PtrSessionBlockType;
                   uep: uep_type; request: amrequesttype;
                   bufptr: charptr; abs_position, length: integer);
var
        blocksize: integer;
        block, intra_block_offset, partial_length: integer;

        procedure checkio;
        begin
                if ioresult <> ord(inoerror) then
                        escape(-10);
        end;

begin {tape_transfer}
   { writeln('ENTERING TAPE TRANSFER'); } 
with pTmRec^ do
begin
try
        {block size is known ???? }
        blocksize := uep^.dvrtemp;
        
        { if request = writebytes then
         begin
          uep^.umaxbytes := uep^.umaxbytes + length;
          writeln('umaxbytes bumped to : ',uep^.umaxbytes);
         end; }
         

        block := abs_position div blocksize;
        intra_block_offset := abs_position mod blocksize;
         $IF XDEBUG$  
                WRITELN;
                WRITELN;
                WRITELN;
                WRITELN('TAPE TRANSFER REQUEST: ', REQUEST);
                WRITELN('LENGTH:           ', LENGTH);
                WRITELN('POSITION:         ', ABS_POSITION);
                WRITELN('SCSI BLOCK:       ', BLOCK);
                WRITELN('SCSI INTRA-BLOCK: ', INTRA_BLOCK_OFFSET);
                WRITELN('SCSI BLOCKSIZE:   ', BLOCKSIZE);
                readln;
         $END$  

        if (blocksize <= 256) and (intra_block_offset<>0) then
        begin
                ioresult   := ord(zbadmode);
                escape(-10);
        end;

        {
          Calculate partial first block parameters.
        }
        partial_length := blocksize-intra_block_offset;
        if partial_length > length then {entire transfer in one block}
        partial_length := length;

        case request of
        readbytes, startread:
        begin
                {
                  handle partial block at beginning of transfer.
                }
                if intra_block_offset>0 then
                begin
                        $IF XDEBUG$
                                WRITELN('READING FIRST PARTIAL BLOCK');
                        $END$

                        {read block into TMRec}
                        if CurrentBlock <> block then
                        begin
                                 $IF XDEBUG$ 
           WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1);
                                 $END$ 
                                CurrentBlock := block;
                                ScsiTapeRead(pSB, 
                                 block, 1, BlockSize, addr(BlockBuffer[0]));
                                checkio;
                        end;

                        {move data from TMRec into user's buffer}
                        moveleft(BlockBuffer[intra_block_offset], bufptr^, partial_length);
                        bufptr := addr(bufptr^, partial_length);
                        block := block + 1;
                        length := length-partial_length;
                end;

                {
                  set up for multiple block read in middle and
                  partial read on last block.
                }
                partial_length := length mod blocksize;
                length := length div blocksize;
                if (blocksize <= 256) and (partial_length <> 0) then
                begin
                        {read entire last block for small last partial block reads}
                        partial_length := 0;
                        length := length + 1;
                end;

                {
                 handle multiple block reads
                }
                if (length>0) then
                begin
                         $IF XDEBUG$ 
                                WRITELN('READING MULTIPLE MIDDLE BLOCKS');
                         $END$ 
                        {read directly into user's buffer}
                        ScsiTapeRead(pSB, 
                          block, length, blocksize, bufptr);
                        checkio;
                        bufptr := addr(bufptr^, length*blocksize);
                        block := block+length;
                        length:=0;
                end;

                {
                  handle partial block at end of transfer.
                }
                if (partial_length > 0) then  {partial block at back}
                begin
                        $IF XDEBUG$ 
                                WRITELN('READING LAST PARTIAL BLOCK');
                        $END$ 
                        {read block into TmRec}
                        if CurrentBlock <> block then
                        begin
                                $IF XDEBUG$
                                        WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1);
                                $END$
                                CurrentBlock := block;
                                { writeln('reading it ..'); }
                                ScsiTapeRead(pSB, 
                                  block, 1, blocksize, addr(BlockBuffer[0]));
                                { writeln('read it.'); }
                                checkio;
                        end;

                        {read data from TmRec into user's buffer}
                        moveleft(BlockBuffer[0], bufptr^, partial_length);
                end;
        end;
        writebytes, startwrite:
        begin
                {
                  handle partial block at beginning of transfer.
                }
                if intra_block_offset>0 then
                begin
                        $IF XDEBUG$
                                WRITELN('WRITING PARTIAL BLOCK AT FRONT');
                        $END$
                        {read block into TMRec}
                        if CurrentBlock <> block then
                        begin
                                $IF XDEBUG$
                                        WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1);
                                $END$
                                CurrentBlock := block;
                                ScsiTapeRead(pSB, block, 1, 
                                  BlockSize, addr(BlockBuffer[0]));
                                checkio;
                        end;

                        {read user's data into TmRec block}
                        moveleft(bufptr^, BlockBuffer[intra_block_offset], partial_length);

                        {write TmRec block back to disc}
                        ScsiTapeWrite(pSB, block, 1, 
                          BlockSize, addr(BlockBuffer[0]));
                        checkio;

                        bufptr := addr(bufptr^, partial_length);
                        block := block + 1;
                        length := length-partial_length;
                end;

                {
                  set up for multiple block write in middle and
                  partial write on last block.
                }
                partial_length := length mod blocksize;
                length := length div blocksize;  {length is number of blocks}


                {
                  handle blocks in middle.
                }
                if length>0 then
                begin
                        $IF XDEBUG$
                                WRITELN('WRITING MIDDLE BLOCKS');
                        $END$
                        {write user's buffer to disc}
                        ScsiTapeWrite(pSB, block, length, blocksize, bufptr);
                        checkio;
                        bufptr := addr(bufptr^, length*blocksize);
                        block := block + length;
                end;

                {
                  handle partial block at end of transfer.
                }
                if partial_length>0 then
                begin
                        $IF XDEBUG$
                                WRITELN('WRITING LAST PARTIAL BLOCK');
                        $END$

                        {
                          zero pad small sectors instead of
                          the read modify write operation used for big block sizes
                        }
                        if blocksize < 256 then
                        begin
                                {overwrite block in TmRec, using zero pad}
                                CurrentBlock := block;
                                moveleft(bufptr^, BlockBuffer[0], partial_length);
                                BlockBuffer[partial_length] := #0;
                                moveleft(BlockBuffer[partial_length],
                                        BlockBuffer[partial_length+1],
                                        blocksize-partial_length-1);
                        end
                        else
                        begin
                                {read last partial block into TmRec}
                                if CurrentBlock <> block then
                                begin
                                        $IF XDEBUG$
                                                WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1);
                                        $END$
                                        CurrentBlock := block;
                                        ScsiTapeRead(pSB, block, 
                                         1, blocksize, addr(BlockBuffer[0]));
                                        checkio;
                                end;

                                {move user's buffer into TmRec}
                                moveleft(bufptr^, BlockBuffer[0], partial_length);
                        end;

                        {write out TmRec into last block}
                        ScsiTapeWrite(pSB, block, 1, 
                                         BlockSize, addr(BlockBuffer[0]));
                        checkio;
                end;

               CurrentBlock := -1;   { JWH 8/30/91 }
        end; { writebytes }
        end; {case}
recover
begin
        if escapecode <> -10 then escape(escapecode);
        CurrentBlock := -1;
        $IF XDEBUG$
                blocksize := ioresult;
                WRITELN('TRANSFER ERROR, IOTEMP: ',BLOCKSIZE);
                ioresult := blocksize;
        $END$
end; {try/recover}
end; {with}
  { writeln('LEAVING TAPE TRANSFER'); }
end; {tape_transfer}
