

	$IO_PERFORM steps				25-Sep-1996 JCH, page 1
	Part I, System Service side

 1. Pick up PCB and PHD P1 space pointers
 2. PAL call to read PS [bletch!]
 3. Return error if buffer not aligned
 4. Return error if chan=0
 5. Get FVE pointer from fandle (fandle: IRP@32!<index>)
    5.1 SYSFIOMAC\EXE$FANDLE_TO_FVE(fandle, PCB, PS), pre-optimized MACRO
    5.2 Return 0 if no FVE array
    5.3 Return 0 if index out of range
    5.4 Calculate &FVE[index]
    5.5 Get IRP from FVE, return 0 if none
    5.6 Validate IRP/PS prev access mode, return 0 if IRP mode is inner to PS
    5.7 Verify fandle IRP matches FVE IRP, return 0 if not
    5.8 Return IRP pointer
 6. Return error if NULL FVE pointer
 7. Raise IPL to ASTDEL
 8. Pick up IRP pointer from FVE
 9. Test and clear irp "done" bit interlocked; error return if bit not set
10. Copy data buffer object pointer from FVE into IRP$L_SVAPTE
11. Initialize IRP ASTPRM, P1, P2, P3 from $IO_PERFORM call arguments
12. Clear CACHEIO bit in IRP$L_STS2 as it may have been "left over"
13. Get IOSA BOD from FVE and verify IOSA is aligned and within BO VA limits
14. Clear IOSA count and status
15. If nonnull AST address, set ACB quota bit in IRP [s.b. in $IO_SETUP?]
16. Verify data buffer VA falls within BO VA limits
17. Initialize FDT context area and IRP pointer thereto
18. Get the original function code given to $IO_SETUP & stored in FVE
19. ("chan=same optimization") If chan parameter is same as previous time,
    go to step 20, else verify channel as ff:

    19.1  Inline local ioc$verifychan:
          19.1.1 Error return if channel = 0
	  19.1.2 Swizzle channel number into channel index
	  19.1.3 Error if channel index > process maximum
	  19.1.4 Convert channel number to CCB address
	  19.1.5 Check CCB$B_AMOD against (a) 0 and (b) PS access mode,
	        if error return SS$_IVCHAN or SS$_NOPRIV as appropriate
          19.1.6 Give good return with variable ccb pointing to CCB
    19.2  Pick up UCB pointer from CCB
    19.3  Verify UCB is online, SS$_DEVOFFLINE if not
    19.4  Error return if this is an HBS member unit
?   19.5  Error return if unit does not do LBN I/O (UCB$M_NOCONVRT must be set)
          (Oops, looks like wrong operator precedence)
    19.6  If spooled device and virtual I/O, fetch new UCB from UCB$L_AMB
    19.7  Set IRP status bit HIFORK if fork IPL not IPL$_SCS
    19.8  Store SVA of CCB in IRP and set IRP$V_CCB_LOOKED_UP
    19.9  Pick up DDT and FDT pointers
    19.10 If FDT says this func is buffered, set bufIO to 1, else 0.
    19.11 If not file oriented device, check device access: (Oops, looks
          like possible 64-bit problems here)
          19.11.1 If read operation and CCB$V_RDCHKDON=0,
		  call EXE_STD$CHECK_DEVICE_ACCESS, set CCB$V_RDCHKDON=1
?         (Oops -- may be a 64-bit problem here)
          19.11.2 If write operation and CCB$V_WRTCHKDON=0,
		  call EXE_STD$CHECK_DEVICE_ACCESS, set CCB$V_WRTCHKDON=1
?         (Oops -- may be a 64-bit problem here)


									page 2

    19.12 If virtual I/O to something other than device mounted structured,
          convert to equivalent logical I/O.
    19.13 Initialize IRP$L_STS to IRP$M_FASTIO ! existing IRP$M_FUNC ! bufIO
    19.14 Store chan number and UCB pointer in IRP
    19.15 Skip step 20, continue with step 21
20. Fetch CCB and UCB from IRP, and DDT from UCB
21. Verify channel access mode not more privileged than processor acmode
22. Fetch WCB pointer from IRP (Oops, wcb not used, it would be wrong if 
?      it were, but this line is optimized away)
23. If buffered I/O, check that (a) driver supports 64-bit addressing or
?      (b) bufadr fits in 32 bits. (Oops, should check bufadr+bytecount too,
       how does $QIO handle this?)
