Annotation of cci/sys/stand/vdformat.c, revision 1.1

1.1     ! root        1: /*
        !             2: ** format disk on VDDC / SMD_E controller - (fsd/smd/xfd/xsd) type 
        !             3: **
        !             4: ** Author:     John R. Franks
        !             5: **
        !             6: **     This program is used to maintain drives attached to a VDDC controller.
        !             7: ** The basic functions are 1) format media,  2) verify media, 3) relocate
        !             8: ** bad blocks that have appeared on the media, and 4) Format and initialize the
        !             9: ** maintenance cylinders on the drive.
        !            10: **
        !            11: **     For in depth information on the structure of this program please refer
        !            12: ** to the comments above the individual subroutines in addition to the design
        !            13: ** notes in vdutil.doc.
        !            14: */
        !            15: 
        !            16: #include       <setjmp.h>
        !            17: #include       "../machine/mtpr.h"
        !            18: #include       "../h/param.h"
        !            19: #include       "../h/inode.h"
        !            20: #include       "../h/fs.h"
        !            21: #include       "../vba/vddc.h"
        !            22: #include       "../stand/saio.h"
        !            23: 
        !            24: #define        MAXCONTROLLER   4
        !            25: #define        MAXDRIVE        16
        !            26: 
        !            27: #define        NUMMNT          2
        !            28: #define        NUMREL          3
        !            29: #define        NUMSYS          (NUMREL+NUMMNT)
        !            30: 
        !            31: #define        TRUE            1
        !            32: #define        FALSE   0
        !            33: 
        !            34: #define        MAXTRKS         24
        !            35: #define        MAXSECS_PER_TRK 48
        !            36: #define        MAXERR          1000
        !            37: #define SECSIZ         512
        !            38: #define        TRKSIZ          ((SECSIZ/sizeof(long)) * MAXSECS_PER_TRK)
        !            39: 
        !            40: #define        HARD_ERROR      (DRVNRDY | INVDADR | DNEMEM | PARERR | OPABRT | \
        !            41:                         WPTERR | DSEEKERR | NOTCYLERR)
        !            42: #define DATA_ERROR     (CTLRERR | UCDATERR | DCOMPERR | DSERLY | DSLATE | \
        !            43:                         TOPLUS | TOMNUS | CPDCRT | \
        !            44:                         HRDERR | SFTERR)
        !            45: #define HEADER_ERROR   (HCRCERR | HCMPERR)
        !            46: #define        NRM             (short)0
        !            47: #define        BAD             (short)VDUF
        !            48: #define WPT            (short)(NRM | VDWPT)
        !            49: #define RELOC_SECTOR   (short)(VDALT)
        !            50: #define        ALT_SECTOR      (short)(VDALT)
        !            51: 
        !            52: static jmp_buf environ;
        !            53: 
        !            54: /* Free bad block allocation bit map */
        !            55: typedef struct {
        !            56:        long    error;
        !            57:        enum    {ALLOCATED, NOTALLOCATED} freestatus;
        !            58: } fmt_free;
        !            59: 
        !            60: 
        !            61: 
        !            62: typedef enum {SINGLE_SECTOR, FULL_TRACK} rel_type;
        !            63: 
        !            64: typedef struct {
        !            65:        dskadr  err_adr;
        !            66:        long    err_stat;
        !            67: } fmt_err;
        !            68: 
        !            69: static fmt_free        free[NUMREL*MAXTRKS][MAXSECS_PER_TRK];
        !            70: static fmt_err dsk_err[MAXERR];/* Disk error table */
        !            71: static fmt_mdcb        mdcb;           /* Master device control block */
        !            72: static fmt_dcb dcb;            /* Device control blocks */
        !            73: static int     bad_secs = 0;   /* Sequence # of last error detected */
        !            74: static cdr     *controller_address;    /* controller physical address */
        !            75: static int     ctlr_num = 0;   /* ctlr number */
        !            76: static int     unit_number = 0;        /* unit number */
        !            77: static int     drive_type;     /* disk type index */
        !            78: static char    *drive_name;
        !            79: static int     verify_count = 16;
        !            80: static char    *stars = "***************";
        !            81: static char    *sure_question = "This is DESTRUCTIVE!  Are you sure";
        !            82: static char    *operation_string = 0;
        !            83: static char    *format_string = "Formatting";
        !            84: static char    *scan_string = "Scanning";
        !            85: static char    *relocate_string = "Relocation";
        !            86: static char    drives_to_do[MAXCONTROLLER][MAXDRIVE];
        !            87: static char    ctlr_type[MAXCONTROLLER] =
        !            88:                    {UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN};
        !            89: static char    *controller_name[MAXCONTROLLER] =
        !            90:                    {"Unknown","Unknown","Unknown","Unknown"};
        !            91: 
        !            92: static long    pattern_0[TRKSIZ],  pattern_1[TRKSIZ];
        !            93: static long    pattern_2[TRKSIZ],  pattern_3[TRKSIZ];
        !            94: static long    pattern_4[TRKSIZ],  pattern_5[TRKSIZ];
        !            95: static long    pattern_6[TRKSIZ],  pattern_7[TRKSIZ];
        !            96: static long    pattern_8[TRKSIZ],  pattern_9[TRKSIZ];
        !            97: static long    pattern_10[TRKSIZ], pattern_11[TRKSIZ];
        !            98: static long    pattern_12[TRKSIZ], pattern_13[TRKSIZ];
        !            99: static long    pattern_14[TRKSIZ], pattern_15[TRKSIZ];
        !           100: 
        !           101: static long    *pattern_address[] = {
        !           102:        pattern_0,  pattern_1,  pattern_2,  pattern_3,
        !           103:        pattern_4,  pattern_5,  pattern_6,  pattern_7,
        !           104:        pattern_8,  pattern_9,  pattern_10, pattern_11,
        !           105:        pattern_12, pattern_13, pattern_14, pattern_15
        !           106: };
        !           107: 
        !           108: /* Double buffer for scanning existing file systems and general scratch */
        !           109: static long    scratch[TRKSIZ];
        !           110: static long    save[TRKSIZ];
        !           111: 
        !           112: static long    max_cyl;
        !           113: static long    max_trk;
        !           114: static long    max_sec;
        !           115: static long    sector_size;
        !           116: static long    num_slip;
        !           117: static int     max_drive;
        !           118: 
        !           119: /*
        !           120: **     Main, of course, is the entry point into vdfmt.  It is responsible
        !           121: ** for calling the routine for the get the disk parameters from the user,
        !           122: ** creating and initializing the bad block patterns for scanning the disk, and
        !           123: ** determining whether or not the user wants to format or relocate bad
        !           124: ** blocks before calling the appropriate routines.
        !           125: **
        !           126: **     Formatting implies cerification of media and creation of the maintenance
        !           127: ** cylinders and relocation of bad blocks.
        !           128: */
        !           129: 
        !           130: main()
        !           131: {
        !           132:        register int    index;
        !           133:        register int    (*operation)();
        !           134:        register int    controller, drive;
        !           135:        cdr             *controller_address;
        !           136:        int             (*get_operation_type())();
        !           137: 
        !           138:        printf("VDFORMAT  Version 2.\n\n");
        !           139:        /* Identify which controllers are present and what type they are. */
        !           140:        for(controller = 0; controller < MAXCONTROLLER; controller++) {
        !           141:                controller_address = (cdr *)(vddcaddr[controller]|IOBASE);
        !           142:                if(!badaddr(controller_address, 2)) {
        !           143:                        controller_address->cdr_reset = 0xffffffff;
        !           144:                        DELAY(1000000);
        !           145:                        if(controller_address->cdr_reset != 0xffffffff) {
        !           146:                                ctlr_type[controller] = SMDCTLR;
        !           147:                                controller_name[controller] = "SMD";
        !           148:                                DELAY(1000000);
        !           149:                        }
        !           150:                        else {
        !           151:                                ctlr_type[controller] = SMD_ECTLR;
        !           152:                                controller_name[controller] = "SMD/E";
        !           153:                                controller_address->cdr_reserved = 0x0;
        !           154:                                DELAY(3000000);
        !           155:                        }
        !           156:                        printf("Controller #%d is an %s disk controller.\n",
        !           157:                            controller, controller_name[controller]);
        !           158:                }
        !           159:                else
        !           160:                        ctlr_type[controller] = UNKNOWN;
        !           161:        }
        !           162:        /* Get operation type */
        !           163:        operation = get_operation_type();
        !           164:        /* Read user input about disk parameters */
        !           165:        get_disk_parameters();
        !           166:        for(controller=0; controller<MAXCONTROLLER; controller++) {
        !           167:                max_drive = (ctlr_type[controller] == SMDCTLR) ? 4 : 16;
        !           168:                for(drive=0; drive<max_drive; drive++)
        !           169:                        if(drives_to_do[controller][drive] != -1)
        !           170:                                do_operation(controller, drive, operation);
        !           171:        }
        !           172: }
        !           173: 
        !           174: /*
        !           175: **     Get_operation_type allows the user to choose which operation he / she
        !           176: ** wants to perform on all the drives selected.  It returns the address of that
        !           177: ** function.
        !           178: */
        !           179: 
        !           180: int (*get_operation_type())()
        !           181: {
        !           182:        extern int      format_operation();
        !           183:        extern int      scan_operation();
        !           184:        extern int      relocate_operation();
        !           185: 
        !           186:        for(;;) {
        !           187:                if(get_yes_no("Do you want to format media"))
        !           188:                        if(get_yes_no(sure_question)) {
        !           189:                                get_number_of_patterns();
        !           190:                                operation_string = format_string;
        !           191:                                return  format_operation;
        !           192:                        }
        !           193:                if(get_yes_no("Do you want to scan an existing file system for bad sectors")) {
        !           194:                        get_number_of_patterns();
        !           195:                        operation_string = scan_string;
        !           196:                        return scan_operation;
        !           197:                }
        !           198:                if(get_yes_no("Do you want to add bad sectors from manufacturer's list")) {
        !           199:                        operation_string = relocate_string;
        !           200:                        return relocate_operation;
        !           201:                }
        !           202:                printf("\nAn operation must be specified!\n\n");
        !           203:        }
        !           204: }
        !           205: 
        !           206: /*
        !           207: **     Get_number_of_patterns reads and validates and sets the number of
        !           208: ** patterns to use during a verification operation.  If no string was typed
        !           209: ** then the number of patterns defaults to four.
        !           210: */
        !           211: 
        !           212: get_number_of_patterns()
        !           213: {
        !           214:        char    count_string[10];
        !           215: 
        !           216:        for(;;) {
        !           217:                count_string[0] = (char)0;
        !           218:                printf("Number of patterns to use when verifying? [1-16]: (16) ");
        !           219:                gets(count_string);
        !           220:                if(count_string[0]) {
        !           221:                        sscanf(count_string, "%d", &verify_count);
        !           222:                        if ((verify_count >= 1) && (verify_count <= 16))
        !           223:                                break;
        !           224:                        printf("\nPattern count must be between 1 and 16.\n\n");
        !           225:                }
        !           226:                else {
        !           227:                        printf("\nDefaulting to 16 patterns.\n\n");
        !           228:                        verify_count = 16;
        !           229:                        break;
        !           230:                }
        !           231:        }
        !           232: }
        !           233: 
        !           234: /*
        !           235: **     This routine ask the user the controller number, unit number,
        !           236: ** and the drive type of the drive to be formatted.  When all information is
        !           237: ** gathered and correct, then, the open() system routine is called to initialize
        !           238: ** the controller and spin up drives if necessary.  If the open fails the whole
        !           239: ** process  is started over again.
        !           240: */
        !           241: 
        !           242: get_disk_parameters()
        !           243: {
        !           244:        register int    at_least_one_drive_specified = 0;
        !           245:        register int    controller, drive, type;
        !           246: 
        !           247:        for(controller = 0; controller < MAXCONTROLLER; controller++) {
        !           248:                max_drive = (ctlr_type[controller] == SMDCTLR) ? 4 : 16;
        !           249:                for(drive = 0; drive < max_drive; drive++)
        !           250:                        drives_to_do[controller][drive] = -1;
        !           251:        }
        !           252:        printf("\nEnter controller number and drive number for each disk.\n");
        !           253:        printf("Key <RETURN> to controller number prompt when through.\n");
        !           254:        for(;;) {
        !           255:                if((controller = get_controller_number()) != -1) {
        !           256:                        drive = get_drive_number(controller);
        !           257:                        type = get_drive_type(controller);
        !           258:                        printf("Is an '%s' drive on controller %d, unit %d ok",
        !           259:                            vdst[type].type_name, controller, drive);
        !           260:                        if(get_yes_no("")) {
        !           261:                                drives_to_do[controller][drive] = type;
        !           262:                                at_least_one_drive_specified = 1;
        !           263:                        }
        !           264:                        else
        !           265:                                printf("\nEntry ignored.\n");
        !           266:                        continue;
        !           267:                }
        !           268:                if(at_least_one_drive_specified)
        !           269:                        break;
        !           270:                printf("You must specify at least one controller number!\n");
        !           271:        }
        !           272: }
        !           273: 
        !           274: /*
        !           275: **     Get_controller_number reads, validates and returns a controller number.
        !           276: */
        !           277: 
        !           278: get_controller_number()
        !           279: {
        !           280:        char    controller[20];
        !           281:        int     controller_number;
        !           282:        int     i, controller_printed = FALSE;
        !           283: 
        !           284:        for(;;) {
        !           285:                printf("\nController number? [");
        !           286:                for(i=0; i<MAXCONTROLLER; i++)
        !           287:                        if(ctlr_type[i] != UNKNOWN) {
        !           288:                                if(controller_printed)
        !           289:                                        printf(", ");
        !           290:                                controller_printed = TRUE;
        !           291:                                printf("%d", i);
        !           292:                        }
        !           293:                printf("]: ");
        !           294:                gets(controller);
        !           295:                if(!controller[0])
        !           296:                        return -1;
        !           297:                if(!sscanf(controller, "%d", &controller_number)) {
        !           298:                        printf("\nResponse must start with a digit!\n");
        !           299:                        continue;
        !           300:                }
        !           301:                if ((controller_number >= 0) && (controller_number <= 3))
        !           302:                        if(ctlr_type[controller_number] != UNKNOWN)
        !           303:                                break;
        !           304:                printf("\nController number %d is illegal!\n",
        !           305:                    controller_number);
        !           306:        }
        !           307:        return controller_number;
        !           308: }
        !           309: 
        !           310: /*
        !           311: **     Get_drive_number reads, validates and returns a drive number.
        !           312: */
        !           313: 
        !           314: get_drive_number(controller)
        !           315: int    controller;
        !           316: {
        !           317:        char    drive_string[20];
        !           318:        int     drive, max_drive;
        !           319: 
        !           320:        for(;;) {
        !           321:                max_drive = (ctlr_type[controller] == SMDCTLR) ? 3 : 15;
        !           322:                printf("Unit number? [0-%d]: ", max_drive);
        !           323:                gets(drive_string);
        !           324:                if(!drive_string[0]) {
        !           325:                        printf("\nA drive number must be specified!\n\n");
        !           326:                        continue;
        !           327:                }
        !           328:                if(!sscanf(drive_string, "%d", &drive)) {
        !           329:                        printf("\nResponse must start with a digit!\n\n");
        !           330:                        continue;
        !           331:                }
        !           332:                if((drive >= 0) && (drive <= max_drive))
        !           333:                        break;
        !           334:                printf("\nDrive number %d is illegal!\n\n", drive);
        !           335:        }
        !           336:        return drive;
        !           337: }
        !           338: 
        !           339: /*
        !           340: **     Do_operation executes the function wanted on all drive in the to_to
        !           341: ** list.
        !           342: */
        !           343: 
        !           344: do_operation(controller, drive, operation)
        !           345: int    controller, drive;
        !           346: int    (*operation)();
        !           347: {
        !           348:        int     status;
        !           349: 
        !           350:        printf("\n%s %s on controller %d, drive %d, started. %s\n\n",
        !           351:            stars, operation_string, controller, drive, stars);
        !           352:        if(!(status = _setjmp(environ))) {
        !           353:                drive_name = "unknown";
        !           354:                init_environment_for_operation(controller, drive);
        !           355:                (*operation)();
        !           356:                printf("\n%s %s on controller %d, drive %d completed ok. %s\n",
        !           357:                    stars, operation_string, controller, drive, stars);
        !           358:                return;
        !           359:        }
        !           360:        printf("\n%s %s on controller %d, drive %d ABORTED!  %s\n",
        !           361:            stars, operation_string, controller, drive, stars);
        !           362:        return;
        !           363: }
        !           364: 
        !           365: /*
        !           366: **     Init_environment_for_operation reset all the variables used by the
        !           367: ** system to suit the new drive type.
        !           368: */
        !           369: 
        !           370: init_environment_for_operation(controller, drive)
        !           371: int    controller, drive;
        !           372: {
        !           373:        register int    index;
        !           374: 
        !           375:        ctlr_num = controller;
        !           376:        controller_address = (cdr *)(vddcaddr[controller]+IOBASE);
        !           377:        unit_number = drive;
        !           378:        drive_type = drives_to_do[controller][drive];
        !           379:        drive_name = vdst[drive_type].type_name;
        !           380:        max_cyl = vdst[drive_type].ncyl;
        !           381:        max_trk = vdst[drive_type].ntrak;
        !           382:        max_sec = vdst[drive_type].nsec;
        !           383:        sector_size = vdst[drive_type].secsize;
        !           384:        num_slip = vdst[drive_type].nslip;
        !           385:        bad_secs = 0;
        !           386:        /* Init bad block pattern array */
        !           387:        for(index=0; index<TRKSIZ; index++) {
        !           388:                pattern_0[index] = vdst[drive_type].fmt_pat[0];
        !           389:                pattern_1[index] = vdst[drive_type].fmt_pat[1];
        !           390:                pattern_2[index] = vdst[drive_type].fmt_pat[2];
        !           391:                pattern_3[index] = vdst[drive_type].fmt_pat[3];
        !           392:                pattern_4[index] = vdst[drive_type].fmt_pat[4];
        !           393:                pattern_5[index] = vdst[drive_type].fmt_pat[5];
        !           394:                pattern_6[index] = vdst[drive_type].fmt_pat[6];
        !           395:                pattern_7[index] = vdst[drive_type].fmt_pat[7];
        !           396:                pattern_8[index] = vdst[drive_type].fmt_pat[8];
        !           397:                pattern_9[index] = vdst[drive_type].fmt_pat[9];
        !           398:                pattern_10[index] = vdst[drive_type].fmt_pat[10];
        !           399:                pattern_11[index] = vdst[drive_type].fmt_pat[11];
        !           400:                pattern_12[index] = vdst[drive_type].fmt_pat[12];
        !           401:                pattern_13[index] = vdst[drive_type].fmt_pat[13];
        !           402:                pattern_14[index] = vdst[drive_type].fmt_pat[14];
        !           403:                pattern_15[index] = vdst[drive_type].fmt_pat[15];
        !           404:        }
        !           405:        spin_up_drive();
        !           406: }
        !           407: 
        !           408: /*
        !           409: **     Spin_up_drive starts the drives on a controller and waits around for
        !           410: ** the drive to spin up if it is not already spinning.
        !           411: */
        !           412: 
        !           413: spin_up_drive()
        !           414: {
        !           415:        VDDC_RESET(controller_address, ctlr_type[ctlr_num]);
        !           416:        if(ctlr_type[ctlr_num] == SMD_ECTLR) {
        !           417:                ((cdr *)controller_address)->cdr_csr =  0;
        !           418:                ((cdr *)controller_address)->mdcb_tcf =  AM_ENPDA;
        !           419:                ((cdr *)controller_address)->dcb_tcf =  AM_ENPDA;
        !           420:                ((cdr *)controller_address)->trail_tcf =  AM_ENPDA;
        !           421:                ((cdr *)controller_address)->data_tcf =  AM_ENPDA;
        !           422:                ((cdr *)controller_address)->cdr_ccf =  CCF_STS | XMD_32BIT |
        !           423:                    BSZ_16WRD | CCF_ERR | CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE;
        !           424:        }
        !           425:        access_with_no_trailer(INIT, 10);
        !           426:        access_with_no_trailer(DIAG, 20);
        !           427:        configure_drive(0);
        !           428: }
        !           429: 
        !           430: /*
        !           431: **     Access_with_no_trailer is used to perform controller functions which
        !           432: ** require no data movement.
        !           433: */
        !           434: 
        !           435: access_with_no_trailer(function, wait_time)
        !           436: int    function, wait_time;
        !           437: {
        !           438:        dcb.opcode = function;          /* command */
        !           439:        dcb.intflg = NOINT;
        !           440:        dcb.nxtdcb = (fmt_dcb *)0;      /* end of chain */
        !           441:        dcb.operrsta  = 0;
        !           442:        dcb.devselect = (function == VDSTART) ? 0 : (char)unit_number;
        !           443:        dcb.trailcnt = (char)0;
        !           444:        mdcb.firstdcb = &dcb;
        !           445:        mdcb.vddcstat = 0;
        !           446:        VDDC_ATTENTION(controller_address, &mdcb, ctlr_type[ctlr_num]); 
        !           447:        POLLTILLDONE(controller_address, &dcb, wait_time, ctlr_type[ctlr_num]);
        !           448:        if(vdtimeout <= 0) {
        !           449:                printf(" during startup operation.\n");
        !           450:                _longjmp(environ, 1);
        !           451:        }
        !           452:        return dcb.operrsta;
        !           453: }
        !           454: 
        !           455: /*
        !           456: **     Configure_drive tells the controller what kind of drive is attached
        !           457: ** on a particular line.
        !           458: */
        !           459: 
        !           460: configure_drive(pass)
        !           461: int    pass;
        !           462: {
        !           463:        dcb.opcode = RSTCFG;            /* command */
        !           464:        dcb.intflg = NOINT;
        !           465:        dcb.nxtdcb = (fmt_dcb *)0;      /* end of chain */
        !           466:        dcb.operrsta  = 0;
        !           467:        dcb.devselect = (char)unit_number;
        !           468:        dcb.trail.rstrail.ncyl = max_cyl;
        !           469:        dcb.trail.rstrail.nsurfaces = max_trk;
        !           470:        if(ctlr_type[ctlr_num] == SMDCTLR)
        !           471:                dcb.trailcnt = (char)2;
        !           472:        else {
        !           473:                dcb.trailcnt = (char)4;
        !           474:                dcb.trail.rstrail.nsectors = max_sec;
        !           475:                dcb.trail.rstrail.slip_sec = num_slip;
        !           476:        }
        !           477:        mdcb.firstdcb = &dcb;
        !           478:        mdcb.vddcstat = 0;
        !           479:        VDDC_ATTENTION(controller_address, &mdcb, ctlr_type[ctlr_num]);
        !           480:        POLLTILLDONE(controller_address, &dcb, 5, ctlr_type[ctlr_num]);
        !           481:        if(vdtimeout <= 0) {
        !           482:                printf(" during drive configuration.\n");
        !           483:                _longjmp(environ, 1);
        !           484:        }
        !           485:        if(dcb.operrsta & (NOTCYLERR | DRVNRDY)) {
        !           486:                if(pass) {
        !           487:                        printf("\nDrive failed to start!\n\n");
        !           488:                        _longjmp(environ, -1);
        !           489:                }
        !           490:                access_with_no_trailer(VDSTART, (unit_number*6)+62);
        !           491:                DELAY((unit_number * 5500000) + 62000000);
        !           492:                configure_drive(1);
        !           493:        }
        !           494: }
        !           495: 
        !           496: /*
        !           497: **     Get_drive_type reads a drive type, validates it and returns the
        !           498: ** validated drive type number to the calling routine.
        !           499: */
        !           500: 
        !           501: get_drive_type(controller)
        !           502: register int   controller;
        !           503: {
        !           504:        char    disk[10];
        !           505: 
        !           506:        for(;;) {
        !           507:                printf("Drive type? [fsd/smd/xfd");
        !           508:                if(ctlr_type[controller] == SMD_ECTLR)
        !           509:                        printf("/fuj/xsd");
        !           510:                printf("]: ");
        !           511:                gets(disk);
        !           512:                if (!strcmp(disk,"fsd"))
        !           513:                        return FSD;
        !           514:                if (!strcmp(disk,"smd"))
        !           515:                        return SMD;
        !           516:                if (!strcmp(disk,"xfd"))
        !           517:                        return XFD;
        !           518:                if(ctlr_type[controller] == SMD_ECTLR) {
        !           519:                        if (!strcmp(disk,"fuj"))
        !           520:                                return FUJ;
        !           521:                        if (!strcmp(disk,"xsd"))
        !           522:                                return XSD;
        !           523:                }
        !           524:                printf("Illegal drive type '%s'\n", disk); 
        !           525:        }
        !           526: }
        !           527: 
        !           528: /*
        !           529: **     Format_operation is the main routine for formatting a disk.
        !           530: ** Take note the the first operation must be format_data_area due to a micro-
        !           531: ** code bug in the controller.  While formatting sectors one sector count is
        !           532: ** lost every 64k sectors, so, on an fsd drive the last four sectors will
        !           533: ** not be formatted.  This is overcome by formatting the entire disk first, then
        !           534: ** formatting the maintenance area, which happens to cover the last n sectors
        !           535: ** that were lost.
        !           536: */
        !           537: 
        !           538: format_operation()
        !           539: {
        !           540:        /* Format relocation area and data area */
        !           541:        format_data_area();
        !           542:        /* Verify the reloaction area and data area */
        !           543:        verify_data_area();
        !           544:        if(bad_secs)
        !           545:                relocate_bad_blocks();
        !           546:        /* Format maintenance cylinders for field service */
        !           547:        lay_maint_cylinders();
        !           548: }
        !           549: 
        !           550: /*
        !           551: **     Relocate_operation() prompts the user for bad block numbers and adds
        !           552: ** to the current bad block table.  This process continues until a null response
        !           553: ** is typed in when prompted for a bad block.  The user is asked to verify that
        !           554: ** the block number typed in is really the block that they wanted to relocate
        !           555: ** before the tables are updated.
        !           556: */
        !           557: 
        !           558: relocate_operation()
        !           559: {
        !           560:        long    old_blk;
        !           561:        char    nxt_blk[20];
        !           562:        dskadr  daddr;
        !           563:        long    last_block = max_cyl * max_trk * max_sec;
        !           564: 
        !           565:        bad_secs = 0;
        !           566:        printf("Just key <RETURN>  when through entering sector numbers.\n");
        !           567:        while(bad_secs < MAXERR) {
        !           568:                printf("Sector number? ");
        !           569:                gets(nxt_blk);
        !           570:                if(!nxt_blk[0])
        !           571:                        break;
        !           572:                sscanf(nxt_blk, "%ld", &old_blk);
        !           573:                if(old_blk >= last_block) {
        !           574:                        printf("\nBlock number must be between 0 and %d!\n\n",
        !           575:                            last_block - 1);
        !           576:                        continue;
        !           577:                }
        !           578:                printf("Relocate sector #%ld", old_blk);
        !           579:                if(get_yes_no("")) {
        !           580:                        daddr.sector = old_blk % max_sec;
        !           581:                        daddr.track = (old_blk / max_sec) % max_trk;
        !           582:                        daddr.cylinder = (old_blk / max_sec) / max_trk;
        !           583:                        flag_sector(&daddr, 0);
        !           584:                }
        !           585:                else
        !           586:                        printf("\nEntry ignored.\n");
        !           587:                printf("\n");
        !           588:        }
        !           589:        relocate_bad_blocks();
        !           590: }
        !           591: 
        !           592: /*
        !           593: **
        !           594: */
        !           595: 
        !           596: scan_operation()
        !           597: {
        !           598:        register int    status, j=0;
        !           599:        dskadr          daddr;
        !           600:        register int    old_verify_count = verify_count;
        !           601: 
        !           602:        bad_secs = 0;
        !           603:        daddr.sector = 0;
        !           604:        for(daddr.cylinder=0;daddr.cylinder<(max_cyl-NUMSYS);daddr.cylinder++) {
        !           605:                if(j++ % 50) printf(".");
        !           606:                else printf("\n    Scanning cylinder %d.", (int)daddr.cylinder);
        !           607:                for(daddr.track = 0; daddr.track < max_trk; daddr.track++) {
        !           608:                        status = access(save, &daddr , FTR, 1, 1);
        !           609:                        if(status & (HRDERR | SFTERR))
        !           610:                                verify_count = 16;
        !           611:                        verify_track(&daddr);
        !           612:                        status = access(save, &daddr , FTW, 1, 1);
        !           613:                        verify_count = old_verify_count;
        !           614:                }
        !           615:        }
        !           616:        printf("\n");
        !           617:        print_bad_sector_list();
        !           618:        print_number_of_bad_sectors("file system");
        !           619:        if(bad_secs)
        !           620:                relocate_bad_blocks();
        !           621: }
        !           622: 
        !           623: /*
        !           624: **     This routine formats the user data area and bad block area of the disk.
        !           625: */
        !           626: 
        !           627: format_data_area()
        !           628: {
        !           629:        register long           sector_count;
        !           630:        dskadr                  zero;
        !           631:        register int            index;
        !           632: 
        !           633:        printf("Formatting media...\n");
        !           634:        zero.cylinder = (short)0;
        !           635:        zero.track = (char)0;
        !           636:        zero.sector = (char)0;
        !           637:        sector_count = (long)(max_cyl * max_trk * max_sec);
        !           638:        format_sectors(&zero, &zero, NRM, sector_count);
        !           639:        printf("Formatting complete.\n");
        !           640: }
        !           641: 
        !           642: /*
        !           643: **     This routine creates a bad block relocation area on disk and then
        !           644: ** certifies the user data area of the disk.
        !           645: */
        !           646: 
        !           647: verify_data_area()
        !           648: {
        !           649:        printf("Scanning for bad sectors...\n");
        !           650:        init_relocation_area();
        !           651:        verify_user_data_area();
        !           652:        printf("\nBad block scan complete.\n");
        !           653: }
        !           654: 
        !           655: /*
        !           656: **     Vdinit_relocation_area certifies the bad block relocation area and flags
        !           657: ** each bad block in the area as bad for later use by load_free_table().  No
        !           658: ** relocation takes place.
        !           659: */
        !           660: 
        !           661: init_relocation_area()
        !           662: {
        !           663:        printf("  Verifying bad sector relocation area...\n");
        !           664:        verify_cylinders((int)max_cyl - NUMSYS, NUMREL);
        !           665:        print_number_of_bad_sectors("relocation");
        !           666:        if(bad_secs)
        !           667:                mark_sectors_as_bad();
        !           668:        printf("  Relocation area verified.\n");
        !           669: }
        !           670: 
        !           671: /*
        !           672: **     This routine certifies the area to be used for user data.
        !           673: */
        !           674: 
        !           675: verify_user_data_area()
        !           676: {
        !           677:        int     temp;
        !           678:        
        !           679:        printf("  Verifying file system area...\n");
        !           680:        verify_cylinders(0, (int)(max_cyl-NUMSYS));
        !           681:        print_number_of_bad_sectors("file system");
        !           682:        printf("  File system area verified.\n");
        !           683: }
        !           684: 
        !           685: /*
        !           686: **     Vdlay_maint_cylinders creates the maintenance cylinders for field
        !           687: ** service techs to run diagnostics on.
        !           688: */
        !           689: 
        !           690: lay_maint_cylinders()
        !           691: {
        !           692:        dskadr          daddr;
        !           693:        register long   *pattern_ptr = (long *)&daddr;
        !           694:        register int    index;
        !           695:        
        !           696:        printf("Creating maintenance cylinders...\n");
        !           697:        /* format read only cylinder */
        !           698:        daddr.cylinder = (short)(max_cyl - NUMMNT);
        !           699:        daddr.track = daddr.sector = (char)0;
        !           700:        format_sectors(&daddr, &daddr, NRM, (long)(NUMMNT * max_trk * max_sec));
        !           701:        printf("  Verifying maintenance area...\n");
        !           702:        verify_cylinders(daddr.cylinder, NUMMNT);
        !           703:        print_number_of_bad_sectors("maintenance");
        !           704:        printf("  Maintenance area verified.\n");
        !           705:        printf("  Writing Read / Write patterns.\n");
        !           706:        daddr.cylinder = (short)(max_cyl - NUMMNT);
        !           707:        for(daddr.track=0; daddr.track<max_trk; daddr.track++)
        !           708:                for(daddr.sector=0; daddr.sector<max_sec; daddr.sector++)
        !           709:                        if(is_bad(&daddr)) {
        !           710:                                extern rel_type new_location();
        !           711:                                rel_type        type;
        !           712:                                dskadr          naddr;
        !           713: 
        !           714:                                type = new_location(&daddr, &naddr,
        !           715:                                    dsk_err[index].err_stat);
        !           716:                                relocate(&daddr, &naddr, type);
        !           717:                        }
        !           718:        printf("  Writing Read only patterns.\n");
        !           719:        for(daddr.cylinder++; daddr.cylinder<max_cyl; daddr.cylinder++) {
        !           720:                for(daddr.track=0; daddr.track<max_trk; daddr.track++)
        !           721:                        for(daddr.sector = 0; daddr.sector < max_sec;
        !           722:                            daddr.sector++) {
        !           723:                                for(index=0; index<(sector_size/sizeof(long)); index++)
        !           724:                                        scratch[index] = *pattern_ptr;
        !           725:                                if(is_bad(&daddr))
        !           726:                                        mark_bad_sector(&daddr, (short)VDWPT);
        !           727:                                else
        !           728:                                        format_sectors(&daddr,&daddr,WPT,(long)1);
        !           729:                        }
        !           730:        }
        !           731:        printf("Maintenance cylinders complete.\n");
        !           732: }
        !           733: 
        !           734: /*
        !           735: **     Is_bad checks to see if a block is known to be bad already.
        !           736: */
        !           737: 
        !           738: is_bad(daddr)
        !           739: dskadr *daddr;
        !           740: {
        !           741:        register int    index;
        !           742: 
        !           743:        for(index=0; index<bad_secs; index++)
        !           744:                if(daddr->cylinder == dsk_err[index].err_adr.cylinder)
        !           745:                        if(daddr->track == dsk_err[index].err_adr.track)
        !           746:                                if(daddr->sector==dsk_err[index].err_adr.sector)
        !           747:                                        return 1;
        !           748:        return 0;
        !           749: }
        !           750: 
        !           751: /*
        !           752: **     verify_cylinders does full track certification for every track
        !           753: ** on the cylinder.  This is done for speed and minimal head movement.  If
        !           754: ** an error occurs on any single track the track is flagged for later
        !           755: ** verification by verify sectors.
        !           756: */
        !           757: 
        !           758: verify_cylinders(base_cyl, cyl_count)
        !           759: int    base_cyl, cyl_count;
        !           760: {
        !           761:        register int    i, j = 0;
        !           762:        dskadr          daddr;
        !           763: 
        !           764:        bad_secs = 0;
        !           765:        /* verify each track of each cylinder */
        !           766:        for (daddr.cylinder=base_cyl; daddr.cylinder<(base_cyl+cyl_count);
        !           767:            daddr.cylinder++) {
        !           768:                if(j++ % 50) printf(".");
        !           769:                else printf("\n    Scanning cylinder %d.", (int)daddr.cylinder);
        !           770:                for (daddr.track = 0; daddr.track < max_trk; daddr.track++) {
        !           771:                        verify_track(&daddr);
        !           772:                }
        !           773:        }
        !           774:        printf("\n");
        !           775:        print_bad_sector_list();
        !           776: }
        !           777: 
        !           778: /*
        !           779: **     verify_track verifies a single track. If the full track write and
        !           780: ** compare operation fails then each sector is read individually to determin
        !           781: ** which sectors are really bad.  If a sector is bad it is flagged as bad by
        !           782: ** the verify sector routine.
        !           783: */
        !           784: 
        !           785: verify_track(daddr)
        !           786: dskadr *daddr;
        !           787: {
        !           788:        register int    index, i;
        !           789:        register int    count;
        !           790:        register long   before;
        !           791:        register long   *after;
        !           792:        register int    status;
        !           793:        register long   offset = sector_size / sizeof(long);
        !           794:        int             pattern_count = verify_count;
        !           795: 
        !           796:        daddr->sector = (char)0;
        !           797:        access(pattern_address[0], daddr, FTW, 1, 1);
        !           798:        for(index = 0; index < pattern_count; index++) {
        !           799:                data_ok(dcb.operrsta);
        !           800:                if(dcb.operrsta & HEADER_ERROR)  {
        !           801:                        if(ctlr_type[ctlr_num]==SMDCTLR)
        !           802:                                goto hard;
        !           803:                        flag_sector(daddr, dcb.operrsta);
        !           804:                        break;
        !           805:                }
        !           806:                if(status & DATA_ERROR)
        !           807:                        pattern_count = 16;
        !           808:                status = access(scratch, daddr, FTR, 1, 1);
        !           809:                if(status & HEADER_ERROR) {
        !           810:                        if(ctlr_type[ctlr_num]==SMDCTLR)
        !           811:                                goto hard;
        !           812:                        flag_sector(daddr, status);
        !           813:                        break;
        !           814:                }
        !           815:                if(!data_ok(status)) {
        !           816:                        pattern_count = 16;
        !           817:                        for(i = 0; i < max_sec; i++) {
        !           818:                                register long   *next;
        !           819: 
        !           820:                                daddr->sector = i;
        !           821:                                next = &scratch[i * offset];
        !           822:                                status = access(next, daddr, RD, 1, 1);
        !           823:                                if(!data_ok(status))
        !           824:                                        flag_sector(daddr, status);
        !           825:                        }
        !           826:                        daddr->sector = (char)0;
        !           827:                }
        !           828:                if(index+1 < pattern_count)
        !           829:                        access(pattern_address[index+1], daddr, FTW, 1, 0);
        !           830:                count = max_sec * offset;
        !           831:                before = *pattern_address[index];
        !           832:                after = scratch;
        !           833:                mtpr(0, PADC);
        !           834:                for(i=0; i<count; i++) {
        !           835:                        if(before != *(after++)) {
        !           836:                                daddr->sector = i / offset;
        !           837:                                flag_sector(daddr, 0);
        !           838:                        }
        !           839:                }
        !           840:                POLLTILLDONE(controller_address, &dcb, 60, ctlr_type[ctlr_num]);
        !           841:                if(vdtimeout <= 0) {
        !           842:                        printf(" in verify_track.\n");
        !           843:                        _longjmp(environ, 1);
        !           844:                }
        !           845:        }
        !           846:        return;
        !           847: 
        !           848: hard:  printf("\nSMD Controllers can't recover from header errors!");
        !           849:        printf("  Status = 0x%x\n", dcb.operrsta);
        !           850:        _longjmp(environ, dcb.operrsta);
        !           851: }
        !           852: 
        !           853: /*
        !           854: **     Vdflag_sector makes an entry into the bad block table for the current
        !           855: ** bad sector.
        !           856: */
        !           857: 
        !           858: flag_sector(daddr, status)
        !           859: dskadr *daddr;
        !           860: long   status;
        !           861: {
        !           862:        register int    index;
        !           863: 
        !           864:        if(bad_secs < MAXERR) {
        !           865:                for(index=0; index<bad_secs; index++)
        !           866:                        if((dsk_err[index].err_adr.cylinder==daddr->cylinder) &&
        !           867:                            (dsk_err[index].err_adr.track == daddr->track) &&
        !           868:                            (dsk_err[index].err_adr.sector==daddr->sector))
        !           869:                                                return;
        !           870:                dsk_err[bad_secs].err_adr.cylinder = daddr->cylinder;
        !           871:                dsk_err[bad_secs].err_adr.track = daddr->track;
        !           872:                dsk_err[bad_secs].err_adr.sector = daddr->sector;
        !           873:                dsk_err[bad_secs++].err_stat = status;
        !           874:                return;
        !           875:        }
        !           876:        printf("Maximum number of %d bad tracks exceeded!\n", MAXERR);
        !           877:        _longjmp(environ, MAXERR);
        !           878: }
        !           879: 
        !           880: /*
        !           881: **     Print_bad_sector list tells the user which sectors are bad.
        !           882: */
        !           883: 
        !           884: print_bad_sector_list()
        !           885: {
        !           886:        register int    index;
        !           887:        register int    sec;
        !           888:        dskadr  daddr;
        !           889: 
        !           890:        if(bad_secs) {
        !           891:                printf("    The following sector");
        !           892:                if(bad_secs == 1)
        !           893:                        printf(" is");
        !           894:                else
        !           895:                        printf("s are");
        !           896:                printf(" bad:\n");
        !           897:                for(index=0; index<bad_secs; index++) {
        !           898:                        sec = dsk_err[index].err_adr.cylinder * max_trk;
        !           899:                        sec += dsk_err[index].err_adr.track;
        !           900:                        sec *= max_sec;
        !           901:                        sec += dsk_err[index].err_adr.sector;
        !           902:                        printf("        %ld\n", sec);
        !           903:                }
        !           904:        }
        !           905: }
        !           906: 
        !           907: /*
        !           908: **     Print_number_of_bad_sectors is used to announce to the user the
        !           909: ** total number of bad sectors in a particular segment of the disk.  Rules
        !           910: ** of english for making a word plural are used to make a readable sentence.
        !           911: */
        !           912: 
        !           913: print_number_of_bad_sectors(str)
        !           914: char   *str;
        !           915: {
        !           916:        if(bad_secs)
        !           917:                printf("\n    %d", bad_secs);
        !           918:        else
        !           919:                printf("\n    No");
        !           920:        printf(" bad sector");
        !           921:        if(bad_secs != 1)
        !           922:                printf("s");
        !           923:        printf(" found in %s area.\n", str);
        !           924: }
        !           925: 
        !           926: /*
        !           927: **     Vdmark_sectors_as_bad marks every block in the current bad block
        !           928: ** table as bad on the disk.
        !           929: */
        !           930: 
        !           931: mark_sectors_as_bad()
        !           932: {
        !           933:        register int    index;
        !           934:        dskadr  daddr;
        !           935: 
        !           936:        for(index=0; index<bad_secs; index++) {
        !           937:                daddr.cylinder = dsk_err[index].err_adr.cylinder;
        !           938:                daddr.track = dsk_err[index].err_adr.track;
        !           939:                daddr.sector = dsk_err[index].err_adr.sector;
        !           940:                mark_bad_sector(&daddr, (short)0);
        !           941:        }
        !           942: }
        !           943: 
        !           944: /*
        !           945: **     mark_bad_sector marks a single sector, on disk, as bad using the bad
        !           946: ** block flags in the sector header.
        !           947: */
        !           948: 
        !           949: mark_bad_sector(daddr, flags)
        !           950: dskadr *daddr;
        !           951: short  flags;
        !           952: {
        !           953:        format_sectors(daddr, daddr, BAD | flags, (long)1);
        !           954: }
        !           955: 
        !           956: 
        !           957: /*
        !           958: **     relocate_bad_blocks scans the current disk error table and relocates
        !           959: ** every block that is flagged as bad in the table.  At the beginning of the
        !           960: ** routine the operator is given the chance to add blocks of his/her own to
        !           961: ** the table.
        !           962: */
        !           963: 
        !           964: relocate_bad_blocks()
        !           965: {
        !           966:        extern rel_type new_location();
        !           967:        register int    index;
        !           968:        dskadr          daddr, naddr;
        !           969:        rel_type        type;
        !           970: 
        !           971:        printf("Relocating bad sectors...\n");
        !           972:        load_free_table();
        !           973:        for(index=0; index<bad_secs; index++) {
        !           974:                daddr.cylinder = dsk_err[index].err_adr.cylinder;
        !           975:                daddr.track = dsk_err[index].err_adr.track;
        !           976:                daddr.sector = dsk_err[index].err_adr.sector;
        !           977:                type = new_location(&daddr, &naddr, dsk_err[index].err_stat);
        !           978:                relocate(&daddr, &naddr, type);
        !           979:        }
        !           980:        printf("Relocation complete.\n");
        !           981: }
        !           982: 
        !           983: /*
        !           984: **     Vdrelocate commands the controller to relocate a block from daddr
        !           985: ** to naddr.  Once this has been done the controller will automatically perform
        !           986: ** relocation whenever data is transfered to or from daddr.
        !           987: */
        !           988: 
        !           989: relocate(daddr, naddr, type)
        !           990: dskadr         *daddr, *naddr;
        !           991: rel_type       type;
        !           992: {
        !           993:        if(type == FULL_TRACK)
        !           994:                relocate_track(daddr, naddr);
        !           995:        else
        !           996:                relocate_sector(daddr, naddr);
        !           997: }
        !           998: 
        !           999: 
        !          1000: /*
        !          1001: **
        !          1002: */
        !          1003: 
        !          1004: relocate_sector(daddr, naddr)
        !          1005: dskadr         *daddr, *naddr;
        !          1006: {
        !          1007:        dskadr          phys, reloc;
        !          1008:        register long   blk;
        !          1009:        register long   status;
        !          1010: 
        !          1011:        access(save, daddr, RD, 1, 1);
        !          1012:        phys.cylinder = daddr->cylinder;
        !          1013:        phys.track = daddr->track;
        !          1014:        phys.sector = daddr-> sector;
        !          1015:        reloc.cylinder = naddr->cylinder;
        !          1016:        reloc.track = naddr->track;
        !          1017:        reloc.sector = naddr->sector;
        !          1018:        format_sectors(&phys, &reloc, RELOC_SECTOR, (long)1);
        !          1019:        
        !          1020:        phys.cylinder = naddr->cylinder;
        !          1021:        phys.track = naddr->track;
        !          1022:        phys.sector = naddr->sector;
        !          1023:        reloc.cylinder = daddr->cylinder;
        !          1024:        reloc.track = daddr->track;
        !          1025:        reloc.sector = daddr->sector;
        !          1026:        format_sectors(&phys, &reloc, ALT_SECTOR, (long)1);
        !          1027:        blk = (daddr->cylinder * max_trk) + daddr->track;
        !          1028:        blk = (blk * max_sec) + daddr->sector;
        !          1029:        printf("  Sector #%ld ", blk);
        !          1030:        status = access(save, daddr, WD, 1, 1);
        !          1031:        if((status & ALTACC) && !(status & HRDERR)) {
        !          1032:                blk = (naddr->cylinder * max_trk) + naddr->track;
        !          1033:                blk = (blk * max_sec) + naddr->sector;
        !          1034:                printf("relocated to sector #%d.\n", blk);
        !          1035:                return;
        !          1036:        }
        !          1037:        printf("was not relocated successfully!  Status = %lx\n", status);
        !          1038: }
        !          1039: 
        !          1040: 
        !          1041: 
        !          1042: /*
        !          1043: **
        !          1044: */
        !          1045: 
        !          1046: relocate_track(daddr, naddr)
        !          1047: dskadr         *daddr, *naddr;
        !          1048: {
        !          1049:        dskadr          phys, reloc;
        !          1050:        register long   blk;
        !          1051:        register long   status;
        !          1052: 
        !          1053:        access(save, daddr, FTR, 1, 1);
        !          1054:        phys.cylinder = daddr->cylinder;
        !          1055:        phys.track = daddr->track;
        !          1056:        phys.sector = 0;
        !          1057:        reloc.cylinder = naddr->cylinder;
        !          1058:        reloc.track = naddr->track;
        !          1059:        reloc.sector = 0xff;
        !          1060:        format_sectors(&phys, &reloc, RELOC_SECTOR, max_sec);
        !          1061:        
        !          1062:        phys.cylinder = naddr->cylinder;
        !          1063:        phys.track = naddr->track;
        !          1064:        phys.sector = 0;
        !          1065:        reloc.cylinder = daddr->cylinder;
        !          1066:        reloc.track = daddr->track;
        !          1067:        reloc.sector = 0;
        !          1068:        format_sectors(&phys, &reloc, ALT_SECTOR, max_sec);
        !          1069:        blk = (daddr->cylinder * max_trk) + daddr->track;
        !          1070:        printf("  Track #%ld ", blk);
        !          1071:        status = access(save, daddr, FTW, 1, 1);
        !          1072:        if((status & ALTACC) && !(status & HRDERR)) {
        !          1073:                blk = (naddr->cylinder * max_trk) + naddr->track;
        !          1074:                printf("relocated to track #%d.\n", blk);
        !          1075:                return;
        !          1076:        }
        !          1077:        printf("was not relocated successfully!  Status = %lx\n", status);
        !          1078: }
        !          1079: 
        !          1080: /*
        !          1081: **     access is used by other routines to do reads and writes to the disk.
        !          1082: ** The status of the read / write is returned to the caller for processing.
        !          1083: */
        !          1084: 
        !          1085: access(buf, daddr, func, count, wait)
        !          1086: char   *buf;
        !          1087: dskadr *daddr;
        !          1088: int    func, count, wait;
        !          1089: {
        !          1090:        dcb.opcode = func;              /* format sector command */
        !          1091:        dcb.intflg = NOINT;
        !          1092:        dcb.nxtdcb = (fmt_dcb *)0;      /* end of chain */
        !          1093:        dcb.operrsta  = 0;
        !          1094:        dcb.devselect = (char)unit_number;
        !          1095:        dcb.trailcnt = (char)(sizeof(trrw) / 4);
        !          1096:        dcb.trail.rwtrail.memadr = buf; 
        !          1097:        dcb.trail.rwtrail.wcount = count * (sector_size / sizeof(short));
        !          1098:        dcb.trail.rwtrail.disk.cylinder = daddr->cylinder;
        !          1099:        dcb.trail.rwtrail.disk.track = daddr->track;
        !          1100:        dcb.trail.rwtrail.disk.sector = daddr->sector;
        !          1101:        mdcb.firstdcb = &dcb;
        !          1102:        mdcb.vddcstat = 0;
        !          1103:        VDDC_ATTENTION(controller_address, &mdcb, ctlr_type[ctlr_num]);
        !          1104:        if(wait) {
        !          1105:                POLLTILLDONE(controller_address,&dcb,2*60,ctlr_type[ctlr_num]);
        !          1106:                if(vdtimeout <= 0) {
        !          1107:                        printf(" in access.\n");
        !          1108:                        _longjmp(environ, 1);
        !          1109:                }
        !          1110:        }
        !          1111:        return dcb.operrsta;
        !          1112: }
        !          1113: 
        !          1114: /*
        !          1115: **     Vdformat_sectors is used to do the actual formatting of a block.
        !          1116: */
        !          1117: 
        !          1118: format_sectors(daddr, haddr, flags, count)
        !          1119: dskadr *daddr, *haddr;
        !          1120: short  flags;
        !          1121: long   count;
        !          1122: {
        !          1123:        dcb.opcode = FSECT;             /* format sector command */
        !          1124:        dcb.intflg = NOINT;
        !          1125:        dcb.nxtdcb = (fmt_dcb *)0;      /* end of chain */
        !          1126:        dcb.operrsta  = 0;
        !          1127:        dcb.devselect = (char)unit_number;
        !          1128:        dcb.trailcnt = (char)(sizeof(trfmt) / 4);
        !          1129:        dcb.trail.fmtrail.addr = (char *)scratch; 
        !          1130:        dcb.trail.fmtrail.nsectors = count;
        !          1131:        dcb.trail.fmtrail.disk.cylinder = daddr->cylinder | flags;
        !          1132:        dcb.trail.fmtrail.disk.track = daddr->track;
        !          1133:        dcb.trail.fmtrail.disk.sector = daddr->sector;
        !          1134:        dcb.trail.fmtrail.hdr.cylinder = haddr->cylinder | flags;
        !          1135:        dcb.trail.fmtrail.hdr.track = haddr->track;
        !          1136:        dcb.trail.fmtrail.hdr.sector = haddr->sector;
        !          1137:        mdcb.firstdcb = &dcb;
        !          1138:        mdcb.vddcstat = 0;
        !          1139:        VDDC_ATTENTION(controller_address, &mdcb, ctlr_type[ctlr_num]);
        !          1140:        POLLTILLDONE(controller_address, &dcb,
        !          1141:            ((count+849)/850)+120, ctlr_type[ctlr_num]);
        !          1142:        if(vdtimeout <= 0) {
        !          1143:                printf(" in format_sectors.\n");
        !          1144:                _longjmp(environ, 1);
        !          1145:        }
        !          1146:        if (!data_ok(dcb.operrsta)) {
        !          1147:                printf("Data error during format operation!\n");
        !          1148:                _longjmp(environ, dcb.operrsta);
        !          1149:        }
        !          1150: }
        !          1151: 
        !          1152: /*
        !          1153: **     Print_dcb() dumps the MDCB and DCB for diagnostic purposes.  This
        !          1154: ** routine is called whenever a fatal error is encountered.
        !          1155: */
        !          1156: 
        !          1157: printdcb(ptr)
        !          1158: register long  *ptr;
        !          1159: {
        !          1160:        register long   i;
        !          1161:        register long   trailer_count;
        !          1162: 
        !          1163:        printf("Dump of MDCB: ");
        !          1164:        for(i=0; i<4; i++)
        !          1165:                printf("  %lx", *(ptr+i));
        !          1166:        if(ptr = (long *)*ptr) {
        !          1167:                printf(" and DCB:");
        !          1168:                trailer_count = *(ptr+3) & 0xff;
        !          1169:                for(i=0; i<7+trailer_count; i++) {
        !          1170:                        uncache(ptr+i);
        !          1171:                        printf("  %lx", *(ptr+i));
        !          1172:                }
        !          1173:        }
        !          1174:        printf("\n");
        !          1175:        for(i=0; i<5000000; i++) ;
        !          1176: }
        !          1177: 
        !          1178: 
        !          1179: /*
        !          1180: **     Vdload_free_table checks each block in the bad block relocation area
        !          1181: ** to see if it is used. If it is, the free relocation block table is updated.
        !          1182: */
        !          1183: 
        !          1184: load_free_table()
        !          1185: {
        !          1186:        dskadr  daddr;
        !          1187:        register int    i, j;
        !          1188: 
        !          1189:        /* Clear free table before starting */
        !          1190:        for(i = 0; i < (max_trk * NUMREL); i++)
        !          1191:                for(j = 0; j < max_sec; j++) {
        !          1192:                        free[i][j].freestatus = NOTALLOCATED;
        !          1193:                        free[i][j].error = (long)0;
        !          1194:                }
        !          1195:        /* For each relocation cylinder */
        !          1196:        for(daddr.cylinder = max_cyl-NUMSYS;
        !          1197:            daddr.cylinder < (max_cyl-NUMMNT); daddr.cylinder++)
        !          1198:                /* For each track on a cylinder */
        !          1199:                for(daddr.track = 0; daddr.track < max_trk; daddr.track++)
        !          1200:                        /* For each sector on a track */
        !          1201:                        for(daddr.sector=0;daddr.sector<max_sec;daddr.sector++)
        !          1202:                                if(block_should_be_allocated(&daddr))
        !          1203:                                        allocate(&daddr, (long)0);
        !          1204: }
        !          1205: 
        !          1206: /*
        !          1207: **     block_should_be_allocated does a read header and data command into
        !          1208: ** a local buffer.  The header address is then checked to see if the block
        !          1209: ** has the relocation bit set or if the block was marked as bad. (either VDMF
        !          1210: ** or VDUF or both bits set). In addition, if data data error is picked up
        !          1211: ** during the read then the block should be allocated. If the block meets
        !          1212: ** the above criteria then
        !          1213: */
        !          1214: 
        !          1215: block_should_be_allocated(daddr)
        !          1216: dskadr *daddr;
        !          1217: {
        !          1218:        /* return false if already replaced or either VDMF or VDUF is set */ 
        !          1219:        return (access(scratch, daddr, RD, 1, 1) & (HRDERR|SFTERR|ALTACC));
        !          1220: }
        !          1221: 
        !          1222: /*
        !          1223: **     allocate marks a replacement sector as used.
        !          1224: */
        !          1225: 
        !          1226: allocate(daddr, status)
        !          1227: dskadr *daddr;
        !          1228: long   status;
        !          1229: {
        !          1230:        register long   trk;
        !          1231: 
        !          1232:        trk = daddr->cylinder - (max_cyl - NUMSYS);
        !          1233:        trk *= max_trk;
        !          1234:        trk += daddr->track;
        !          1235:        free[trk][daddr->sector].freestatus = ALLOCATED;
        !          1236:        free[trk][daddr->sector].error = status;
        !          1237: }
        !          1238: 
        !          1239: /*
        !          1240: **     Vdnew_location allocates a replacement block given a bad block address.
        !          1241: **  The algorithm is fairly simple; it simply searches for the first
        !          1242: **  free sector that has the same sector number of the bad sector.  If no sector
        !          1243: **  is found then the drive should be considered bad because of a microcode bug
        !          1244: **  in the controller that forces us to use the same sector number as the bad
        !          1245: **  sector for relocation purposes.  Using different tracks and cylinders is ok
        !          1246: **  of course.
        !          1247: */
        !          1248: 
        !          1249: rel_type new_location(daddr, naddr, status)
        !          1250: dskadr *daddr, *naddr;
        !          1251: long   status;
        !          1252: {
        !          1253:        register int    index, sec;
        !          1254: 
        !          1255:        if(status & (HEADER_ERROR)) {
        !          1256:                for(index = 0; index < (max_trk * NUMREL); index++) {
        !          1257:                        for(sec=0; sec < max_sec; sec++) {
        !          1258:                                if(free[index][sec].freestatus == ALLOCATED)
        !          1259:                                        break;
        !          1260:                        }
        !          1261:                        if(sec == max_sec) {
        !          1262:                                for(sec = 0; sec < max_sec; sec++) {
        !          1263:                                        free[index][sec].freestatus = ALLOCATED;
        !          1264:                                        free[index][sec].error = status;
        !          1265:                                }
        !          1266:                                naddr->cylinder=index/max_trk+(max_cyl-NUMSYS);
        !          1267:                                naddr->track = index % max_trk;
        !          1268:                                naddr->sector = 0;
        !          1269:                                return FULL_TRACK;
        !          1270:                        }
        !          1271:                }
        !          1272:        }
        !          1273:        for(index = 0; index < (max_trk * NUMREL); index++)
        !          1274:                if(free[index][daddr->sector].freestatus != ALLOCATED) {
        !          1275:                        free[index][daddr->sector].freestatus = ALLOCATED;
        !          1276:                        free[index][daddr->sector].error = status;
        !          1277:                        naddr->cylinder = index / max_trk + (max_cyl - NUMSYS);
        !          1278:                        naddr->track = index % max_trk;
        !          1279:                        naddr->sector = daddr->sector;
        !          1280:                        return SINGLE_SECTOR;
        !          1281:                }       
        !          1282:        printf("Bad sector relocation area is full!");
        !          1283:        _longjmp(environ, daddr->sector);
        !          1284: }
        !          1285: 
        !          1286: /*
        !          1287: **     data_ok checks an error status word for bit patterns
        !          1288: **  associated with error conditions from the VDDC controller.  If a hardware
        !          1289: **  error is present then the problem is reported on the console and the program
        !          1290: **  is halted.  If a data error is present the a zero is returned.
        !          1291: **  If everything is OK then a 1 is returned.
        !          1292: */
        !          1293: 
        !          1294: data_ok(status)
        !          1295: long   status;
        !          1296: {
        !          1297:        if(status & HARD_ERROR){
        !          1298:                if(status & DRVNRDY)
        !          1299:                        printf("\nDrive is not ready!");
        !          1300:                else if(status & INVDADR)
        !          1301:                        printf("\nInvalid disk address issued!");
        !          1302:                else if(status & DNEMEM)
        !          1303:                        printf("\nNon-existent memory error!");
        !          1304:                else if(status & PARERR)
        !          1305:                        printf("\nMain memory parity error!");
        !          1306:                else if(status & OPABRT) 
        !          1307:                        printf("\nCPU aborted operation!");
        !          1308:                else if(status & WPTERR)
        !          1309:                        printf("\nDrive is write protected!");
        !          1310:                else if(status & DSEEKERR)
        !          1311:                        printf("\nDisk seek error!");
        !          1312:                else
        !          1313:                        printf("\nNot on cylinder error!");
        !          1314:                printf("    Status = %lx\n", status);
        !          1315:                _longjmp(environ, -1);
        !          1316:        }
        !          1317:        return (int)(!(status & DATA_ERROR));
        !          1318: }
        !          1319: 
        !          1320: /*
        !          1321: **     Vdget_yes_no is used to ask simple yes or no questions.  The question
        !          1322: ** prompt is supplied by the caller,  The question mark, possible responses,
        !          1323: ** and the default response is printed at the end of the prompt.  The routine
        !          1324: ** then reads the answer and returns a 1 if a 'y' is typed or no response was
        !          1325: ** given, otherwise, a zero is returned.
        !          1326: */
        !          1327: 
        !          1328: get_yes_no(str)
        !          1329: register char  *str;
        !          1330: {
        !          1331:        char    answer[80];
        !          1332: 
        !          1333:        for(;;) {
        !          1334:                printf("%s? [y/n] (n): ", str);
        !          1335:                gets(answer);
        !          1336:                if((answer[0] == 'Y') || (answer[0] == 'y'))
        !          1337:                        return(TRUE);
        !          1338:                if((answer[0] == 'N') || (answer[0] == 'n'))
        !          1339:                        return(FALSE);
        !          1340:                printf("\nA 'Y' (yes) or 'N' (no) must be typed!\n\n");
        !          1341:        }
        !          1342: }
        !          1343: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.