/************************************************************************/ /************************************************************************/ /* genc4.c - This module exports the following routines: /* /* initxios_info(xf,goff) 'xf' is XIOSMOD file descriptor, 'goff' /* is offset of data group in XIOSMOD (including header); /* this module inits the buffering info questions. /* doxbufs(txt,title) 'txt' is a command, 'title' is the prompt for this fn; /* this routine is called within the MENU module, and prompts user /* for xios info. /* xiosvalid() returns a BOOLEAN value indicating whether the xios info /* is valid. /* genxios(doffset) generates the buffers for the xios, starting at 'doffset' /* in the system data area. /* fixupxios_info() writes DPH fixups required by genxios /**************************************************************************/ /**************************************************************************/ #ifndef MAINMODULE #include #endif /**************************************************************************/ /* edsdisk.h : defines the data structures used in this module /**************************************************************************/ #define ADDR UWORD /* Address (offset) within SysDat */ #define SEG UWORD /* Segment address (may be outside SysDat) */ #define DPH struct dph_item DPH { /* Disk Parameter Header structure */ ADDR dph_xlt; /* Translation Table Address */ BYTE dph_space[6]; /* reserved & Media Flag */ ADDR dph_dpb; /* Disk Parameter Block Address */ ADDR dph_csv; /* CheckSum Vector Address */ ADDR dph_alv; /* Allocation Vector Address */ ADDR dph_dirbcb; /* Dir Buffer Control Block Header Address */ ADDR dph_datbcb; /* Data Buffer Control Block Header Address */ SEG dph_hstbl; /* Hash Table Segment */ }; #define EDPB struct edbp_item EDPB { /* Extended Disk Parameter Block entries */ WORD edpb_extflag; /* Extended DPB flag */ WORD edpb_nfats; /* Number of FATS */ WORD edpb_nfatrecs; /* Number of records per FAT */ WORD edpb_nclstrs; /* Number of clusters */ WORD edpb_clsize; /* Cluster size */ WORD edpb_fatadd; /* FAT address */ }; #define DPB struct dpb_item DPB { /* Disk Parameter Block structure */ WORD dpb_spt; /* Sectors Per Track */ BYTE dpb_bsh; /* Allocation Block Shift Factor */ BYTE dpb_blm; /* Allocation Block Mask */ BYTE dpb_exm; /* Extent Mask */ WORD dpb_dsm; /* Disk Storage Maximum */ WORD dpb_drm; /* Directory Maximum */ WORD dpb_dav; /* Directory Allocation Vector */ WORD dpb_cks; /* Checksum Vector Size */ WORD dpb_off; /* Track Offset */ WORD dpb_psh; /* Physical Record Shift Factor */ WORD dpb_phm; /* Physical Record Mask */ }; #define BCBH struct bcbh_item BCBH { /* Buffer Control Block Header structure */ ADDR bcbh_lr; /* BCB List Root */ BYTE bcbh_pm; /* BCB Process Max */ }; #define BCB struct bcb_item BCB { /* Buffer Control Block structure */ BYTE bcb_drv; /* Drive */ BYTE bcb_record[3]; /* Record Number */ BYTE bcb_wflg; /* Write Pending Flag */ BYTE bcb_seq; /* Sequential Access Counter */ WORD bcb_track; /* Logical Track Number */ WORD bcb_sector; /* Logical Translated Sector Number */ UWORD bcb_bufptr; /* Buffer Offset (for DIRBCB) / Segment (for DATBCB) */ ADDR bcb_link; /* Link to next BCB */ WORD bcb_pdadr; /* Process Descriptor Address */ }; #define DINFO struct dirbuf_information DINFO { BOOLEAN d_modified; /* DPH was modified? */ BOOLEAN d_hashing; /* user wants hashing? */ WORD d_ndirbs; /* Num dir buffers */ WORD d_sdirbs; /* Size dir buffers */ WORD d_pmdirbs; /* Process Max Number Dir Buffs */ WORD d_ndatbs; /* Num data buffers */ WORD d_sdatbs; /* Size data buffers */ WORD d_pmdatbs; /* Process Max Number Dir Buffs */ WORD d_shash; /* Size of hash table */ WORD d_alvsize; /* size of Alloc Vector area (in bytes ) */ WORD d_blksize; /* size of disk Allocation Block */ WORD d_csvsize; /* size of Checksum Vector area */ }; /* end of edsdisk.h ********************************************************/ /***************************************************************************/ WORD csfd; /* command file descriptor */ WORD csgoff; /* group offset within command file */ cseek(offs) /* seek offset within Command File */ ADDR offs; { lseek(csfd,(LONG) offs+csgoff, 0); /* compensate for cmd header */ } /***************************************************************************/ /* Put special byte for buffer fills */ #define ZBYTE (doffset&0xFF) /* the byte usually passed in */ WORD bufwrite(size,byt) WORD size; BYTE byt; { WORD ss; for( ss=size; ss>0; --ss ) write(fns,&byt,1); return size; } /***************************************************************************/ /* Module local variables */ #define DPHNUM 16 /* number of possible disks */ ADDR *dphtab; /* table of offsets of Disk Parm Hdrs */ DPH *dh[DPHNUM]; /* table of Disk Parm Hdrs */ DINFO *di[DPHNUM]; /* table of info on DPHs */ /* Module local predicates */ #define ASKFOR(aa) ((aa) == 0xFFFF) /* Is this one we're sposed to ask for? */ #define SHRMSK 0x8000 /* Is this shared with another drive? */ #define SHARED(bb) ((bb)!=0xFFFF && (bb) & SHRMSK) /* Is this nd??bs field shared with another disk? */ #define GETSHARED(cc) ((cc) & ~SHRMSK) /* Get the drive we share with */ /***************************************************************************/ /* EXPORT /* initxios_info: gets whatever information GENSYS needs from xios /***************************************************************************/ initxios_info(xf,goff) /* get info from xios file */ WORD xf; /* xios file descriptor */ WORD goff; /* group offset within xios file */ { REG WORD ii; /* counter */ DPB dd; /* a place to keep this info */ EDPB ee; /* a place to keep this info */ DPH *dph; DINFO *dinf; csfd = xf; /* assign to global: set up cseek */ csgoff = goff; /* assign to global */ cseek(XTABLOC); /* go to where the XIOSTAB info is */ read(xf,&xt,sizeof xt); /* read in the xios info */ dphtab = xt.xt_dphtab; /* point to disk parm header table */ for( ii=0; iidph_dpb); /* point to the disk parm block */ read(xf,&ee,sizeof(EDPB)); /* Read as though EDPB */ if (ee.edpb_extflag == 0xFFFF) { /* Extended DPB */ cseek(dph->dph_dpb+12); /* seek past extended info */ } else { cseek(dph->dph_dpb); } read(xf,&dd,sizeof(DPB)); /* read DPH */ dinf->d_blksize = 128 << dd.dpb_psh; dinf->d_csvsize = 0x7FFF & dd.dpb_cks; dinf->d_alvsize = (dd.dpb_dsm/8 + 1) * 2; dinf->d_shash = 4 * (1 + dd.dpb_drm); dinf->d_ndirbs = -1; /* ask for these by name! */ dinf->d_ndatbs = -1; dinf->d_hashing = TRUE; /* default to hashing */ } /* end of drive info init */ } /************************************************************************/ /* EXPORT /* doxbufs: queries user for BDOS buffering info; /* exits only when all data valid /************************************************************************/ BYTE * doxbufs(txt,bdtitle) BYTE *txt; BYTE *bdtitle; { BYTE cmds[CMDSLEN]; BOOLEAN xiosvalid(); EXTERN BYTE *clearit; FOREVER { printf("%s",clearit); /* clear screen */ printf("%s\n",bdtitle); dbufs_display(); /* display */ printf("Drive ( to exit) ? "); if( gets(cmds)!=cmds || *cmds==NULL ) { /* they hit ? */ if( xiosvalid() ) break; USERR("Please correct drive buffers information\n"); press_return(); continue; } askabout(cmds); /* go do what they want */ } return NULLPTR; /* error msg for menu handler */ } /************************************************************************/ /* dbufs_display: display disk buffering info /************************************************************************/ dbufs_display() { REG UWORD ii, jj, tot; /* counters */ DPH *dph; DINFO *dinf; tot = 0; /* init this */ dcalcsizes(); /* check all the sizes */ printf("\n\t*** Disk Buffering Information ***\n"); printf(" Dir Max/Proc Data Max/Proc Hash Specified\n"); printf("Drv Bufs Dir Bufs Bufs Dat Bufs -ing Buf Pgphs\n"); printf("=== ==== ======== ==== ======== ==== =========\n"); for( ii=0; iidph_dirbcb,dinf->d_ndirbs,dinf->d_pmdirbs); dspdnums(dph->dph_datbcb,dinf->d_ndatbs,dinf->d_pmdatbs); if( ! ASKFOR(dph->dph_hstbl) ) printf(" fixed "); else if( dinf->d_hashing ) printf(" yes "); else printf(" no "); jj = dspdsize(dph,dinf); if( jj == -2 ) printf(" fixed "); else if( jj == -1 ) printf(" ?? "); else { printf(" %4.4x ",jj >> 4); tot += jj; } printf("\n"); } /*** end for each drive ***/ printf("Total paragraphs allocated to buffers: %x\n",tot >> 4); } /***************************************************************************/ /* dspdsize: calculates a drive's user-requestable buffer size, in bytes /***************************************************************************/ WORD dspdsize(dph,dinf) /* calculate size requested */ DPH *dph; /* returns -1 if still needs info */ DINFO *dinf; /* returns -2 if pre-allocated */ { REG WORD siz; siz=0; if( !ASKFOR(dph->dph_dirbcb) && !ASKFOR(dph->dph_datbcb) && !ASKFOR(dph->dph_hstbl) ) return -2; /* nothing to say here */ if( ASKFOR(dph->dph_dirbcb) ){ if( ASKFOR(dinf->d_ndirbs) ) return -1; if( !SHARED(dinf->d_ndirbs) ) siz += dinf->d_sdirbs * dinf->d_ndirbs; } if( ASKFOR(dph->dph_datbcb) ){ if( ASKFOR(dinf->d_ndatbs) ) return -1; if( !SHARED(dinf->d_ndatbs) ) siz += dinf->d_sdatbs * dinf->d_ndatbs; } if( ASKFOR(dph->dph_hstbl) ){ if( dinf->d_hashing ) siz += dinf->d_shash; } return siz; } /***************************************************************************/ /* dspdnums: displays the data/dir buf numbers /***************************************************************************/ dspdnums(nfix,ninput,npm) /* display subroutine */ WORD nfix; WORD ninput; WORD npm; { if( !ASKFOR(nfix) ) printf("fixed "); else if( SHARED(ninput) ) printf("shares %c: ",'A'+GETSHARED(ninput)); else { if( ASKFOR(ninput) ) printf(" ?? "); else printf(" %2.2x ",ninput); if( ASKFOR(npm) ) printf(" ?? "); else printf(" %2.2x ",npm); } } /***************************************************************************/ /* dcalcsizes: calculates buffer sizes across shared buffers /***************************************************************************/ dcalcsizes() /* make sure all the sizes are correct */ { REG WORD ii, jj; REG WORD *pkk; DPH *dph; DINFO *dinf; for( ii=0; iid_sdirbs = dinf->d_sdatbs = 0; } for( ii=0; iidph_dirbcb) ) /* max out the size of a dirbuf */ if( !ASKFOR(dinf->d_ndirbs) ) { /* if it's real data there */ if( SHARED(dinf->d_ndirbs) ) { jj = GETSHARED(dinf->d_ndirbs); pkk = & ((di[jj])->d_sdirbs); } else pkk = & dinf->d_sdirbs; if( dinf->d_blksize > *pkk ) /* assign the maximum size found */ *pkk = dinf->d_blksize; } if( ASKFOR(dph->dph_datbcb) ) /* max out the size of a data buf */ if( !ASKFOR(dinf->d_ndatbs) ) { if( SHARED(dinf->d_ndatbs) ) { jj = GETSHARED(dinf->d_ndatbs); pkk = & ((di[jj])->d_sdatbs); } else pkk = & dinf->d_sdatbs; if( dinf->d_blksize > *pkk ) *pkk = dinf->d_blksize; } } } /***************************************************************************/ /* ask user about a drive /***************************************************************************/ askabout(drspec) /* ask user about a drive */ BYTE *drspec; { REG WORD dr; DPH *dph; DINFO *dinf; BOOLEAN askhash(); if( *drspec == '*' ) { askstar(); /* get info, apply to all disks */ return; } dr = toupper(*drspec) - 'A'; /* which drive do they want to fix? */ if( dr<0 || dr>=DPHNUM || dphtab[dr]==0 || drspec[1] != ':') { USERR("Problem with '%s':\n",drspec); USERR("Please specify an existing drive between 'A:' and 'P:'\n"); press_return(); return; } dph = dh[dr]; dinf = di[dr]; if( dspdsize(dph,dinf) == -2 ) { /* is there anything to modify? */ USERR("All buffers for %c: are fixed within the XIOS module.\n", dr+'A'); USERR("You can't modify this fixed information in GENSYS.\n"); press_return(); return; } if( ASKFOR(dph->dph_dirbcb) ){ dinf->d_ndirbs = asknd(1,FALSE); /* get directory info */ dinf->d_pmdirbs = askpm(1,dinf->d_ndirbs); } if( ASKFOR(dph->dph_datbcb) ){ dinf->d_ndatbs = asknd(2,(128==dinf->d_blksize)); /* get data info */ dinf->d_pmdatbs = askpm(2,dinf->d_ndatbs); } if( ASKFOR(dph->dph_hstbl) ){ dinf->d_hashing = askhash(); } } /****************************************************************************/ /* askstar: asks buffering questions & applies to all ASKFOR/unanswered drives /****************************************************************************/ askstar() { REG WORD dr; DPH *dph; DINFO *dinf; WORD andirbs, andirpms, andatbs, andatpms; BOOLEAN ahash, askhash(); andirbs = asknd(1,FALSE); /* Number of directory buffers? */ andirpms = askpm(1,andirbs); /* Process Max Dir Bufs? */ andatbs = asknd(2,FALSE); /* Number of data buffers? */ andatpms = askpm(2,andatbs); /* Process Max Data Bufs? */ ahash = askhash(); /* Hashing? */ for( dr=0; drdph_dirbcb) ) if( ASKFOR(dinf->d_ndirbs) ) { dinf->d_ndirbs = andirbs; dinf->d_pmdirbs = andirpms; } if( ASKFOR(dph->dph_datbcb) ) if( ASKFOR(dinf->d_ndatbs) ) { dinf->d_ndatbs = andatbs; dinf->d_pmdatbs = andatpms; } if( ASKFOR(dph->dph_hstbl) ) dinf->d_hashing = ahash; } } /***************************************************************************/ /* asknd: ask the user for the number of dir/data buffers /***************************************************************************/ WORD asknd(type,zero_ok) WORD type; /* 1=dir, 2=data */ BOOLEAN zero_ok; { REG WORD val, jj; BYTE *name; BYTE cmds[CMDSLEN]; DPH *dph; if( type==1 ) name="directory"; else name="data"; FOREVER { printf("Number of %s buffers, or drive to share with ? ",name); gets( cmds ); if( cmds[1] != ':' ) { val = atoih(cmds); if( val > 0 && val <= 127 ) break; if(*cmds == '0') { if( zero_ok ) break; USERR("Number of buffers must be greater than 0\n"); press_return(); continue; } } else { val = toupper(*cmds) - 'A'; /* which drive do they want? */ if( val>=0 && valdph_dirbcb; else jj = dph->dph_datbcb; if( ASKFOR(jj) ) { if( type==1 ) jj = di[val]->d_ndirbs; else jj = di[val]->d_ndatbs; if( !SHARED(jj) ) { val |= SHRMSK; /* turn on sharing */ break; } } USERR("Drive %c: is not available for sharing\n",'A'+val); press_return(); continue; } } USERR("Please input a number, or an existing drive from 'A:' to 'P:'\n"); press_return(); } return val; } /************************************/ /* askpm: ask about process maximum /************************************/ WORD askpm(type,pmmax) WORD type; WORD pmmax; { REG WORD val; BYTE *cmds[CMDSLEN]; BYTE *name; switch(type) { case 1: name="directory"; break; case 2: name="data"; } if( SHARED(pmmax) || pmmax<=0 ) return 0; FOREVER { /* get input from user */ printf("Maximum %s buffers per process [%x]? ",name,pmmax); gets( cmds ); if( *cmds==NULL ) val = pmmax; /* default value */ else val = atoih(cmds); if( val > 0 && val <= pmmax ) break; USERR("Maximum must be > zero and <= %x\n",pmmax); press_return(); } return val; } /*****************************************/ /* askhash: ask user if they'd like to hash /*****************************************/ BOOLEAN askhash() { REG WORD val; BYTE *cmds[CMDSLEN], *cp; FOREVER { printf("Hashing [yes] ? "); gets( cmds ); if( *cmds == NULL ) return TRUE; for( cp=cmds; *cp; ++cp ) { if( *cp==' ' || *cp=='\t' ) { *cp = NULL; break; } if( isupper(*cp) ) *cp = tolower(*cp); } if( (val=whichof(cmds,",yes,true,on,hashing,no,false,off")) > 0 ) break; USERR("Please answer 'hashing', 'yes', or 'no'.\n"); press_return(); } return val<=4; /* TRUE iff answer was one of 1st four */ } /************************************************************************/ /* EXPORT /* xiosvalid: validates that all the user-requestable info has been filled in /************************************************************************/ BOOLEAN xiosvalid() { REG WORD ii; REG WORD ndph; ndph = 0; for( ii=0; iidph_csv) ){ dinf->d_modified = TRUE; if( dinf->d_csvsize == 0 ) dph->dph_csv=0; else { dph->dph_csv = doffset; doffset += bufwrite(dinf->d_csvsize,ZBYTE); } } } for( ii=0; iidph_alv) ){ dinf->d_modified = TRUE; dph->dph_alv = doffset; doffset += bufwrite(dinf->d_alvsize,ZBYTE); } } locbufs_off = 0; /* amount (bytes) of local dir buffer*/ for( ii=0; iidph_dirbcb) ){ /* DIR BCBs */ dinf->d_modified = TRUE; if( ! SHARED(dinf->d_ndirbs) ) { /* take care of sharing later */ lastlink=0; /* linker */ zfill(&bcb,sizeof(BCB)); /* init to zeroes */ bcb.bcb_drv = 0xFF; for( jj=dinf->d_ndirbs; jj>0; --jj ){ bcb.bcb_link = lastlink; /* pts to loc of buffer relative to locrsvd_off */ bcb.bcb_bufptr = locbufs_off; locbufs_off += dinf->d_sdirbs; /* increase buf size */ /* calc where bcb will be written to, for fixlater */ dmagic = lseek(fns,0L,1) + OFF_BCBPTR; fixlater(dmagic,F_ADD,&locrsvd_off); /* finally, write out the bcb info */ lastlink = doffset; /* point to the bcb */ doffset += datwrite(&bcb,sizeof bcb); } bcbh.bcbh_lr = lastlink; /* fill in the bcb hdr */ bcbh.bcbh_pm = dinf->d_pmdirbs; dph->dph_dirbcb = doffset; /* link to head of list */ /* write out a buffer control block hdr */ doffset += datwrite(&bcbh,sizeof bcbh); } } } for( ii=0; iidph_datbcb) ){ /* DATA BCBs: !!temporary!! */ dinf->d_modified = TRUE; if( ! SHARED(dinf->d_ndatbs) ) { /* do sharing later */ lastlink=0; /* linker */ zfill(&bcb,sizeof(BCB)); /* init to zeroes */ bcb.bcb_drv = 0xFF; for( jj=dinf->d_ndatbs; jj>0; --jj ){ bcb.bcb_link = lastlink; bcb.bcb_bufptr = bufs_seg; /* point into reserved area */ bufs_seg += (dinf->d_sdatbs) >>4; /* cvt to pgphs */ /* calculate where the bcb.bcb_bufptr will be written in file */ dmagic = lseek(fns,0L,1) + OFF_BCBPTR; fixlater(dmagic,F_ADD,&rsvd_seg); /* fix the bufptr */ lastlink = doffset; /* write out a buffer control block */ doffset += datwrite(&bcb,sizeof bcb); } bcbh.bcbh_lr = lastlink; /* fill in the bcb hdr */ bcbh.bcbh_pm = dinf->d_pmdatbs; dph->dph_datbcb = doffset; /* link to head of list */ /* write out a buffer control block hdr */ doffset += datwrite(&bcbh,sizeof bcbh); } } } /* now write the local directory buffers */ locrsvd_off = doffset; /* address of directory buffer area */ doffset += bufwrite(locbufs_off,ZBYTE); /* write out the buffers */ /* dmagic: magic number to add to dphtab[ii] */ dmagic = OFF_DPHHTAB + fldstart;/* where in file does SYSDAT start */ for( ii=0; iidph_hstbl) ) { /* HASH TABLE ALLOC */ dinf->d_modified = TRUE; if( dinf->d_hashing ) { dph->dph_hstbl = bufs_seg; /* point into reserved area */ bufs_seg += (dinf->d_shash) >>4; /* cvt bytes to pgphs */ /* remember where the dph_hstbl word will be stored */ /* so we can adjust bufs_seg by starting loc of rsvd_seg */ fixlater(dmagic+dphtab[ii],F_ADD,&rsvd_seg); } else dph->dph_hstbl = 0; } } /**** end of processing ****/ for( ii=0; iidph_dirbcb) ) { jj = GETSHARED(di[ii]->d_ndirbs); dh[ii]->dph_dirbcb = dh[jj]->dph_dirbcb; } if( ASKFOR(dh[ii]->dph_datbcb) ) { jj = GETSHARED(di[ii]->d_ndatbs); dh[ii]->dph_datbcb = dh[jj]->dph_datbcb; } } /* end resolve shared buffers */ return doffset; } /***************************************************************************/ /* EXPORT /* fixupxios_info: does the fixup for the dph info in the xios /*************************************************************************/ fixupxios_info() /* call from fixups */ { REG WORD ii; /* counter */ REG LONG dmagic; /* addr var */ for( ii=0; iid_modified ) { dmagic = fldstart + dphtab[ii]; lseek(fns,dmagic,0); /* where to write to */ write(fns,dh[ii],sizeof(DPH)); /* what to write */ } }