Annotation of cci/sys/stand/vdformat.c, revision 1.1.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.