%TITLE 'IOGEN-CONNECT, create and connect the I/O database for a device' MODULE iogen$connect (IDENT = 'X-11', ENVIRONMENT(NOFP)) = BEGIN ! ! Copyright © Digital Equipment Corporation, 1990, 1992 All Rights Reserved. ! Unpublished rights reserved under the copyright laws of the United States. ! ! The software contained on this media is proprietary to and embodies the ! confidential technology of Digital Equipment Corporation. Possession, use, ! duplication or dissemination of the software and media is authorized only ! pursuant to a valid written license from Digital Equipment Corporation. ! ! RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure by the U.S. ! Government is subject to restrictions as set forth in Subparagraph ! (c)(1)(ii) of DFARS 252.227-7013, or in FAR 52.227-19, as applicable. ! !++ ! COMPONENT: ! ! IOGEN ! ! MODULE DESCRIPTION: ! ! This module contains the routines that create and connect the I/O ! database structures for a given device ! ! AUTHOR: ! ! Richard W. Critz, Jr. ! ! CREATION DATE: 5-Nov-1990 ! ! MODIFICATION HISTORY: ! ! X-11 TGA Thomas G. Arnold 18-Jun-1996 ! Fix for EVMS-GRYPHON QAR 355: move invocation of ! iogen$init_db() into iogen$connect(). This closes a hole ! whereby $ASSIGN can come in between the two routines ! and cause a system crash when $ASSIGN finds that the UCB field ! UCB$L_DDT is zero. ! Also fix error handling in iog$connect() where failure of ! CRAM allocation would not properly release the IO lock or ! lower IPL. Although if you can't allocate a CRAM, your ! system is probably in deep sneakers already, we shouldn't ! just hang or crash with a spin lock timeout. ! ! X-10 JCH710a John C. Hallyburton, Jr. 4-Dec-1995 ! Happy birthday Carol Gillette. Extend X-9 to not meddle with ! the controller letter for port allocation classes for ports, ! (PKx, etc.) but not classes (DKx, MKx). ! ! X-9 JCH710 John C. Hallyburton, Jr. 17-Oct-1995 ! Naming: edit create_ddb to handle port allocation classes. ! DOCD$:[EVMS.PROJECT_DOCUMENTS]FS-SCSI-NAMING.PS ! ! While we're in the area, fix EVMS-GHOST QAR 21, a fencepost ! error in X-8. ! ! X-8 RWC135 Richard W. Critz, Jr. 21-Dec-1993 ! Add support for creating an MCJ in CREATE_IDB. ! ! X-7 RWC134 Richard W. Critz, Jr. 13-Sep-1993 ! Change references to IOC$LINK_UCB and IOC$SEVER_UCB to be the ! new standard calls, especially since IOC$LINK_UCB no longer ! exists. ! ! X-6 BAP079 Bridget Powers 24-Sep-1992 ! Changed reference to EXE$DEANONPAGED_LINKAGE to ! EXE$DEANONPAGED_LINKAGE_2 for consistancy with changes ! to IOGEN-MACROS.REQ ! ! X-5 RWC092 Richard W. Critz, Jr. 8-Jul-1992 ! Add support for the IOGEN$_NODE item code. Basically, this is ! simply user supplied data that is copied to CRB$L_NODE if that ! field is currently zero. This allows an easy way to provide bus ! node number information to device drivers. This was ! precipitated by the need to implement support for the ! TurboChannel Interrupt Mask Register (TC IMR) for Flamingo. ! !===============Masterpack reorganized between these edits================= ! ! X-8 RWC052 Richard W. Critz, Jr. 20-Nov-1991 ! Fill in UCB$PS_ADP (I still don't know why we added this ! unnecessary field) in CREATE_UCB. ! ! X-7 RWC050 Richard W. Critz, Jr. 11-Nov-1991 ! Do better checking of MAXUNITS. Note that LDDB$L_MAXUNITS is ! set to 0 when DPT$V_NO_IDB_DISPATCH is set. If IDB$V_NORESIZE ! is set and no UCBLST is included with the IDB, use the ! previously calculated MAXUNITS. Otherwise, use the size of the ! UCBLST as maxunits. ! ! X-6 RWC044 Richard W. Critz, Jr. 28-Oct-1991 ! BL4 completion: ! ! 1) Add support for the the NORESIZE flag in the IDB. ! 2) Correct allocation of CRAMs to the IDB. ! 3) Don't allocate a VLE if one already exists. ! 4) Set UNINIT flag in the CRB when it is created. ! ! X-5 RWC041 Richard W. Critz, Jr. 21-Aug-1991 ! Change IDBE references to VLE. ! ! X-4 RWC036 Richard W. Critz, Jr. 25-Apr-1991 ! 1) Properly initialize status so that an attempt to add a unit ! doesn't fail prematurely. ! ! 2) Use the PCB and not the PHD to lock and unlock MUTEXes. ! ! X-3 RWC034 Richard W. Critz, Jr. 17-Apr-1991 ! BL1 completion: ! ! 1) Do CRAM allocation in CREATE_IDB, CHECK_IDB and CREATE_UCB. ! 2) Do CRAM and IDBE deallocation in CLEANUP_DB. ! 3) Update vector connect processing to match new interface. ! 4) Add CREATE_IDBE. ! ! X-1K3 RWC019 Richard W. Critz, Jr. 11-Jan-1991 ! Change field names to coordinate reorganization of LDDB. ! ! X-1K2 RWC018 Richard W. Critz, Jr. 18-Dec-1990 ! Correct source of name copied into the DDB. ! ! X-1K1 RWC003 Richard W. Critz, Jr. 5-Nov-1990 ! Original. !-- ! ! TABLE OF CONTENTS: ! FORWARD ROUTINE iogen$connect, create_ddb, create_crb, create_idb, check_idb, create_vle, create_ucb, cleanup_db : NOVALUE; ! ! INCLUDE FILES: ! LIBRARY 'sys$library:lib'; REQUIRE 'src$:iogen-macros'; ! ! MACROS: ! ! ! EQUATED SYMBOLS: ! LITERAL bytes_per_addr = 4; ! This only holds for EVMS Phase I... ! ! OWN STORAGE: ! ! ! EXTERNAL REFERENCES: ! EXTERNAL clu$gl_allocls : SIGNED LONG, clu$gl_tape_allocls : SIGNED LONG, ctl$gl_pcb : SIGNED LONG, exe$gl_affinity : SIGNED LONG, mmg$gl_sptbase : SIGNED LONG; EXTERNAL ROUTINE iogen$allocate_block, iogen$class_match : NOVALUE, iogen$set_spte : NOVALUE, ioc$allocate_cram, ioc$deallocate_cram, exe$deanonpaged : exe$deanonpaged_linkage_2, smp$alloc_spl : smp$alloc_spl_linkage, ioc_std$link_ucb, ioc_std$sever_ucb, sch$iolockw : sch$iolock_linkage, sch$iounlock : sch$iounlock_linkage, ldr$alloc_pt : ldr$alloc_pt_linkage, iogen$init_db; %SBTTL 'IOGEN$CONNECT, create and connect the I/O database for a device' GLOBAL ROUTINE iogen$connect (lddb : REF BLOCK[,BYTE]) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine creates and connects the appropriate I/O database structures ! to make the specified device available to the system as a whole. ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! None ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! * TBS * ! ! SIDE EFFECTS: ! ! None !-- BEGIN LOCAL status : INITIAL(ss$_normal); IF .lddb[lddb$ps_ucb] NEQA 0 ! see if the device already exists THEN RETURN ss$_devexists; %IF NOT %VARIANT %THEN sch$iolockw(.ctl$gl_pcb); %FI IF .lddb[lddb$ps_ddb] EQLA 0 ! first, do the DDB THEN status = create_ddb(.lddb); IF .status AND .lddb[lddb$ps_crb] EQLA 0 ! next do the CRB THEN status = create_crb(.lddb); IF .status THEN BEGIN LOCAL crb : REF BLOCK[,BYTE]; crb = .lddb[lddb$ps_crb]; ! fill in CRB$L_NODE IF .crb[crb$l_node] EQL 0 ! if that's appropriate THEN crb[crb$l_node] = .lddb[lddb$l_node]; END; IF .status ! next comes the IDB THEN IF .lddb[lddb$ps_idb] EQLA 0 ! create if none exists THEN status = create_idb(.lddb) ELSE ! check the UCBLST size and reallocte status = check_idb(.lddb); ! if necessary for an existing one IF .status THEN BEGIN BIND idb = lddb[lddb$ps_idb] : REF BLOCK[,BYTE], dpt = lddb[lddb$ps_dpt] : REF BLOCK[,BYTE], vector = lddb[lddb$l_vector] : LONG; IF NOT .idb[idb$v_cram_alloc] ! if we haven't done this already THEN INCR i FROM 1 TO .dpt[dpt$iw_idb_crams] BY 1 DO BEGIN LOCAL cram : REF BLOCK[,BYTE]; IF NOT (status = ioc$allocate_cram(cram, .idb)) THEN BEGIN %IF NOT %VARIANT %THEN sch$iounlock(.ctl$gl_pcb); $setipl(newipl = 0); %FI RETURN .status; END; cram[cram$l_flink] = .idb[idb$ps_cram]; idb[idb$ps_cram] = .cram; ! link into list off of IDB END; idb[idb$v_cram_alloc] = true; ! indicate that CRAM processing is done IF .lddb[lddb$l_numvec] EQL 1 ! if only one vector THEN ! save it in IDB$L_VECTOR idb[idb$l_vector] = .vector ELSE ! otherwise, create and initialize status = create_vle(.lddb) ! a VLE. END; IF .status ! finally the UCB which we THEN ! already know doesn't exist status = create_ucb(.lddb); IF NOT .status ! if something failed then cleanup THEN ! all that this pass allocated cleanup_db(.lddb) ELSE status = iogen$init_db(.lddb, false); ! False indicates this is not a RELOAD %IF NOT %VARIANT %THEN sch$iounlock(.ctl$gl_pcb); $setipl(newipl = 0); %FI RETURN .status END; %SBTTL 'CREATE_DDB, create and initialize a DDB' ROUTINE create_ddb (lddb : REF BLOCK[,BYTE]) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine allocates a DDB, links it into the I/O database and ! initializes various fields within it. ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! None ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! value from IOGEN$ALLOCATE_BLOCK ! SS$_NORMAL ! ! SIDE EFFECTS: ! ! None ! ! PRECONDITIONS: ! ! The caller must have the I/O database mutex locked for write. !-- BEGIN EXTERNAL ROUTINE INI$BRK: NOVALUE; BIND ddb = lddb[lddb$ps_ddb] : REF BLOCK[,BYTE], dpt = lddb[lddb$ps_dpt] : REF BLOCK[,BYTE]; LOCAL prev_ddb : REF BLOCK[,BYTE] INITIAL(.lddb[lddb$ps_lastddb]), nopac; LOCAL status; IF NOT (status = iogen$allocate_block(ddb$k_length, ddb)) THEN RETURN .status; nopac = false; lddb[lddb$v_ddb] = true; ! indicate that a DDB was created ddb[ddb$b_type] = dyn$c_ddb; ! Link DDB off of SB and ddb[ddb$ps_link] = .prev_ddb[ddb$ps_link]; ! be sure that we don't lose prev_ddb[ddb$ps_link] = .ddb; ! any DDBs in the chain ! By initing the port_id cell to zero we ensure that anything finding ! a nonzero value here can use it. That means dkdriver can be altered ! to use it. (ditto mkdriver etc.) ddb[ddb$l_port_id] = 0; ! Initialize this cell 0 ddb[ddb$ps_dpt] = .dpt; ! Link to DPT and bump the ddb[ddb$ps_drvlink] = .dpt[dpt$ps_ddb_list];! DPT reference count dpt[dpt$ps_ddb_list] = .ddb; dpt[dpt$il_refc] = .dpt[dpt$il_refc] + 1; ddb[ddb$ps_sb] = .lddb[lddb$ps_sb]; ! Link to the appropriate SB ddb[ddb$il_allocls] = (IF .dpt[dpt$v_tpalloc]! Set the allocation class THEN .clu$gl_tape_allocls ELSE .clu$gl_allocls); ! See also end of routine ddb[ddb$ib_name_len] = .lddb[lddb$il_ddb_namelen]; CH$MOVE(.lddb[lddb$il_ddb_namelen], .lddb[lddb$ps_ddb_name], ddb[ddb$t_name_str]); ! If the lddb has an alloclass, it may be from the controller. ! If so set the DDB alloclass here. then zero the lddb alloclass IF NOT .lddb[lddb$v_pac] THEN ! Port allocation class specified? BEGIN ! No, see if implied by exact match in tables. IF .lddb[lddb$l_allocls] GEQ 0 THEN BEGIN ddb[ddb$il_allocls] = .lddb[lddb$l_allocls]; ! Flag that the allocation class was > 0 and NOT a PAC nopac = true; ! Some alloc class data exists lddb[lddb$v_pac] = 0; END; END; ! Fix up the allocation class and controller letter. An allocation class can ! either be supplied explicitly (usually for class drivers) or implicitly ! (usually for port drivers). Explicit classes are supplied to $LOAD_DRIVER, ! implicit classes are found right here. IF NOT .lddb[lddb$v_pac] THEN ! Port allocation class specified? BEGIN ! No, see if implied by exact match in tables. iogen$class_match(ddb[ddb$t_name_str], lddb[lddb$l_allocls]); IF .lddb[lddb$l_allocls] GEQ 0 THEN lddb[lddb$v_pac] = 1; END; IF ((.lddb[lddb$v_pac]) OR .nopac) THEN ! Port allocation class specified? BEGIN if ((NOT .nopac) AND 1) THEN BEGIN ddb[ddb$v_pac] = 1; ddb[ddb$l_allocls] = .lddb[lddb$l_allocls]; END; ! For port DDBs (i.e., adapter supplied) \don't/ twiddle the controller letter. ! Keeping the original port controller letter simplifies things later on. ! However if an alloc class must be set due to device allo class (HSZ) ! we want to fold controller letters to A. That guarantees they'll all be ! named the same regardless of path. IF .lddb[lddb$v_noadap] THEN BEGIN MACRO ctrltr = 2+$byteoffset(ddb$t_name_str), 0, 8, 0%; ddb[ddb$l_port_id] = .ddb[ctrltr]; IF .ddb[ddb$l_allocls] GTR 0 THEN ! Nonzero allocation class? ddb[ctrltr] = %C'A' END END; RETURN ss$_normal END; %SBTTL 'CREATE_CRB, create and initialize a CRB' ROUTINE create_crb (lddb : REF BLOCK[,BYTE]) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine allocates and initializes a CRB. The only pointer to this ! new CRB, upon completion of this routine, exists in the LDDB. ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! None ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! status from IOGEN$ALLOCATE_BLOCK or SMP$ALLOC_SPL ! ! SIDE EFFECTS: ! ! A dynamic spinlock (the devicelock) is allocated to the CRB ! ! PRECONDITIONS: ! ! The caller must have the I/O database mutex locked for write. !-- BEGIN BIND crb = lddb[lddb$ps_crb] : REF BLOCK[,BYTE]; LOCAL status, crb_size; crb_size = crb$k_length + ((.lddb[lddb$l_numvec] - 1) * vec$k_length); IF NOT (status = iogen$allocate_block(.crb_size, crb)) THEN RETURN .status; lddb[lddb$v_crb] = true; ! indicate that a CRB was created crb[crb$b_type] = dyn$c_crb; ! Initialize the CRB's Wait Queue header. Note that this is an ! absolute queue so the flink and blink must point to the queue header. crb[crb$l_wqfl] = crb[crb$l_wqbl] = crb[crb$l_wqfl]; crb[crb$v_uninit] = true; ! Allocate a spinlock for the controller. status = smp$alloc_spl(; crb[crb$ps_dlck]); RETURN .status END; %SBTTL 'CREATE_IDB, create and initialize an IDB' ROUTINE create_idb (lddb : REF BLOCK[,BYTE]) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine creates and initializes an IDB. It completes each INTD ! field in the associated CRB. ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! Assumes that LDDB$L_MAXUNITS contains the desired value and has been ! defaulted from the equivalent field in the DPT, if necessary. ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! status from IOGEN$ALLOCATE_BLOCK ! SS$_NORMAL ! ! SIDE EFFECTS: ! ! None ! ! PRECONDITIONS: ! ! The caller must have the I/O database mutex locked for write. !-- BEGIN BIND crb = lddb[lddb$ps_crb] : REF BLOCK[,BYTE], idb = lddb[lddb$ps_idb] : REF BLOCK[,BYTE], dpt = lddb[lddb$ps_dpt] : REF BLOCK[,BYTE]; LOCAL status, idb_size : INITIAL(idb$k_base_length), vec : REF BLOCK[,BYTE] INITIAL(crb[crb$l_intd]); IF NOT .dpt[dpt$v_no_idb_dispatch] THEN idb_size = .idb_size + (.lddb[lddb$l_maxunits] * bytes_per_addr) ELSE lddb[lddb$l_maxunits] = 0; ! update for later assignment IF NOT (status = iogen$allocate_block(.idb_size, idb)) THEN RETURN .status; lddb[lddb$v_idb] = true; ! indicate that an IDB was created idb[idb$b_type] = dyn$c_idb; idb[idb$w_units] = .lddb[lddb$l_maxunits]; ! save length of UCBLST idb[idb$ps_spl] = .crb[crb$ps_dlck]; ! set devicelock address IF .dpt[dpt$il_adptype] EQL at$_null THEN BEGIN vec[vec$ps_adp] = idb[idb$ps_adp] = 0; ! no ADP for null adapter vec[vec$l_idb] = .idb ! set IDB address in CRB's INTD END ELSE BEGIN idb[idb$ps_adp] = .lddb[lddb$ps_adp]; ! set ADP in IDB INCR i FROM 1 TO .lddb[lddb$l_numvec] BY 1 DO BEGIN vec[vec$ps_adp] = .lddb[lddb$ps_adp]; vec[vec$l_idb] = .idb; vec = .vec + vec$k_length END END; IF .lddb[lddb$v_remote] OR ! if device is remote or (.dpt[dpt$il_adptype] EQL at$_null AND ! it's a local psedo-device .dpt[dpt$v_scs]) ! that requires SCS THEN ! then use SYSID as the CSR CH$MOVE(idb$s_csr, lddb[lddb$q_sysid], idb[idb$q_csr]) ELSE ! else use the specified CSR CH$MOVE(idb$s_csr, lddb[lddb$q_csr], idb[idb$q_csr]); IF .lddb[lddb$il_iohandles] GTR 1 ! X-9 THEN BEGIN LOCAL mcj_size, mcj : REF BLOCK[,BYTE]; ! ! IOHANDLEs are 64 bit magic numbers. Allocate 8 bytes per plus room ! for the header. ! mcj_size = mcj$k_header_len + 8 * .lddb[lddb$il_iohandles]; IF NOT (status = iogen$allocate_block(.mcj_size, mcj)) THEN RETURN .status; ! ! Initialize the MCJ. ! mcj[mcj$ps_idb] = .idb; mcj[mcj$l_crumb_count] = .lddb[lddb$il_iohandles]; mcj[mcj$b_type] = dyn$c_misc; mcj[mcj$b_subtype] = dyn$c_mcj; ! ! Connect MCJ to IDB. ! idb[$byteoffset(idb$q_csr),0,32,0] = .mcj; IF .mcj LEQA 0 ! sign extend the low longword THEN idb[$byteoffset(idb$q_csr),32,32,0] = -1; idb[idb$v_mcj] = true; END; RETURN ss$_normal END; %SBTTL 'CHECK_IDB, verify that UCBLST is large enough' ROUTINE check_idb (lddb : REF BLOCK[,BYTE]) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine insures that the UCBLST field in an existing IDB is large ! enough to support the maximum number of units for this controller. ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! None ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! status from IOGEN$ALLOCATE_BLOCK ! SS$_NORMAL ! ! SIDE EFFECTS: ! ! If the existing IDB is not large enough, it will be deallocated. This ! will cause any user's cached IDB address to be invalidated. ! ! PRECONDITIONS: ! ! The caller must have the I/O database mutex locked for write. !-- BEGIN BIND crb = lddb[lddb$ps_crb] : REF BLOCK[,BYTE], idb = lddb[lddb$ps_idb] : REF BLOCK[,BYTE], dpt = lddb[lddb$ps_dpt] : REF BLOCK[,BYTE]; LOCAL status, idb_size, old_idb : REF BLOCK[,BYTE] INITIAL(.idb), vec : REF BLOCK[,BYTE] INITIAL(crb[crb$l_intd]); ! If the IDB is large enough, do nothing. IF .idb[idb$v_noresize] AND .idb[idb$w_units] NEQ 0 THEN lddb[lddb$l_maxunits] = .idb[idb$w_units]; IF .dpt[dpt$v_no_idb_dispatch] THEN lddb[lddb$l_maxunits] = 0; IF .lddb[lddb$l_maxunits] LEQU .idb[idb$w_units] OR .idb[idb$v_noresize] ! hack for permanent_device_database bugs THEN RETURN ss$_normal; ! Otherwise, calculate the correct size and allocate a new one. idb_size = idb$k_base_length + (.lddb[lddb$l_maxunits] * bytes_per_addr); IF NOT (status = iogen$allocate_block(.idb_size, idb)) THEN RETURN .status; ! Copy the contents of the old IDB into the new one and reset the ! fields that should be different. The deallocate the old one. CH$MOVE(.old_idb[idb$w_size], .old_idb, .idb); idb[idb$w_size] = .idb_size; idb[idb$w_units] = .lddb[lddb$l_maxunits]; exe$deanonpaged(.old_idb); ! Now update the INTD fields in the CRB to point to the new IDB. INCR i FROM 1 TO .lddb[lddb$l_numvec] BY 1 DO BEGIN vec[vec$l_idb] = .idb; vec = .vec + vec$k_length END; RETURN ss$_normal END; %SBTTL 'CREATE_VLE, allocate and initialize a VLE' ROUTINE create_vle (lddb : REF BLOCK[,BYTE]) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine allocates and initializes a VLE. Once it is successfully ! created and the vector list has been copied into it, it is hung from the ! IDB. ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! None ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! status from IOGEN$ALLOCATE_BLOCK ! SS$_NORMAL ! ! SIDE EFFECTS: ! ! None ! !-- BEGIN BIND idb = lddb[lddb$ps_idb] : REF BLOCK[,BYTE], vectors = lddb[lddb$l_vector] : VECTOR[,LONG]; ! UNSIGNED LOCAL vle : REF BLOCK[,BYTE], vle_size, status; IF .idb[idb$v_vle] THEN RETURN ss$_normal; ! if a VLE already exists, do no more vle_size = vle$k_length + (.lddb[lddb$l_numvec] * 4); IF NOT (status = iogen$allocate_block(.vle_size, vle)) THEN RETURN .status; ! VLE was successfully allocated. Now, fill it in. vle[vle$ps_idb] = .idb; vle[vle$l_numvec] = .lddb[lddb$l_numvec]; vle[vle$b_type] = dyn$c_misc; vle[vle$b_subtype] = dyn$c_vle; INCR i FROM 0 TO .lddb[lddb$l_numvec] - 1 BY 1 DO BEGIN BIND vector_list = vle[vle$l_vector_list] : VECTOR[,LONG]; ! UNSIGNED vector_list[.i] = .vectors[.i] END; ! VLE is now complete. Connect it to the IDB. idb[idb$l_vector] = .vle; idb[idb$v_vle] = true; RETURN ss$_normal END; %SBTTL 'CREATE_UCB, allocate and initialize a UCB' ROUTINE create_ucb (lddb : REF BLOCK[,BYTE]) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine creates and initializes a UCB and its associated ORB. It ! connects the UCB into the I/O database and will allocate a SPTE to the ! unit if the driver writer so requested. ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! None ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! status from IOGEN$ALLOCATE_BLOCK or LDR$ALLOC_PT ! SS$_DEVEXISTS ! SS$_NORMAL ! ! SIDE EFFECTS: ! ! None ! ! PRECONDITIONS: ! ! The caller must have the I/O database mutex locked for write. !-- BEGIN BIND dpt = lddb[lddb$ps_dpt] : REF BLOCK[,BYTE], ddb = lddb[lddb$ps_ddb] : REF BLOCK[,BYTE], crb = lddb[lddb$ps_crb] : REF BLOCK[,BYTE], ucb = lddb[lddb$ps_ucb] : REF BLOCK[,BYTE]; LOCAL status, orb : REF BLOCK[,BYTE], spte : REF VECTOR[,LONG]; IF .lddb[lddb$l_unit] GEQU .lddb[lddb$l_maxunits] AND .lddb[lddb$l_maxunits] NEQ 0 THEN RETURN ss$_ivdevnam; IF NOT (status = iogen$allocate_block(.dpt[dpt$iw_ucbsize], ucb)) THEN RETURN .status; lddb[lddb$v_ucb] = true; ! indicate that a UCB was allocated ! Set structure type, unit number and default device affinity. ucb[ucb$b_type] = dyn$c_ucb; ucb[ucb$w_unit] = .lddb[lddb$l_unit]; ucb[ucb$l_affinity] = .exe$gl_affinity; ! Initialize absolute queue headers. ucb[ucb$l_astqfl] = ucb[ucb$l_astqbl] = ucb[ucb$l_astqfl]; ucb[ucb$l_ioqfl] = ucb[ucb$l_ioqbl] = ucb[ucb$l_ioqfl]; ! Connect up devicelock, CRB and DDB. ucb[ucb$l_dlck] = .crb[crb$ps_dlck]; ucb[ucb$l_crb] = .crb; ucb[ucb$l_ddb] = .ddb; ucb[ucb$ps_adp] = .lddb[lddb$ps_adp]; ! Allocate an ORB and connect it to the UCB. IF NOT (status = iogen$allocate_block(orb$k_length, orb)) THEN RETURN .status ELSE ucb[ucb$l_orb] = .orb; ! Initialize the ORB. orb[orb$b_type] = dyn$c_orb; orb[orb$l_acl_mutex] = %X'0000FFFF'; ! equivalent to MOVZWL #-1,... orb[orb$b_flags] = orb$m_prot_16; orb[orb$l_acl_count] = orb[orb$l_acl_desc] = 0; ! Now link UCB onto DDB. If link fails, it's because somehow the UCB ! now exists so change the status to SS$_DEVEXISTS. IF NOT ioc_std$link_ucb(.ucb) THEN RETURN ss$_devexists; ! If the driver requests preallocation of per-unit CRAMs, do that now. INCR i FROM 1 TO .dpt[dpt$iw_ucb_crams] BY 1 DO BEGIN LOCAL cram : REF BLOCK[,BYTE]; IF NOT (status = ioc$allocate_cram(cram, .lddb[lddb$ps_idb], .ucb)) THEN RETURN .status; cram[cram$l_flink] = .ucb[ucb$ps_cram]; ucb[ucb$ps_cram] = .cram END; ! If the driver does not need a SPTE, we're done. Otherwise, allocate ! and initialize one. IF NOT .dpt[dpt$v_svp] THEN RETURN ss$_normal; IF NOT (status = ldr$alloc_pt(1; spte)) THEN RETURN .status; iogen$set_spte(.spte); ucb[ucb$l_svpn] = (.spte - .mmg$gl_sptbase) / pte$c_bytes_per_pte; RETURN ss$_normal END; %SBTTL 'CLEANUP_DB, disconnect and deallocate I/O database structures' ROUTINE cleanup_db (lddb : REF BLOCK[,BYTE]) : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine deallocates any structures that we allocated during this ! call to $LOAD_DRIVER (based upon the flags in the LDDB). ! ! FORMAL PARAMETERS: ! ! lddb - the address of the LDDB ! ! IMPLICIT INPUT PARAMETERS: ! ! None ! ! IMPLICIT OUTPUT PARAMETERS: ! ! None ! ! RETURN VALUE: ! ! None ! ! SIDE EFFECTS: ! ! None ! ! PRECONDITIONS: ! ! The caller must have the I/O database mutex locked for write. !-- BEGIN BIND sb = lddb[lddb$ps_sb] : REF BLOCK[,BYTE], dpt = lddb[lddb$ps_dpt] : REF BLOCK[,BYTE], ddb = lddb[lddb$ps_ddb] : REF BLOCK[,BYTE], crb = lddb[lddb$ps_crb] : REF BLOCK[,BYTE], idb = lddb[lddb$ps_idb] : REF BLOCK[,BYTE], ucb = lddb[lddb$ps_ucb] : REF BLOCK[,BYTE]; IF .lddb[lddb$v_ucb] ! if we allocated a UCB THEN BEGIN LOCAL cram : REF BLOCK[,BYTE]; ioc_std$sever_ucb(.ucb); ! remove it from the chain WHILE (cram = .ucb[ucb$ps_cram]) NEQA 0 DO ! nuke any CRAMs allocated BEGIN ucb[ucb$ps_cram] = .cram[cram$l_flink]; ioc$deallocate_cram(.cram) END; IF .ucb[ucb$l_orb] NEQA 0 ! if we allocated an ORB THEN exe$deanonpaged(.ucb[ucb$l_orb]); ! get rid of it exe$deanonpaged(.ucb) ! deallocate the UCB END; IF .lddb[lddb$v_idb] ! if we allocated an IDB THEN BEGIN LOCAL cram : REF BLOCK[,BYTE]; WHILE (cram = .idb[idb$ps_cram]) NEQA 0 DO ! nuke any CRAMs allocated BEGIN idb[idb$ps_cram] = .cram[cram$l_flink]; ioc$deallocate_cram(.cram) END; IF .idb[idb$v_vle] ! if we allocated a VLE, lose it THEN exe$deanonpaged(.idb[idb$l_vector]); IF .idb[idb$v_mcj] ! if we allocate an MCJ, break it THEN exe$deanonpaged(.idb[$byteoffset(idb$q_csr),0,32,1]); exe$deanonpaged(.idb) ! deallocate the IDB END; IF .lddb[lddb$v_crb] ! if we allocated a CRB THEN BEGIN IF .crb[crb$ps_dlck] NEQA 0 ! if we got a spinlock THEN exe$deanonpaged(.crb[crb$ps_dlck]); ! get rid of it exe$deanonpaged(.crb) ! deallocate the CRB END; IF .lddb[lddb$v_ddb] ! if we allocated a DDB THEN BEGIN LOCAL prev_ddb : REF BLOCK[,BYTE]; ! Break the DDB out of the list from the SB. Special case its ! presence at the head of the list. IF (prev_ddb = .sb[sb$l_ddb]) EQLA .ddb THEN sb[sb$l_ddb] = .ddb[ddb$ps_link] ELSE BEGIN ! Note that, unless CREATE_DDB made a grevious error, ! prev_ddb[ddb$ps_link] cannot equal 0 during this search ! and this search WILL eventually succeed. WHILE .prev_ddb[ddb$ps_link] NEQA .ddb DO prev_ddb = .prev_ddb[ddb$ps_link]; prev_ddb[ddb$ps_link] = .ddb[ddb$ps_link] END; ! Now do the same thing for the list from the DPT. IF (prev_ddb = .dpt[dpt$ps_ddb_list]) EQLA .ddb THEN dpt[dpt$ps_ddb_list] = .ddb[ddb$ps_drvlink] ELSE BEGIN WHILE .prev_ddb[ddb$ps_drvlink] NEQA .ddb DO ! same comment as above prev_ddb = .prev_ddb[ddb$ps_drvlink]; prev_ddb[ddb$ps_drvlink] = .ddb[ddb$ps_drvlink] END; ! Now decrement the DPT reference count and deallocate the DDB. dpt[dpt$il_refc] = .dpt[dpt$il_refc] - 1; exe$deanonpaged(.ddb) END END; END ! End of module ELUDOM