24. Init IRP$L_WIND from CCB, note IRP$L_WIND==IRP$L_KAST so we have to
       do this each time -- I think
25. If IRP$L_WIND > 0 we have a section index I/O. Get "real" IRP$L_WIND
       from PST.
26. Error return if CCB channel interlock bit set
27. IOPERFORM (not $IO_PERFORM) "start request" or just update I/O seqnum
28. Logical I/O privilege check and possible error return
29. Increment CCB$L_IOC
30. Increment PHD$L_{B,D}IOCNT, the accounting cell
31. Driver have fast FDT routine? Yes, so:
32. Increment global BUFIO or DIRIO PMS cell
33. Set a couple IRP flags for "FAST_FINISH" and "DID_FAST_FDT", for use
    in completion code
34. Call *DDT$PS_FAST_FDT(irp, pcb, ucb, ccb)
-------------------------------------------------------------------------------
   
       Part II: Fast-FDT routine ACP_STD$FASTIO_BLOCK for mounted disks/tapes
       Comment on code layout: {Disk, Tape} X {Virtual, Logical}

35. Set up pointer to first PTE for BufObj, and PTE offset into BufObj
36. Initialize IRP BOFF, BCNT, MEDIA from P1,P2,P3 in step 11
37. Zero ABCNT, OBCNT
38. If bytecount == 0, return success via FINISHIO
39. Calculate number of PTEs needed to map the buffer
40. Clear flags in the DIOBM in the IRP
41. If S2 window maps buffer and more than DIOBM$K_PTECNT_FIX PTEs needed,
    call FILL_DIOBM to make a usable buffer map
42. Else if S2 window and fewer than DIOBM$K_PTECNT_FIX PTEs needed,
    copy PTEs into DIOBM in IRP, point IRP$L_SVAPTE to first PTE
43. Else if S0 window, set up IRP$L_SVAPTE from PTE in BufObj
44. Test for disk vs. tape via DEV$M_SQD -- it's disk this time
45. ABORTIO if illegal modifier (not DATACHECK nor NOVCACHE)
46. ABORTIO if bytecount not multiple of 512 bytes
47. Get UCB MAXBCNT (if 0, get 0xFE00) and see if transfer needs to
    be segmented
48. Segmented transfer reduces BCNT appropriately and turns off the
    FAST_FINISH bit
49. See if this is a virtual I/O, which it is
50. ABORTIO if WCB == 0


									page 3

51. See if this is a write, which it is
52. ABORTIO if WCB denies write access
53. Set IO$M_DATACHECK if WCB requests datacheck writes
54. Bump WCB write counter
55. Set IRP$M_VIRTUAL in IRP$L_STS
56. Convert P1 from process VA to BufObj system VA
57. Check if VIOC enabled, which it is
    57.1 Save IRP$L_SVAPTE
    57.2 Call CACHE$QIO(irp, pcb, ucb, ccb), get returned status
    57.3 If good status, return SS$_FDT_COMPL -- VIOC hit
    57.4 If IRP$V_CACHEIO set, get CPT pointer from IRP$L_SVAPTE-CPT$L_PTE
    57.5 ... and set IRP$L_BCNT and IRP$L_MEDIA from CPT
    57.6 If IRP$V_CACHEIO clear, restore saved IRP$L_SVAPTE
58. Copy IRP$L_MEDIA and IRP$L_SVAPTE into IRP$L_SEGVBN and IRP$L_DIAGBUF
    in case of segmentation
59. No need to lock down buffers, which is what SYSACPFDT would do now
60. Initialize IRP$L_OBCNT from IRP$L_BCNT
61. Convert IRP$L_FUNC from virtual to physical I/O counterpart
62. Call IOC_STD$MAPVBLK
63. Get the "output" UCB pointer (which should be the same as the "input"
?   pointer since volume sets are not supported for Fast-IO. Oops, should
    check here for UCB change and ABORTIO if so).
