|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.