home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume03 / badm < prev    next >
Encoding:
Internet Message Format  |  1988-09-11  |  43.6 KB

  1. From: <decvax!philabs!nyit!rick>
  2. Newsgroups: mod.sources
  3. Subject: badm - BSD4.2 MASSBUS disk formatter
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 3, Issue 84
  7. Submitted by: Rick Ace <decvax!philabs!nyit!rick>
  8.  
  9.  
  10. This is a copy of the 4.2bsd timesharing disk formater I posted to
  11. net.sources a few months ago.
  12.  
  13. Rick Ace
  14. New York Institute of Technology
  15. Computer Graphics Laboratory
  16. Wheatley Road
  17. Old Westbury, NY  11568
  18.  
  19. USENET:    {decvax,seismo}!philabs!nyit!rick
  20.  
  21. --Cut here-- --Cut here--  --Cut here--
  22. #!/bin/sh
  23. # shar:    Shell Archiver
  24. #    Run the following text with /bin/sh to create:
  25. #    README badm.c badm.8 hp.diffs dkio.add
  26. echo shar: extracting README
  27. cat - << \SHAR_EOF > README
  28. badm Rev 2.0                        31-Oct-85
  29.  
  30. The "badm" utility is a formater for certain MASSBUS disks, operating
  31. under full multi-user timesharing 4.2bsd Vax system.  This software
  32. has been placed in the public domain, for the benefit of all Vax
  33. 4.2bsd sites.  The following files are included in this distribution:
  34.  
  35.     badm.c        C source code for badm utility
  36.     badm.8        Manual entry for badm - READ THIS FIRST!
  37.     hp.diffs    Additions/differences to vaxmba/hp.c
  38.     dkio.add    Additions to vax/dkio.h
  39.  
  40. Installation consists of some minor additions and modifications to the
  41. 4.2bsd MASSBUS disk driver (vaxmba/hp.c) and some additions to the
  42. disk ioctl header file (vax/dkio.h).  badm will *not* work without
  43. these changes to the 4.2bsd kernel.
  44.  
  45. To install:
  46.     1.  Read hp.diffs and dkio.add, and make coding changes
  47.         specified therein.
  48.     2.  Recompile kernel and boot it.
  49.     3.  Compile badm.c.
  50.     4.  READ MANUAL ENTRY BEFORE USING badm.
  51.  
  52. This is the 2.0 revision of badm, supporting the following disks:
  53.     RM05  RM03  Eagle  RP06  RP05  RP04
  54.  
  55. Additional disks can be supported by adding entries to the disktypes[]
  56. table in badm.c (this may also require a new whdr_XXX() subroutine,
  57. depending upon the header design of the target disk).
  58.  
  59. Please address comments, questions, flames to the author:
  60.  
  61. Rick Ace
  62. New York Institute of Technology
  63. Computer Graphics Laboratory
  64. Wheatley Road
  65. Old Westbury, NY  11568
  66.  
  67. USENET:    {decvax,seismo}!philabs!nyit!rick
  68. SHAR_EOF
  69. echo shar: extracting badm.c
  70. cat - << \SHAR_EOF > badm.c
  71. #ifndef lint
  72. static char rcsid[] = "$Header: badm.c,v 2.0 85/10/31 12:57:16 rick Exp $";
  73. #endif
  74.  
  75. /* 
  76.  * Utility to do media checking/formating during timesharing
  77.  *
  78.  * $Log:    badm.c,v $
  79.  * Revision 2.0  85/10/31  12:57:16  rick
  80.  * * First publicly-released version *
  81.  * 
  82.  * Rick Ace
  83.  * New York Institute of Technology
  84.  * Computer Graphics Laboratory
  85.  * Old Westbury, New York  11568
  86.  *
  87.  * {seismo,decvax}!philabs!nyit!rick
  88.  */
  89.  
  90. #include <sys/types.h>
  91. #include <sys/ioctl.h>
  92. #include <sys/dkbad.h>
  93. #include <vax/dkio.h>
  94. #include <disktab.h>
  95. #include <signal.h>
  96. #include <stdio.h>
  97. #include <sysexits.h>
  98.  
  99. /*
  100.  * There are a few hp.c driver bugs that can be circumvented by
  101.  * workaround code in badm.  These workarounds appear under the
  102.  * HPBUG conditional.  The `normal' (i.e., driver functions
  103.  * properly) case appears after the `#else'.
  104.  *
  105.  * Of course, the right thing is to fix the driver instead,
  106.  * but who knows... the same bugs might be in 4.Xbsd forever.
  107.  */
  108. #define HPBUG    1    /* hp driver bugs are present */
  109.  
  110. #define MAXNUMBAD    126    /* max # of bad sectors on one disk */
  111.  
  112. /*
  113.  * Function codes for drive-specific header-write routines
  114.  */
  115. #define WHDR_VALID    0    /* mark the header as valid */
  116. #define WHDR_BAD    1    /* mark the header as a bad sector */
  117.  
  118. /*
  119.  * Special values returned by Btsector() 
  120.  */
  121. #define BTEMPTY        ((daddr_t) -1)    /* entry is empty */
  122. #define BTINVALID    ((daddr_t) -2)    /* entry contains an illegal c/t/s */
  123.  
  124. int    bflag,iflag;
  125. char    *cmd;        /* command and options, from argv */
  126. char    diskdevice[100] = "/dev/r"; /* disk device name, built from argv */
  127. int    dfd;        /* file descriptor of disk device */
  128. char    *patternbuf;    /* output buffer, contains patterns, 0 if none */
  129. char    *readbackbuf;    /* input buffer, for readback from disk */
  130. unsigned short short_ones = ~0; /* all 1 bits set */
  131. int    wantout;    /* set by SIGINT to request graceful exit */
  132. int    bsi;        /* T/F: bst has been initialized */
  133. struct dkbad bst;    /* bad sector table */
  134. int    whdr_unknown();
  135.  
  136. /*
  137.  * Drive description table
  138.  */
  139. struct st {
  140.     char    vname[12];    /* vendor's name for disk */
  141.     int    sectsize;    /* # bytes per sector */
  142.     daddr_t    nsect;        /* # sectors/track */
  143.     daddr_t    ntrack;        /* # tracks/surfaces/heads */
  144.     daddr_t    nspc;        /* # sectors/cylinder */
  145.     daddr_t    ncyl;        /* # cylinders */
  146.     int    (*wheader)();    /* routine to write sector header */
  147.     daddr_t    bad0sn;        /* sector # of first bad sector table */
  148. } st =
  149.     { "default",      0,  0,  0,     0,   0, whdr_unknown };
  150.  
  151. int    whdr_rm(),whdr_rp();
  152.  
  153. struct st disktypes[] = {
  154.     { "eagle",    512, 48, 20, 48*20, 842, whdr_rm },
  155.     { "rm05",    512, 32, 19, 32*19, 823, whdr_rm },
  156.     { "rm03",    512, 32,  5, 32* 5, 823, whdr_rm },
  157.     { "rp06",    512, 22, 19, 22*19, 815, whdr_rp },
  158.     { "rp05",    512, 22, 19, 22*19, 411, whdr_rp },
  159.     { "rp04",    512, 22, 19, 22*19, 411, whdr_rp },
  160.     { "\0" }        /* LAST ENTRY SENTINEL */
  161. };
  162.  
  163. /*
  164.  * Bit patterns for media surface testing
  165.  */
  166. unsigned short testpattern[] = {
  167.     0x3333, 0x71C7, 0xB6DB, 0xDB6D, 0xE38E, 0xC71C, 0x83E8, 0x0FF0,
  168.     0xEC6D, 0x1C71, 0x38E3, 0xAAAA, 0x5555, 0xF00F, 0xA5A5, 0x6DEC
  169. };
  170.  
  171. #define    NPATTERN    (sizeof testpattern / sizeof testpattern[0]) 
  172.  
  173. /*
  174.  * Torture-seek routine tables
  175.  *
  176.  * Routines take ordinal iteration number, returning
  177.  * a sector number to seek to
  178.  */
  179. daddr_t    tort0(),tort1(),tort2(),tort3();
  180. daddr_t    (*tortvec[])() = {
  181.     tort0, tort1, tort2, tort3
  182. };
  183.  
  184. /*
  185.  * Command/options table
  186.  *
  187.  * WHEN CHANGING THIS TABLE BE SURE TO CHANGE THE USAGE MESSAGE TOO!
  188.  *
  189.  * Any option characters appearing in co_opt must also appear as
  190.  * cases of the `switch' statement in Main().
  191.  */
  192. int    cmda(),cmdrw(),cmdt();
  193.  
  194. struct cotab {
  195.     char    co_cmd;        /* command name, 1 letter */
  196.     char    co_opt[7];    /* legal options for the command */
  197.     int    (*co_rtn)();    /* driver */
  198. } cotab[] = {
  199.     'w',    "bi",    cmdrw,
  200.     'r',    "",    cmdrw,
  201.     'a',    "",    cmda,
  202.     't',    "",    cmdt,
  203.     0                /* TERMINATOR */
  204. };
  205.  
  206. long    atol(),lseek();
  207. char    *ctime(),*index(),*malloc();
  208. int    catchint();
  209. daddr_t    btsector();
  210.  
  211. main(argc,argv)
  212.     int argc;
  213.     char **argv;
  214. {
  215.     register struct cotab *co;
  216.     register char *p;
  217.  
  218.     if (signal(SIGINT,SIG_IGN) != SIG_IGN) 
  219.         (void) signal(SIGINT,catchint);
  220.     if (argc < 2) 
  221.         usage();
  222.     /*
  223.      * Identify the command
  224.      */
  225.     cmd = argv[1];
  226.     co = &cotab[0];
  227.     co--;
  228.     do if ((++co)->co_cmd == 0) usage();
  229.      while (cmd[0] != co->co_cmd);
  230.     /*
  231.      * Inspect and validate the options to the main command
  232.      */
  233.     for (p = cmd; *++p; ) {
  234.         if (index(co->co_opt,*p) == 0) 
  235.             usage();
  236.         /*
  237.          * All flag characters specified in the co_opt strings
  238.          * must have `case' entries in this switch statement.
  239.          * Arriving at the `should not happen' default case indicates
  240.          * that at least one such `case' is missing (programmer error).
  241.          */
  242.         switch (*p) {
  243.         case 'b':    bflag++; break;
  244.         case 'i':    iflag++; break;
  245.         default:    quit(EX_SOFTWARE,"UNEXPECTED FLAG: %c\n",*p);
  246.         }
  247.     }
  248.     /*
  249.      * Command/options scan is complete, invoke the driver for this command
  250.      */
  251.     (*co->co_rtn)(argc-2,argv+2);
  252. }
  253.  
  254. /*
  255.  * Add a sector to the bad sector table and rewrite the header for the sector
  256.  *
  257.  * Returns T/F: sector was added to the bad sector table
  258.  */
  259. addbad(sn)
  260.     daddr_t sn;        /* sector number */
  261. {
  262.     register struct bt_bad *e,*e1;
  263.     register char **bsp;
  264.     daddr_t esn;
  265.     char *bsbuf[MAXNUMBAD];
  266.  
  267.     /*
  268.      * Abort now if I don't know how to write headers on this drive
  269.      */
  270.     if (st.wheader == whdr_unknown) {
  271.         whdr_unknown((daddr_t)0,0,WHDR_BAD); /* only print error msg */
  272.         exit(EX_UNAVAILABLE);    /* should never get here, but... */
  273.     }
  274.     if (!bsi)    /* double-check for programming errors */
  275.         quit(EX_SOFTWARE,"bst NOT SET UP!\n");
  276.     printf("sn%d: ",sn);
  277.     if (btsector(&bst.bt_bad[MAXNUMBAD - 1]) != BTEMPTY) {
  278.         printf("BAD SECTOR TABLE IS FULL, CANNOT ADD\n");
  279.         return 0;
  280.     }
  281.     /*
  282.      * Locate the position in the table where the new entry will go.
  283.      */
  284.     e = &bst.bt_bad[-1];
  285.     do {
  286.         esn = btsector(++e);
  287.         if (esn == BTINVALID) {
  288.             /*
  289.              * This should never happen because the sector
  290.              * entries in bt_bad have already been validated
  291.              */
  292.             printf("BAD SECTOR TABLE ENTRY %d CONTAINS AN ILLEGAL ADDRESS cyl=%x trksec=%x\n\
  293. NO ACTION TAKEN\n", e - &bst.bt_bad[0], e->bt_cyl, e->bt_trksec);
  294.             return 0;
  295.         }
  296.         if (sn == esn) {
  297.             printf("ALREADY IN BAD SECTOR TABLE (ALTERNATE IS BAD!)\n");
  298.             return 0;
  299.         }
  300.     } while (esn != BTEMPTY && sn > esn);
  301.     /*
  302.      * Found the proper position for the new entry.  If there are any
  303.      * active entries with higher disk addresses, they must be shuffled
  304.      * down one slot to make room for the new entry, because DEC std 144
  305.      * dictates that the table must be in ascending order.
  306.      *
  307.      * Shuffling the entries also entails shuffling the contents of the
  308.      * alternate sectors, so the first task is to grab those contents.
  309.      */
  310.     bsp = &bsbuf[0];
  311.     e1 = e;
  312.     do {
  313.         esn = btsector(e1);
  314.         if (esn == BTEMPTY) 
  315.             break;
  316.         if ((*bsp = malloc((unsigned)st.sectsize)) == 0) {
  317.             printf("Cannot Malloc memory, no action taken\n");
  318.             goto fre0;
  319.         }
  320.         if (bread(esn, *bsp++, st.sectsize) < 0) {
  321.             printf("Error reading sector %d, no action taken\n",esn);
  322.             *bsp = 0;
  323.             goto fre0;
  324.         }
  325.     } while (++e1 < &bst.bt_bad[MAXNUMBAD]);
  326.     *bsp = 0;            /* tie off buffer list */
  327.     /*
  328.      * Shuffle the table entries to make room, then install the new entry
  329.      */
  330.     for (e1 = &bst.bt_bad[MAXNUMBAD - 2]; e1 >= e; e1--) 
  331.         e1[1] = e1[0];
  332.     e->bt_cyl = sn / st.nspc;
  333.     e->bt_trksec = sn % st.nspc / st.nsect << 8 | sn % st.nsect;
  334.     writebst();            /* write bad sector table, 5 copies */
  335.     /*
  336.      * Rewrite the header of the new bad sector to mark it bad
  337.      */
  338.     (*st.wheader)(sn,1,WHDR_BAD);
  339.     printf("added to bad sector table\n");
  340.     /*
  341.      * Write the contents of the shuffled sectors back to their
  342.      * new alternates on disk
  343.      */
  344.     e1 = e;
  345.     for (bsp = &bsbuf[0]; *bsp; ) {
  346.         /*
  347.          * For each core buffer there should be a sector number.
  348.          * Abort if I can't determine the sector number (this
  349.          * would imply a logic error in this subroutine).
  350.          */
  351.         if (++e1 >= &bst.bt_bad[MAXNUMBAD] ||
  352.             (esn = btsector(e1)) == BTEMPTY ||
  353.             esn == BTINVALID) 
  354.             quit(EX_SOFTWARE,"LOST SECTOR NUMBERS FOR RE-WRITE\n");
  355.         if (bwrite(esn, *bsp, st.sectsize) < 0) 
  356.             printf("FAILED to re-write sector %d\n",esn);
  357.         free(*bsp++);            /* discard buffer */
  358.     }
  359.     return 1;                /* added successfully */
  360.  
  361.     /*
  362.      * Free Malloc buffers and error exit
  363.      */
  364. fre0:    for (bsp = &bsbuf[0]; *bsp; ) 
  365.         free(*bsp++);
  366.     return 0;
  367. }
  368.  
  369. /*
  370.  * Read from disk
  371.  *
  372.  * Returns 0 OK, -1 error
  373.  */
  374. bread(sn,buf,size)
  375.     daddr_t sn;        /* sector number */
  376.     char *buf;        /* buffer */
  377.     int size;        /* size (bytes) */
  378. {
  379.     (void) lseek(dfd, (long)sn * (long)st.sectsize, 0);
  380.     if (read(dfd,buf,size) == size) 
  381.         return 0;
  382.     return -1;
  383. }
  384.  
  385. /*
  386.  * Given a bad sector table (bt_bad) entry, convert it to a sector number
  387.  *
  388.  * Returns sector number, or
  389.  *    BTEMPTY if the entry is all 1s (i.e., unoccupied), or
  390.  *    BTINVALID if entry's cylinder, track, or sector number is out of range
  391.  */
  392. daddr_t
  393. btsector(e)
  394.     register struct bt_bad *e;    /* entry to be converted */
  395. {
  396.     register unsigned int etrack,esector;
  397.  
  398.     if (e->bt_cyl == short_ones && e->bt_trksec == short_ones) 
  399.         return BTEMPTY;
  400.     etrack = e->bt_trksec >> 8;
  401.     esector = e->bt_trksec & 0xFF;
  402.     if (e->bt_cyl >= st.ncyl ||
  403.         etrack >= st.ntrack ||
  404.         esector >= st.nsect) 
  405.         return BTINVALID;
  406.     return e->bt_cyl * st.nspc + etrack * st.nsect + esector;
  407. }
  408.  
  409. /*
  410.  * Write to disk
  411.  *
  412.  * Returns 0 OK, -1 error
  413.  */
  414. bwrite(sn,buf,size)
  415.     daddr_t sn;        /* sector number */
  416.     char *buf;        /* buffer */
  417.     int size;        /* size (bytes) */
  418. {
  419.     (void) lseek(dfd, (long)sn * (long)st.sectsize, 0);
  420.     if (write(dfd,buf,size) == size) 
  421.         return 0;
  422.     return -1;
  423. }
  424.  
  425. /*
  426.  * SIGINT (Control-C) handler
  427.  */
  428. catchint()
  429. {
  430.     wantout++;
  431. }
  432.  
  433. /*
  434.  * Driver for `a' command
  435.  */
  436. cmda(ac,av)
  437.     int ac;
  438.     char **av;    /* main() argv sans first two entries */
  439. {
  440.     register int snx;
  441.     char *sbuf;
  442.     daddr_t sn;
  443.     int brv;
  444.  
  445.     if (ac < 2) 
  446.         usage();
  447.     diskopen(av[0],2);
  448.     get_devdata();        /* get disk geometry, etc. */
  449.     readbst();        /* read bad sector table off pack */
  450.     snx = 1;
  451.     sbuf = malloc((unsigned)st.sectsize);
  452.     do {
  453.         sn = atol(av[snx]);
  454.         if (sn < 0 || sn >= st.bad0sn - MAXNUMBAD) {
  455.             /*
  456.              * Illegal to specify sectors that are
  457.              * 1.  beyond the end of the disk
  458.              * 2.  in the last track (where the bad sector file is) 
  459.              * 3.  in the alternate-sector region (the 126 sectors
  460.              *     preceding the last track on the disk) 
  461.              */
  462.             printf("sn%d: out of range for `%s' disk\n",sn,st.vname);
  463.             continue;
  464.         }
  465.         /*
  466.          * Read sector contents, mark sector bad, and then
  467.          * write the old contents out to the alternate.
  468.          * If the data is so far gone that it cannot be
  469.          * read, then put something clean (i.e., zeros) 
  470.          * in the alternate in lieu of the data.
  471.          */
  472.         if ((brv = bread(sn,sbuf,st.sectsize)) < 0) {
  473.             printf("sn%d: CANNOT READ DATA - substituting zeros\n",sn);
  474.             bzero(sbuf,st.sectsize);    /* substitute zeros */
  475.         }
  476.         if (addbad(sn)) {    
  477.             /* rewrite contents to alternate */
  478.             printf("sn%d: copy ",sn);
  479.             if (bwrite(sn,sbuf,st.sectsize) < 0 || brv < 0) 
  480.                 printf("failed\n");
  481.             else
  482.                 printf("successful\n");
  483.         }
  484.     } while (++snx < ac);
  485.     free(sbuf);
  486. }
  487.  
  488. /*
  489.  * Driver for `r' and `w' commands
  490.  */
  491. cmdrw(ac,av)
  492.     int ac;
  493.     char **av;    /* main() argv sans first two entries */
  494. {
  495.     register daddr_t sector;
  496.     int pass,tracksize;
  497.     time_t now;
  498.  
  499.     if (ac != (iflag ? 2 : 1)) 
  500.         usage();
  501.     (void) time(&now);
  502.     printf(ctime(&now));
  503.     diskopen(av[0], cmd[0]=='w'?2:0);
  504.     get_devdata();        /* get disk geometry, etc. */
  505.     printf("%s: %s  #cylinders=%d, #tracks=%d, #sectors=%d, bytes/sector=%d\n",
  506.         diskdevice, st.vname, st.ncyl, st.ntrack, st.nsect, st.sectsize);
  507.     if (iflag) {
  508.         int serialno;
  509.  
  510.         printf("\nWriting valid headers on all sectors\n");
  511.         initheaders();        /* writes in last track too */
  512.         serialno = atoi(av[1]);
  513.         printf("\nInitializing empty bad sector table, pack serial # %d\n",serialno);
  514.         initbst(serialno);
  515.         writebst();
  516.     }
  517.     else {
  518.         if (bflag)        /* possibly updating the bad table? */
  519.             readbst();    /* yes, must read it in then */
  520.     }
  521.     printf("\nBeginning surface test\n");
  522.     tracksize = st.sectsize * st.nsect;    /* 1 track's worth of bytes */
  523.     if (*cmd == 'w') 
  524.         patternbuf = malloc((unsigned)tracksize);
  525.     readbackbuf = malloc((unsigned)tracksize);
  526.     /*
  527.      * Loop forever:
  528.      *    FOR (all patterns, repeat ad infinitum) 
  529.      *        FOR (all tracks on disk) 
  530.      *            write/read all sectors in track
  531.      *        END
  532.      *    END
  533.      */
  534.     for (pass = 0; ; pass = (pass + 1) % NPATTERN) {
  535.         if (patternbuf) 
  536.             initpattern(patternbuf,tracksize,pass);
  537.         for (sector = 0; sector < st.bad0sn; sector += st.nsect) {
  538.             if (wantout) {
  539.                 (void) time(&now);
  540.                 printf("\n*** badm interrupted at %s",ctime(&now));
  541.                 exit(EX_OK);
  542.             }
  543.             if (sector && (sector % (st.nspc * 100)) == 0) 
  544.                 printf("cylinder %d\n", sector / st.nspc);
  545.             format_track(sector,tracksize);
  546.         }
  547.     }
  548. }
  549.  
  550. /*
  551.  * Driver for `t' command (torture disk) 
  552.  */
  553. cmdt(ac,av)
  554.     int ac;
  555.     char **av;    /* main() argv sans first two entries */
  556. {
  557. #define TORTURE_MAX    5000
  558.     int pass,sbint,torture;
  559.     time_t now;
  560.     char *sbuf;
  561.  
  562.     if (ac != 1) 
  563.         usage();
  564.     (void) time(&now);
  565.     printf("Torture test, %s\n",ctime(&now));
  566.     diskopen(av[0],0);
  567.     get_devdata();        /* get disk geometry, etc. */
  568.     /*
  569.      * Slightly more optimal page-aligned buffer,
  570.      * so kernel spends less time in vslock/vsunlock
  571.      */
  572.     sbint = (int) malloc((unsigned)st.sectsize + 512);
  573.     sbint += 511;        /* round up to next page */
  574.     sbint &= ~511;
  575.     sbuf = (char *)sbint;
  576.     for (pass = 1; ; pass++) {
  577.         printf("Pass %d\n",pass);
  578.         torture = sizeof tortvec / sizeof tortvec[0] - 1;
  579.         do {
  580.             register daddr_t n,(*trou)();
  581.  
  582.             n = 0;
  583.             trou = tortvec[torture];
  584.             do {
  585. #ifdef TTEST
  586.                 printf("%d\t%6d\n",torture,(*trou)(n));
  587. #else
  588.                 (void) bread((*trou)(n),sbuf,st.sectsize);
  589. #endif
  590.                 if (wantout) {
  591.                     printf("\n*** torture interrupted\n");
  592.                     exit(EX_OK);
  593.                 }
  594.             } while (++n < TORTURE_MAX);
  595.         } while (--torture >= 0);
  596.     }
  597. }
  598.  
  599. /*
  600.  * Construct pathname of raw disk device and open it
  601.  *
  602.  * Outputs:
  603.  *    dfd        file descriptor on disk device
  604.  *    diskdevice    ASCII name of disk device (/dev/...) 
  605.  */
  606. diskopen(devun,omode)
  607.     char *devun;    /* device/unit specifier, e.g., "hp1" */
  608.     int omode;    /* mode for Open() syscall */
  609. {
  610.     strcat(diskdevice,devun);
  611.     strcat(diskdevice,"c");
  612.     if ((dfd = open(diskdevice,omode)) < 0) {
  613.         perror(diskdevice);
  614.         exit(EX_NOINPUT);
  615.     }
  616. #ifdef HPBUG
  617.     /*
  618.      * hp.c driver bug.  After spinning up a new disk, the Volume
  619.      * Valid bit in the RM/RP drive is reset.  hp.c notices this
  620.      * on the first I/O request following spinup, and sneaks in
  621.      * a read of the bad sector table prior to doing the requested
  622.      * disk transfer.  The bug comes when the first transfer
  623.      * done by badm includes the header; hp.c mistakenly
  624.      * 1) applies the DKIOCHDR request to the bad sector table
  625.      *    read operation,
  626.      * 2) then resets sc_hdr, failing to honor badm's request for
  627.      *    header I/O.
  628.      * Bummer # 1 causes hp.c to get a mangled copy of the bad
  629.      * sector table, and bummer # 2 causes errors when badm tries
  630.      * to write sector headers during a `badm wbi' operation.
  631.      *
  632.      * Workaround:  perform a gratuitous non-header read operation
  633.      * upon opening the disk to get the driver's bad sector table
  634.      * read operation over and done with.  My read here will probably
  635.      * fail with an HCE, but even so, it will have served its purpose.
  636.      */
  637.     {
  638.         char gbuf[512];
  639.  
  640.         (void) read(dfd,gbuf,sizeof gbuf);
  641.     }
  642. #endif HPBUG
  643. }
  644.  
  645. /*
  646.  * Per-track logic for surface testing and bad sector flagging
  647.  */
  648. format_track(startsn,tracksize)
  649.     daddr_t startsn;    /* starting sector number */
  650.     int tracksize;        /* number of bytes in the track */
  651. {
  652.     register int errorval,i,readpass;
  653.     char badmap[256];
  654.  
  655.     /*
  656.      * If doing the `w' command, write test patterns
  657.      */
  658.     if (patternbuf && bwrite(startsn,patternbuf,tracksize) < 0) {
  659.         /*
  660.          * Problems... slow down to 1 sector at a time
  661.          * ignoring errors (I'll catch them on readback) 
  662.          */
  663.         i = 0;
  664.         do (void) bwrite(startsn+i,patternbuf,st.sectsize);
  665.          while (++i < st.nsect);
  666.     }
  667.     /*
  668.      * Read test patterns (or whatever) back
  669.      */
  670.     (void) numecc();        /* clear ECC count */
  671.     if (bread(startsn,readbackbuf,tracksize) < 0 || numecc()) {
  672.         /*
  673.          * Hard error or ECC, slow down to inspect sectors individually.
  674.          * The code here makes several passes over the entire track,
  675.          * because if the error is marginal, it might not show up on
  676.          * the first try.
  677.          *
  678.          * `badmap' limits the number of complaints to one per sector
  679.          * when I can't mark the sector as bad (i.e., Addbad()==0).
  680.          */
  681.         readpass = 8;        /* init pass counter */
  682.         bzero(badmap,sizeof badmap); /* no complaints issued yet */
  683.         do {
  684.             i = 0;        /* init sector # within track */
  685.             do {
  686.                 if (badmap[i]) /* if previous pass found it */
  687.                     continue; /* ... that was enough */
  688.                 errorval = 0;
  689.                 if (bread(startsn+i,readbackbuf,st.sectsize) < 0
  690.                      || (errorval = numecc())) {
  691.                     /*
  692.                      * Report bad sector, then if `b' flag
  693.                      * is set, bad it and retry the read
  694.                      */
  695.                     printf("sn%d: ",startsn+i);
  696.                     printf(errorval?"soft (%d)":"hard",errorval);
  697.                     printf(" read error\n");
  698.                     if (bflag && addbad(startsn+i)) 
  699.                         i--;    /* retry */
  700.                     else
  701.                         badmap[i] = 1;
  702.                 }
  703.             } while (++i < st.nsect);
  704.         } while (--readpass > 0);
  705.     }
  706. }
  707.  
  708. /*
  709.  * Obtain device-specific data and set up `st' structure
  710.  */
  711. get_devdata()
  712. {
  713.     register struct st *s;
  714.     register struct disktab *d;
  715.     struct iogstat gs;
  716.  
  717.     if (ioctl(dfd,DKIOGSTAT,(char *)&gs) < 0) 
  718.         quit(EX_UNAVAILABLE,"cannot get drive status of %s\n",diskdevice);
  719.     if (!gs.iogs_online) 
  720.         quit(EX_IOERR,"%s: not online\n",diskdevice);
  721.     s = &disktypes[0];
  722.     do {
  723.         if (strcmp(gs.iogs_vname,s->vname) == 0) {
  724.             bcopy((char *)s,(char *)&st,sizeof st);
  725.             goto calc0;
  726.         }
  727.     } while ((++s)->vname[0]);
  728.     /*
  729.      * Cannot find a description of the disk in my tables,
  730.      * so try Getdiskbyname() to see if it knows anything
  731.      */
  732.     s = &st;        /* use defaults */
  733.     bcopy(gs.iogs_vname,s->vname,sizeof s->vname - 1);
  734.     if ((d = getdiskbyname(gs.iogs_vname)) == 0) 
  735.         quit(EX_OSFILE,"cannot get `disktab' information for `%s' disk\n",gs.iogs_vname);
  736.     s->sectsize = d->d_secsize;
  737.     s->nsect = d->d_nsectors;
  738.     s->ntrack = d->d_ntracks;
  739.     s->ncyl = d->d_ncylinders;
  740.     s->nspc = s->nsect * s->ntrack;    /* sectors per cylinder */
  741. calc0:    /*
  742.      * Sector number of first copy of bad sector table, per DEC Std 144.
  743.      * This is the first sector of the last track
  744.      */
  745.     s = &st;
  746.     s->bad0sn = s->ncyl * s->nspc - s->nsect;
  747. }
  748.  
  749. /*
  750.  * Initialize the in-core copy of the bad sector table:
  751.  *    1.  install pack serial number
  752.  *    2.  mark all bad sector slots as unused (all 1's) 
  753.  */
  754. initbst(packsn)
  755.     int packsn;        /* serial number for pack */
  756. {
  757.     register struct bt_bad *be;
  758.  
  759.     bst.bt_csn = packsn;
  760.     bst.bt_mbz = 0;
  761.     bst.bt_flag = 0;
  762.     be = &bst.bt_bad[0];
  763.     do {
  764.         be->bt_cyl = short_ones;
  765.         be->bt_trksec = short_ones;
  766.     } while (++be < &bst.bt_bad[MAXNUMBAD]);
  767.     bsi++;
  768. }
  769.  
  770. /*
  771.  * Write good headers to every sector on the disk, a whole track at a time
  772.  * including the last track where the bad sector file lives.
  773.  */
  774. initheaders()
  775. {
  776.     register daddr_t sn,cyli;
  777.  
  778.     cyli = st.ntrack * 100;    /* keep user entertained while I work */
  779.     sn = 0;
  780.     do {
  781.         if (wantout) {
  782.             printf("\nLast sector written: %d\n",sn - 1);
  783.             exit(EX_OK);
  784.         }
  785.         (*st.wheader)(sn,(int)st.nsect,WHDR_VALID);
  786.         if (--cyli <= 0) {
  787.             printf("cylinder %d\n", sn / st.nspc + 1);
  788.             cyli = st.ntrack * 100;
  789.         }
  790.     } while ((sn += st.nsect) < st.nspc * st.ncyl);
  791. }
  792.  
  793. /*
  794.  * Initialize a buffer with the requested pattern
  795.  */
  796. initpattern(bp,size,patno)
  797.     char *bp;    /* buffer to initialize */
  798.     int size;    /* size (bytes) */
  799.     int patno;    /* pattern number */
  800. {
  801.     register unsigned short *pp;
  802.     unsigned short patn;
  803.  
  804.     pp = (unsigned short *)bp;
  805.     patn = testpattern[patno];
  806.     printf("Write pattern %d = 0x%04x\n",patno,patn);
  807.     size /= sizeof patn;
  808.     do {
  809.         *pp++ = patn;
  810.     } while (--size > 0);
  811. }
  812.  
  813. /*
  814.  * Return the number of ECC errors corrected since the last call here
  815.  */
  816. numecc()
  817. {
  818.     register long lecc;
  819.     static long necc;
  820.     static int eccnotavail;
  821.  
  822.     if (eccnotavail) 
  823.         return 0;
  824.     lecc = necc;            /* previous count */
  825.     if (ioctl(dfd,DKIOGETECC,(char *)&necc) < 0) {
  826.         printf("WARNING: ECC COUNTS NOT AVAILABLE, LIMPING ALONG\n");
  827.         eccnotavail++;
  828.         return 0;
  829.     }
  830.     return necc - lecc;
  831. }
  832.  
  833. /*
  834.  * Printf a diagnostic message and exit
  835.  */
  836. /*VARARGS2*/
  837. quit(exitcode,fmt,args)
  838.     int exitcode;
  839.     char *fmt;
  840. {
  841.     _doprnt(fmt,&args,stdout);    /* tacky, tacky */
  842.     if (exitcode == EX_SOFTWARE) 
  843.         abort();        /* make core image for debugging */
  844.     exit(exitcode);
  845.     /* should *NEVER EVER* get here :-) */
  846. }
  847.  
  848. /*
  849.  * Read the bad sector table off the pack into core, and validate it
  850.  */
  851. readbst()
  852. {
  853.     register int n;
  854.     register struct bt_bad *e;
  855.     int active;
  856.     daddr_t btabsn, cursn, lastsn;
  857.  
  858.     btabsn = st.bad0sn;    /* where the first copy of the table is */
  859.     n = 5;            /* 5 copies, per DEC std 144 */
  860.     while (bread(btabsn,(char *)&bst,sizeof bst) < 0) {
  861.         printf("WARNING: CANNOT READ BAD SECTOR TABLE (sn%d)\n",btabsn);
  862.         btabsn += 2;    /* try another copy */
  863.         if (--n <= 0) {
  864.             /*
  865.              * If I can't read the current bad sector table,
  866.              * I can't augment it now, can I?
  867.              */
  868.             printf("\n\
  869. You might have to re-format the *WHOLE* disk with `badm wbi'\n");
  870.             exit(EX_IOERR);
  871.         }
  872.     }
  873.     printf("Bad sector table read from sn%d\n",btabsn);
  874.     /*
  875.      * Validate the contents per these rules:
  876.      *    o  Active slots, if any, must be clustered at the
  877.      *       beginning of the table, and inactive slots at the end
  878.      *    o  Cylinder, track, and sector numbers must be within
  879.      *       the legal ranges for the type of disk I'm working on
  880.      *    o  Bad sector entries must be in order of ascending
  881.      *       disk addresses
  882.      */
  883.     e = &bst.bt_bad[0];
  884.     active = 1;            /* in active region of table */
  885. #ifdef lint
  886.     lastsn = 0;            /* avoid lint complaint */
  887. #endif
  888.     do {
  889.         cursn = btsector(e);    /* convert entry to sector number */
  890.         if (cursn == BTINVALID) 
  891.             quit(EX_DATAERR,"Entry %d: illegal disk address, cyl=%x trksec=%x\n",
  892.                 e - &bst.bt_bad[0], e->bt_cyl, e->bt_trksec);
  893.         if (cursn == BTEMPTY) 
  894.             active = 0;
  895.         else {
  896.             if (!active ||
  897.                 e > &bst.bt_bad[0] && cursn <= lastsn) 
  898.                 quit(EX_DATAERR,"Entry %d: out of order\n",
  899.                     e - &bst.bt_bad[0]);
  900.             lastsn = cursn;
  901.         }
  902.     } while (++e < &bst.bt_bad[MAXNUMBAD]);
  903.     bsi++;        /* note that bst is set up */
  904. }
  905.  
  906. /*
  907.  * Random places on disk
  908.  */
  909. /*ARGSUSED*/
  910. daddr_t
  911. tort0(n)
  912.     daddr_t n;
  913. {
  914.     long random();
  915.  
  916.     return random() % (st.nspc * st.ncyl);
  917. }
  918.  
  919. /*
  920.  * Start at opposite ends of disk, then oscillate, closing in on center
  921.  */
  922. daddr_t
  923. tort1(n)
  924.     daddr_t n;
  925. {
  926.     register daddr_t cyl,dist;
  927.  
  928.     dist = n % st.ncyl >> 1;
  929.     cyl = n & 1 ? st.ncyl - dist - 1 : dist;
  930.     return cyl * st.nspc;
  931. }
  932.  
  933. /*
  934.  * Slam heads from end to end
  935.  */
  936. daddr_t
  937. tort2(n)
  938.     daddr_t n;
  939. {
  940.     /*
  941.      * 0x301 is about 1/4 as abusive as 0x001
  942.      */
  943.     if (n & 0x301) 
  944.         return (st.ncyl - 1) * st.nspc;
  945.     return 0;
  946. }
  947.  
  948. /*
  949.  * 4 close, large seek, 4 close, large seek ...
  950.  */
  951. daddr_t
  952. tort3(n)
  953.     register daddr_t n;
  954. {
  955.     register daddr_t cyl;
  956.     static daddr_t tab4[4] = { 0, 2, 1, 3 };
  957.  
  958.     cyl = tab4[n & 3] + (n >> 3) % (st.ncyl - 8 >> 1);
  959.     if (n & 4) 
  960.         cyl += st.ncyl >> 1;
  961.     return cyl * st.nspc;
  962. }
  963.  
  964. usage()
  965. {
  966.     fprintf(stderr,"Usage:\n\
  967. badm r DISKDEVICE\n\
  968. \tread entire disk sequentially, scanning for errors and ECCs\n\
  969. \t(does not alter disk)\n");
  970.     fprintf(stderr,"\n\
  971. badm t DISKDEVICE\n\
  972. \tread-only torture test for disk arm\n");
  973.     fprintf(stderr,"\n\
  974. badm w[bi] DISKDEVICE [ PACKSN ]\n\
  975. \tw    write and readback test patterns (bashes filesystems!)\n\
  976. \twb   same as `w', and augments bad sector table\n\
  977. \twbi  same as `wb', and clears all headers and bad sector tables first\n\
  978. \t     (decimal pack serial number PACKSN required with `wbi')\n\
  979. ");
  980.     fprintf(stderr,"\n\
  981. badm a DISKDEVICE SECTORNO [ SECTORNO ... ]\n\
  982. \tadd specified sectors to the bad sector table\n\
  983. ");
  984.     fprintf(stderr,"\n\
  985. DISKDEVICE is the device name and unit number, like `hp1'\n\
  986. SECTORNO is a decimal sector number\n\
  987. *** READ THE CAUTIONS IN THE MANUAL ENTRY FIRST!!! ***\n\
  988. ");
  989.     exit(EX_USAGE);
  990. }
  991.  
  992. char    nohmemmsg[] = "cannot get memory for header I/O\n";
  993.  
  994. /*
  995.  * Sector header I/O for RM-class MASSBUS disks (incl. Eagle) 
  996.  */
  997. whdr_rm(sn,nb,type)
  998.     daddr_t sn;        /* disk sector number */
  999.     int nb;            /* number of sectors */
  1000.     int type;        /* WHDR_xxx */
  1001. {
  1002.     static struct rmhdrbuf {
  1003.         unsigned short hdr1;
  1004.         char h2sector;
  1005.         char h2track;
  1006.         char pad[512];
  1007.     } *ebuf;
  1008.     register struct rmhdrbuf *e;
  1009.     register int i;
  1010.  
  1011.     if ((e = ebuf) == 0) {
  1012.         e = (struct rmhdrbuf *)malloc(sizeof (struct rmhdrbuf) * (unsigned)st.nsect);
  1013.         if (e == 0) 
  1014.             quit(EX_OSERR,nohmemmsg);
  1015.         ebuf = e;
  1016.     }
  1017.     i = 0;
  1018.     do {
  1019.         e->hdr1 = 1 << 12;        /* 16-bit format */
  1020.         if (type == WHDR_VALID) 
  1021.             e->hdr1 |= 0xC000;    /* good (valid) sector */
  1022.         e->hdr1 |= (sn + i) / st.nspc;
  1023.         e->h2track = (sn + i) % st.nspc / st.nsect;
  1024.         e->h2sector = (sn + i) % st.nsect;
  1025.         e++;
  1026.     } while (++i < nb);
  1027.     if (ioctl(dfd,DKIOCHDR,(char *)0) < 0) {
  1028.         perror("DKIOCHDR");
  1029.         exit(EX_UNAVAILABLE);
  1030.     }
  1031. #ifdef HPBUG
  1032.     /*
  1033.      * Circumvent hp.c driver bug.  When testing to see if I/O will
  1034.      * tread beyond the end of the disk, hpstrategy() does not take
  1035.      * into account the fact that the sector size during header I/O
  1036.      * is 516 (not 512) bytes.  Thus, the driver rejects some
  1037.      * legitimate requests because it erroneously concludes that
  1038.      * they would result in a transfer beyond the end of the disk.
  1039.      *
  1040.      * The workaround here deducts the number of bytes consumed by
  1041.      * the headers (nb * 4) from the `right' (nb * 516) byte count;
  1042.      * this appeases hp.c, but it also results in a partial write to
  1043.      * the last sector of the bunch.  The partial write is harmless
  1044.      * here, since we care only about the headers and not about
  1045.      * anything else in the sectors.  The only possible problem can
  1046.      * occur if more than 512 bytes are deducted (i.e., nb > 128),
  1047.      * because that would eat into the header of the last sector.
  1048.      */
  1049.     if (nb > 128)        /* should never happen :-) */
  1050.         quit(EX_SOFTWARE,"\nSOFTWARE BUG: nb (%d) > 128\n",nb);
  1051.     if (bwrite(sn, (char *)ebuf, st.sectsize * nb) < 0) 
  1052. #else HPBUG
  1053.     if (bwrite(sn, (char *)ebuf, (char *)e - (char *)ebuf) < 0) 
  1054. #endif HPBUG
  1055.         printf("sn%d: HEADER WRITE FAILED, CONTINUING\n",sn);
  1056. }
  1057.  
  1058. /*
  1059.  * Sector header I/O for RP04/5/6 MASSBUS disks
  1060.  */
  1061. whdr_rp(sn,nb,type)
  1062.     daddr_t sn;        /* disk sector number */
  1063.     int nb;            /* number of sectors */
  1064.     int type;        /* WHDR_xxx */
  1065. {
  1066.     static struct rphdrbuf {
  1067.         unsigned short hdr1;
  1068.         char h2sector;
  1069.         char h2track;
  1070.         unsigned short keyfield1,keyfield2;
  1071.         char pad[512];
  1072.     } *ebuf;
  1073.     register struct rphdrbuf *e;
  1074.     register int i;
  1075.  
  1076.     if ((e = ebuf) == 0) {
  1077.         e = (struct rphdrbuf *)malloc(sizeof (struct rphdrbuf) * (unsigned)st.nsect);
  1078.         if (e == 0) 
  1079.             quit(EX_OSERR,nohmemmsg);
  1080.         ebuf = e;
  1081.     }
  1082.     i = 0;
  1083.     do {
  1084.         /*
  1085.          * Bad sector handling on RP04/5/6s is a kludge, since there
  1086.          * is no true hardware support (a la RM series drives).
  1087.          * The convention employed in badm and the kernel (hp.c) to
  1088.          * denote a bad sector is to clear 16-bit format (bit 12) 
  1089.          * in the header.  When reading accessing the sector, the
  1090.          * drive will report "format error", which hp.c assumes to
  1091.          * mean "RP0x bad sector".
  1092.          */
  1093.         e->hdr1 = 0;            /* invalid */
  1094.         if (type == WHDR_VALID) 
  1095.             e->hdr1 = 0x1000;    /* good (valid) sector */
  1096.         e->hdr1 |= (sn + i) / st.nspc;
  1097.         e->h2track = (sn + i) % st.nspc / st.nsect;
  1098.         e->h2sector = (sn + i) % st.nsect;
  1099.         e->keyfield1 = 0;        /* what are these for? */
  1100.         e->keyfield2 = 0;
  1101.         e++;
  1102.     } while (++i < nb);
  1103.     if (ioctl(dfd,DKIOCHDR,(char *)0) < 0) {
  1104.         perror("DKIOCHDR");
  1105.         exit(EX_UNAVAILABLE);
  1106.     }
  1107. #ifdef HPBUG
  1108.     /*
  1109.      * Circumvent hp.c driver bug.
  1110.      * See comments in whdr_rm() for explanation of this bug.
  1111.      * Sector size during header I/O for RP06 is 520 bytes
  1112.      * (512 sector data + 8 header).
  1113.      */
  1114.     if (nb > 512 / 8)        /* should never happen :-) */
  1115.         quit(EX_SOFTWARE,"\nSOFTWARE BUG: nb (%d) > 512 / 8\n",nb);
  1116.     if (bwrite(sn, (char *)ebuf, st.sectsize * nb) < 0) 
  1117. #else HPBUG
  1118.     if (bwrite(sn, (char *)ebuf, (char *)e - (char *)ebuf) < 0) 
  1119. #endif HPBUG
  1120.         printf("sn%d: HEADER WRITE FAILED, CONTINUING\n",sn);
  1121. }
  1122.  
  1123. /*ARGSUSED*/
  1124. whdr_unknown(sn,nb,type)
  1125.     daddr_t sn;        /* disk sector number */
  1126.     int nb;            /* number of sectors */
  1127.     int type;        /* WHDR_xxx */
  1128. {
  1129.     quit(EX_UNAVAILABLE,"don't know how to read/write headers on `%s' disks\n",st.vname);
  1130. }
  1131.  
  1132. /*
  1133.  * Write the bad sector table out to the disk
  1134.  *
  1135.  * Writes 5 copies, in the first 5 even-numbered sectors of the
  1136.  * last track of the last cylinder of the disk (per DEC Std 144) 
  1137.  *
  1138.  * Also informs the driver there's a new bad sector table, because some
  1139.  * drivers (e.g., hp.c) keep in-core copies, which are read only at bootup
  1140.  * or when the drive is spun up (i.e., when Volume-Valid is reset) 
  1141.  */
  1142. writebst()
  1143. {
  1144.     register int i;
  1145.     static int noioctl;
  1146.  
  1147.     /*
  1148.      * Write 5 copies, per DEC std 144
  1149.      */
  1150.     i = 0;
  1151.     do {
  1152.         if (bwrite(st.bad0sn + i * 2, (char *)&bst, sizeof bst) < 0) 
  1153.             printf("ERROR WRITING BAD TABLE %d, CONTINUING\n",i);
  1154.     } while (++i < 5);
  1155.     /*
  1156.      * Now tell the driver that the bad block table has been updated.
  1157.      * This is necessary because hp.c maintains an in-core copy of
  1158.      * this table (in "hpbad"), and, in order to do the job right,
  1159.      * the in-core copy must be accurate.
  1160.      */
  1161.     if (!noioctl && ioctl(dfd,DKIONEWBAD,(char *)0) < 0) {
  1162.         noioctl++;
  1163.         printf("WARNING: Cannot inform driver of new bad sector table\n");
  1164.     }
  1165. #ifdef HPBUG
  1166.     /*
  1167.      * Perform a gratuitous read operation to force driver to read
  1168.      * the bad sector table into the in-core "hpbad" table.
  1169.      * See explanation in Diskopen() for more details.
  1170.      */
  1171.     {
  1172.         char gbuf[512];
  1173.  
  1174.         (void) bread((daddr_t)0,gbuf,sizeof gbuf);
  1175.     }
  1176. #endif HPBUG
  1177. }
  1178. SHAR_EOF
  1179. echo shar: extracting badm.8
  1180. cat - << \SHAR_EOF > badm.8
  1181. .TH BADM 8 10/31/85
  1182. .SH NAME
  1183. badm \- disk formating and bad sector maintenance
  1184. .SH SYNOPSIS
  1185. .B badm w
  1186. diskdevice
  1187. .PP
  1188. .B badm wb
  1189. diskdevice
  1190. .PP
  1191. .B badm wbi
  1192. diskdevice packsn
  1193. .PP
  1194. .B badm r
  1195. diskdevice
  1196. .PP
  1197. .B badm t
  1198. diskdevice
  1199. .PP
  1200. .B badm a
  1201. diskdevice sectorno [ sectorno ... ]
  1202. .SH DESCRIPTION
  1203. .I Badm
  1204. gives the system administrator control over the bad sector information
  1205. on a disk pack.  Some of the salient features are:
  1206. .TP 3
  1207. \(bu
  1208. Comprehensive, thorough formating capability available under
  1209. timesharing, eliminating the need to devote an entire Vax
  1210. system for a disk format operation
  1211. .TP
  1212. \(bu
  1213. Read-only mode available to assist in locating deficient sectors
  1214. on the disk without disturbing filesystems
  1215. .TP
  1216. \(bu
  1217. Capability to add `johnny-come-lately' failing sectors to the bad
  1218. sector table without disturbing other data on the disk
  1219. .PP
  1220. In the following command descriptions, the
  1221. .I diskdevice
  1222. argument refers to a disk drive by type and unit number (e.g., `hp1'), and
  1223. .I sectorno
  1224. is a sector number on the disk, expressed as an unsigned integer.
  1225. .TP 3
  1226. .B w
  1227. Write and readback test patterns.  With no options, the
  1228. .B w
  1229. command writes a test pattern to every track of the disk and reads
  1230. each track after writing it.  Any hard errors or soft ECC errors
  1231. reported by the drive are also reported by
  1232. .IR badm .
  1233. If the
  1234. .B b
  1235. option is given,
  1236. .I badm
  1237. will also add all sectors with hard or soft errors to the bad
  1238. sector table on the disk and mark the headers of the failing
  1239. sectors as being bad.  If the
  1240. .B i
  1241. option is given,
  1242. .I badm
  1243. makes an initial pass over the disk, writing good headers on all
  1244. sectors of the disk and marking all entries in the bad sector table
  1245. as unused.  When invoking
  1246. .I badm
  1247. with the
  1248. .B i
  1249. option, the decimal serial number
  1250. .RI ( packsn )
  1251. of the disk must be included on the command line.  The function of
  1252. .B badm wbi
  1253. may be used in lieu of the traditional
  1254. .I format
  1255. procedure that the DEC VMS formater performs on new disks.
  1256. When invoked with the
  1257. .B w
  1258. command,
  1259. .I badm
  1260. will cycle forever through all its test patterns, writing the patterns
  1261. to the disk and reading them back.  Typing CTRL/C will exit the program.
  1262. .TP
  1263. .B r
  1264. This function simply reads the entire disk from beginning to end
  1265. ad infinitum, reporting soft ECC and hard errors to the user.
  1266. It does not modify anything on the disk, and is thus safe to run
  1267. at any time.  Type CTRL/C to exit.
  1268. .TP
  1269. .B t
  1270. Torture the disk drive by moving the arm through a series of positions,
  1271. ad infinitum.  This function does not alter any data on the disk.
  1272. Type CTRL/C to exit.
  1273. .TP
  1274. .B a
  1275. Each
  1276. .I sectorno
  1277. argument specifies (as a decimal number) a sector to be labeled as `bad'.
  1278. .I Badm
  1279. rewrites the sector header to indicate that the sector is `bad', adds the
  1280. the sector to the disk's bad sector table, and copies the contents of the
  1281. specified sector to its replacement sector.  If the contents of the sector
  1282. cannot be read,
  1283. .I badm
  1284. complains and fills the replacement sector with zeros.  This function is
  1285. useful for adding known failing sectors to the bad sector list without
  1286. incurring the risk and expense of reformating the entire disk.
  1287. .RB ( CAUTION:
  1288. See operational restrictions below about other disk activity while using
  1289. .IR badm .)
  1290. .PP
  1291. To format a brand new disk, use
  1292. .B badm
  1293. .BR wbi .
  1294. The longer
  1295. .I badm
  1296. runs, the higher the probability that all of the marginal sectors on
  1297. the disk have been classified as being `bad'.  The formating process
  1298. begun by
  1299. .B badm wbi
  1300. can be continued after interruption (CTRL/C, system crash, etc.) by
  1301. .B badm
  1302. .BR wb .
  1303. .PP
  1304. When invoked with the
  1305. .B w
  1306. command,
  1307. .I badm
  1308. prints a message whenever it begins writing a different test pattern
  1309. on the disk:
  1310. .PP
  1311. .ti +4
  1312. Write pattern N = 0xV
  1313. .PP
  1314. where
  1315. .I N
  1316. is the pattern number and
  1317. .I V
  1318. is the test data composing the pattern.  The pattern number,
  1319. .IR N ,
  1320. will count upward from 0; when it returns to 0, all patterns have been
  1321. written to the disk once.
  1322. .PP
  1323. When formating a disk, it is recommended to let
  1324. .I badm
  1325. write each of its test patterns on the disk at least once.  This may
  1326. take many hours, depending upon the size of the disk, but any time
  1327. invested in the formating process will pay off well in the long run.
  1328. If it is necessary to have a formated disk quickly, use
  1329. .B badm wbi
  1330. and type CTRL/C after
  1331. .I badm
  1332. has begun to write the first test pattern.
  1333. .SH OPERATIONAL RESTRICTIONS
  1334. It is
  1335. .I absolutely imperative
  1336. that no other I/O activity be permitted
  1337. on a disk that is being modified by the
  1338. .BR wb ,
  1339. .BR wbi ,
  1340. or
  1341. .B a
  1342. command to
  1343. .IR badm .
  1344. This means if the disk is a user disk, none of its areas may be mounted.
  1345. Also,
  1346. .I badm cannot be used at all
  1347. to modify a disk that is serving as a system disk; attempts to do so can
  1348. result in corruption of the filesystem and/or format information on the disk.
  1349. The proper technique for using
  1350. .I badm
  1351. on a pack that normally serves as a system disk is to boot UNIX from
  1352. another system disk and to operate on the target pack as a non-system disk.
  1353. .PP
  1354. .I Badm
  1355. should be used with the same care that one exercises when using
  1356. .IR mkfs (8).
  1357. .SH DIAGNOSTICS
  1358. .TP 5
  1359. BAD SECTOR TABLE IS FULL, CANNOT ADD
  1360. An attempt to place more than 126 bad sectors in the bad sector file failed.
  1361. DEC Standard 144 limits the number of `bad' blocks on a disk to 126.
  1362. Try reformating the disk completely
  1363. .RB ( badm
  1364. .BR wbi );
  1365. if this message appears again, the disk has too many bad spots and
  1366. should be returned to the vendor for replacement.
  1367. .TP
  1368. ALREADY IN BAD SECTOR TABLE (ALTERNATE IS BAD!)
  1369. .I Badm
  1370. detected a failure in a sector that is already marked as being bad.
  1371. This usually means that the alternate sector is failing as well; DEC
  1372. standard 144 does not deal well with this situation.
  1373. .TP
  1374. Write pattern N = 0xV
  1375. .I Badm
  1376. is beginning pass
  1377. .I N
  1378. over the disk, writing pattern
  1379. .I V
  1380. in all sectors of the disk.  (This message is informational only,
  1381. and indicates no problem.)
  1382. .TP
  1383. snS: {soft (E), hard} read error
  1384. .I Badm
  1385. detected a soft ECC (with
  1386. .I E
  1387. corrections) or a hard read error while reading sector
  1388. .IR S .
  1389. When operating in
  1390. .B w
  1391. mode,
  1392. .I badm
  1393. attempts to classify any sector exhibiting a read error as a `bad' sector.
  1394. This message is a normal consequence of the formating process.
  1395. .TP
  1396. WARNING: ECC COUNTS NOT AVAILABLE, LIMPING ALONG
  1397. The UNIX driver for the disk does not support the
  1398. .I ioctl
  1399. call to return the number of soft ECC correction counts.
  1400. The consequence of this is that
  1401. .I badm
  1402. cannot detect or act upon soft ECC errors on the disk.
  1403. Consult a system programmer.
  1404. .TP
  1405. WARNING: CANNOT READ BAD SECTOR TABLE (snS)
  1406. .I Badm
  1407. cannot read the bad sector file from sector number
  1408. .IR S .
  1409. There are five identical copies of the bad sector file; if the first
  1410. copy is unreadable,
  1411. .I badm
  1412. tries to read the other copies until it finds one that it can read.
  1413. If none of the copies can be read, the disk should be completely
  1414. reformated
  1415. .RB ( badm
  1416. .BR wbi ).
  1417. .TP
  1418. WARNING: Cannot inform driver of new bad sector table
  1419. The UNIX driver for the disk does not support the
  1420. .I ioctl
  1421. call to update the in-core copy of the bad block table.
  1422. Consult a system programmer.
  1423. .TP
  1424. Entry N: illegal disk address, cyl=X trksec=X
  1425. The bad sector table on the disk contains a disk address that is
  1426. not legal.  The entry number (from 0 to 125) is displayed, along
  1427. with the contents of the cylinder and track/sector fields.
  1428. This can be corrected by completely reformating the disk
  1429. .RB ( badm
  1430. .BR wbi ).
  1431. .TP
  1432. Entry N: out of order
  1433. Entries in the bad sector table on the disk must be appear in order
  1434. of ascending disk addresses.  Entry N in the bad sector table is
  1435. out of order.  This can be corrected by completely reformating the disk
  1436. .RB ( badm
  1437. .BR wbi ).
  1438. .PP
  1439. There are other, more self-explanatory diagnostics.
  1440. .PP
  1441. While
  1442. .I badm
  1443. is running, reports of hard and soft disk ECC errors may appear
  1444. at the Vax console.  These messages are normal; they indicate
  1445. that bad sectors are being identified and dealt with by
  1446. .IR badm .
  1447. .SH BUGS
  1448. .I Badm
  1449. updates the bad sector table of the disk; this is technically a violation
  1450. of DEC standard 144, which specifies that this information is recorded at
  1451. the time of manufacture.  In practice, however, there seem to be no
  1452. operational problems incurred by updating the bad sector table in the field.
  1453. .PP
  1454. The implementation of the
  1455. .B wb
  1456. and
  1457. .B wbi
  1458. functions of
  1459. .I badm
  1460. requires support from the UNIX kernel in the form of additional
  1461. .IR ioctl (2)
  1462. services.  These are currently available only for RM05, RP06, RP05,
  1463. RP04, and Eagle disks.
  1464. .SH SEE ALSO
  1465. bad144(8), badsect(8), format(8V)
  1466. .PP
  1467. DEC Standard 144
  1468. .PP
  1469. DEC EK-ORM05-UG-002 RM05 Disk Subsystem User Guide
  1470. .PP
  1471. Emulex SC7851001 SC780 Disk Controller Technical Manual
  1472. .SH AUTHOR
  1473. .nf
  1474. Rick Ace
  1475. New York Institute of Technology
  1476. Computer Graphics Laboratory
  1477. Old Westbury, NY 11568
  1478. .fi
  1479. SHAR_EOF
  1480. echo shar: extracting hp.diffs
  1481. cat - << \SHAR_EOF > hp.diffs
  1482. Modifications to 4.2bsd vaxmba/hp.c to support badm Rev 2.0.
  1483.  
  1484. These changes apply to vaxmba/hp.c bearing the identification
  1485.     /*    hp.c    6.2    83/09/25    */
  1486.  
  1487. Comments in brackets have been added to line-number markers to
  1488. help you locate the proper places to modify if your hp.c differs.
  1489. --------------------------------------------------------------------------
  1490. 36a37        [add file.h for symbol "FWRITE"]
  1491. > #include "../h/file.h"                /* BADM */
  1492. 207a209        [add new element at end of "struct hpst"]
  1493. >     char    vname[12];    /* BADM vendor's name for device */
  1494. 209,222c211,224    [add vendor name string to hpst initializers]
  1495. <     { 32,    5,    32*5,    823,    rm03_sizes,    3, 4 },    /* RM03 */
  1496. <     { 32,    19,    32*19,    823,    rm05_sizes,    3, 4 },    /* RM05 */
  1497. <     { 22,    19,    22*19,    815,    rp06_sizes,    3, 4 },    /* RP06 */
  1498. <     { 31,    14,     31*14,    559,    rm80_sizes,    3, 4 },    /* RM80 */
  1499. <     { 22,    19,    22*19,    411,    rp05_sizes,    3, 4 },    /* RP04 */
  1500. <     { 22,    19,    22*19,    411,    rp05_sizes,    3, 4 },    /* RP05 */
  1501. <     { 50,    32,    50*32,    630,    rp07_sizes,    7, 8 },    /* RP07 */
  1502. <     { 1,    1,    1,    1,    0,        0, 0 },    /* ML11A */
  1503. <     { 1,    1,    1,    1,    0,        0, 0 },    /* ML11B */
  1504. <     { 32,    40,    32*40,    843,    cdc9775_sizes,    3, 4 },    /* 9775 */
  1505. <     { 32,    10,    32*10,    823,    cdc9730_sizes,    3, 4 },    /* 9730 */
  1506. <     { 32,    16,    32*16,    1024,    capricorn_sizes,7, 8 },    /* Capricorn */
  1507. <     { 48,    20,    48*20,    842,    eagle_sizes,    7, 8 },    /* EAGLE */
  1508. <     { 32,    19,    32*19,    815,    ampex_sizes,    3, 4 },    /* 9300 */
  1509. ---
  1510. >     { 32,    5,    32*5,    823,    rm03_sizes,    3, 4, "rm03" },
  1511. >     { 32,    19,    32*19,    823,    rm05_sizes,    3, 4, "rm05" },
  1512. >     { 22,    19,    22*19,    815,    rp06_sizes,    3, 4, "rp06" },
  1513. >     { 31,    14,     31*14,    559,    rm80_sizes,    3, 4, "rm80" },
  1514. >     { 22,    19,    22*19,    411,    rp05_sizes,    3, 4, "rp04" },
  1515. >     { 22,    19,    22*19,    411,    rp05_sizes,    3, 4, "rp05" },
  1516. >     { 50,    32,    50*32,    630,    rp07_sizes,    7, 8, "rp07" },
  1517. >     { 1,    1,    1,    1,    0,        0, 0, "ml11a" },
  1518. >     { 1,    1,    1,    1,    0,        0, 0, "ml11b" },
  1519. >     { 32,    40,    32*40,    843,    cdc9775_sizes,    3, 4, "9775" },
  1520. >     { 32,    10,    32*10,    823,    cdc9730_sizes,    3, 4, "9730" },
  1521. >     { 32,    16,    32*16,    1024,    capricorn_sizes,7, 8, "capricorn" },
  1522. >     { 48,    20,    48*20,    842,    eagle_sizes,    7, 8, "eagle" },
  1523. >     { 32,    19,    32*19,    815,    ampex_sizes,    3, 4, "9300" },
  1524. 241a244        [add new element at end of "struct hpsoftc"]
  1525. >     long    sc_ecccnt;    /* BADM ECC correction count */
  1526. 730a734,737    [add automatic variables in hpioctl()]
  1527. >     register int unit = minor(dev) >> 3;        /* BADM */
  1528. >     register struct iogstat *d;            /* BADM */
  1529. >     struct mba_device *mi;                /* BADM */
  1530. >     int ds;                        /* BADM */
  1531. 737a745,767    [add new cases to switch in hpioctl()]
  1532. >     case DKIOGETECC:                    /* BADM */
  1533. >         *(long *)data = hpsoftc[unit].sc_ecccnt;    /* BADM */
  1534. >         return 0;                    /* BADM */
  1535. >     case DKIOGSTAT:                        /* BADM */
  1536. >         mi = hpinfo[unit];                /* BADM */
  1537. >         bzero(data, sizeof (struct iogstat));        /* BADM */
  1538. >         d = (struct iogstat *)data;            /* BADM */
  1539. >         d->iogs_areasize = hpst[mi->mi_type].sizes[minor(dev)&7].nblocks; /* BADM */
  1540. >         bcopy(hpst[mi->mi_type].vname,d->iogs_vname,sizeof d->iogs_vname); /* BADM */
  1541. >         ds = ((struct hpdevice *)mi->mi_drv)->hpds;    /* BADM */
  1542. >         if (ds & HPDS_MOL)                 /* BADM */
  1543. >             d->iogs_online++;            /* BADM */
  1544. >         if (ds & HPDS_WRL)                 /* BADM */
  1545. >             d->iogs_writelock++;            /* BADM */
  1546. >         return 0;                    /* BADM */
  1547. >     case DKIONEWBAD:                    /* BADM */
  1548. >         if ((flag & FWRITE) == 0)             /* BADM */
  1549. >             return EBADF;                /* BADM */
  1550. >         hpsoftc[unit].sc_hpinit = 0;            /* BADM */
  1551. >         return 0;                    /* BADM */
  1552. 791a822        [add to hpecc() after statement "bit -= 8;"]
  1553. >             hpsoftc[mi->mi_unit].sc_ecccnt++;    /* BADM */
  1554. 848c879        [repair bug in hpecc()]
  1555. <     mi->mi_tab.b_errcnt = 0;    /* error has been corrected */
  1556. ---
  1557. >     mi->mi_tab.b_errcnt--;        /* error has been corrected */
  1558. SHAR_EOF
  1559. echo shar: extracting dkio.add
  1560. cat - << \SHAR_EOF > dkio.add
  1561. /*
  1562.  * Additions to vax/dkio.h to support "badm" disk formater
  1563.  */
  1564.  
  1565. #define DKIOGSTAT    _IOR(d, 2, struct iogstat)    /* get device status */
  1566. #define DKIOGETECC    _IOR(d, 3, long)        /* disk ECC count */
  1567. #define DKIONEWBAD    _IO(d, 4)            /* new bad sec table */
  1568.  
  1569. struct iogstat {
  1570.     long    iogs_areasize;        /* size of disk area (512-byte units) */
  1571.     char    iogs_online;        /* 0 = offline, non-zero = online */
  1572.     char    iogs_writelock;        /* non-zero = write locked */
  1573.     char    iogs_vname[12];        /* null-terminated vendor device name */
  1574. };
  1575. SHAR_EOF
  1576.  
  1577.  
  1578.