64. Set IRP$L_BCNT to IRP$L_OBCNT-<count of bytes-not-mapped>
65. If some bytes not mapped, set IRP$V_FAST_FINISH = 0
66. If complete map failure, hairy code to do window turn and handle
    I/O past high-water mark (gee, I wonder if this has been tested)
67. ABORTIO if read past end of disk (N.B., Andy comments that the
    file system should instead verify the mapping pointers as it
    builds the WCB, so this check would not need to be made on every
    single I/O)
68. If write (it is) call IOC_STD$CHECK_HWM and return SS$_FDT_COMPL
    if bad status (meaning IRP already queued)
69. return call_qiodrvpkt(irp, ucb)
------------------------------------------------------------------------------
70. fetch status from FDT context area
71. lower IPL and return status



									page 4

       Part III: I/O completion
       In REQCOM and similar places after mount-verify and PMS END_IO checks:

72. If IRP$V_FAST_FINISH set, invoke FAST_FINISH macro:
    72.1 If IRP$V_COMPLX set, "never mind", back to slow finish
    72.2 System completion? No (See Glenn E. for the "Yes" side)
    72.3 Pick up CPU database via PAL call
    72.4 Make IRP into fork block with FLCK == 0 for no SCS spinlock
    72.5 Insert IRP onto IPL8 fork queue
    72.6 If IRP$V_HIFORK is set, request IPL8 interrupt (no need if at 8)
73. Rejoin mainline completion in REQCOM, usually to REMQUE the next IRP 
    from the UCB I/O queue
------------------------------------------------------------------------------
74. IPL 8 fork dispatcher removes IRP from fork queue
75. Sees bit 5 is clear so doesn't take out forklock
76. Calls SYSFIOMAC\EXE$FASTIO_FINISH
77. EXE$FASTIO_FINISH picks up UCB and PID from IRP
78. If negative PID (it's not) JSBs @PID and RSBs to fork dispatcher
79. Good PID, pick up PCB
80. Pick up CCB entry S0 address from IRP (CCB is locked down via BufObj)
81. Decrement UCB queue length (interlocked)
82. Decrement CCB I/O count and pick up CCB$L_DIRP using LDQL/STQC
    (This is tricky code but I believe I have it solid)
83. If deaccess packet, go off to queue it to ACP
84. If disk (not tape) write (not read) and cache on (but not cache I/O),
    call CACHE$IOPOST function #2
85. If cache I/O, call CACHE$IOPOST function #3 then CACHE$DIRPOST to copy
    data to user buffer (via BufObj SVA)
86. Store status and bytecount in IOSA, zeroing the reserved IOSA quadword
87. If buffered I/O (it's not) go off to do that part
88. If we used a DIOBM for this I/O, release it via IOC_STD$RELEASE_DIOBM
89. If any IRPEs (nope), go off and delete them
90. If PMS enabled, go off and do END_IO and END_RQ. (Oops, END_IO already
?   done in REQCOM.)
91. If AST was requested, call SCH$QAST to queue AST
92. If no AST, "set" EFN "ENF" and IRP status bit IRP$M_FASTIO_DONE
93. RSB to fork dispatcher
------------------------------------------------------------------------------
94. In ASTDEL\PROCESS_AST, where the ACB (i.e., the IRP) is to be deleted 
    we check ACB$V_NODELETE (it's set)
95. In which case we see if the ACB is really a Fast-IO IRP via bit
    ACB$V_FASTIO in ACB$L_FLAGS
96. In which case we set IRP status bit IRP$M_FASTIO_DONE and go off to
    deliver the AST to the user (never a special Kernel AST in Fast-IO)




    Fandle Vector Entry (FVE) from [LIB]FVEDEF.SDL:


                         +================+ 
                         | Pointer to IRP |     IRPPTR
                         +----------------+ 
                         | Original func  |     ORGFUNC
                         +----------------+ 
                         |DB-Bufobj handle|     Data buffer
                         +----------------+     object handle
                         |DB-Bufobj handle|
                         +----------------+ 
                         |IO-Bufobj handle|     IOSA buffer
                         +----------------+     object handle
                         |IO-Bufobj handle|
                         +----------------+
                         | Quadword data  |
                         +                +
                         | BufObj length  |
                         +================+ 
