1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains routines to analyze the surface of a disk. 31 */ 32 #include "global.h" 33 #include "analyze.h" 34 #include <stdlib.h> 35 #include <errno.h> 36 #include "misc.h" 37 #include "defect.h" 38 #include "label.h" 39 #include "param.h" 40 #include "checkdev.h" 41 42 43 /* 44 * These global variables control the surface analysis process. They 45 * are set from a command in the defect menu. 46 */ 47 int scan_entire = 1; /* scan whole disk flag */ 48 diskaddr_t scan_lower = 0; /* lower bound */ 49 diskaddr_t scan_upper = 0; /* upper bound */ 50 int scan_correct = 1; /* correct errors flag */ 51 int scan_stop = 0; /* stop after error flag */ 52 int scan_loop = 0; /* loop forever flag */ 53 int scan_passes = 2; /* number of passes */ 54 int scan_random = 0; /* random patterns flag */ 55 int scan_size = 0; /* sectors/scan operation */ 56 int scan_auto = 1; /* scan after format flag */ 57 int scan_restore_defects = 1; /* restore defect list after writing */ 58 int scan_restore_label = 1; /* restore label after writing */ 59 60 /* 61 * These are summary variables to print out info after analysis. 62 * Values less than 0 imply they are invalid. 63 */ 64 offset_t scan_cur_block = -1; /* current block */ 65 int64_t scan_blocks_fixed = -1; /* # blocks repaired */ 66 67 /* 68 * This variable is used to tell whether the most recent surface 69 * analysis error was caused by a media defect or some other problem. 70 */ 71 int media_error; /* error was caused by defect */ 72 73 int disk_error; /* disk errors during analysis */ 74 75 /* 76 * These are the data patterns used if random patterns are not chosen. 77 * They are designed to show pattern dependent errors. 78 */ 79 static unsigned int scan_patterns[] = { 80 0xc6dec6de, 81 0x6db6db6d, 82 0x00000000, 83 0xffffffff, 84 0xaaaaaaaa, 85 }; 86 #define NPATTERNS 5 /* number of predefined patterns */ 87 88 /* 89 * These are the data patterns from the SunFed requirements document. 90 */ 91 static unsigned int purge_patterns[] = { /* patterns to be written */ 92 0xaaaaaaaa, /* 10101010... */ 93 0x55555555, /* 01010101... == UUUU... */ 94 0xaaaaaaaa, /* 10101010... */ 95 0xaaaaaaaa, /* 10101010... */ 96 }; 97 98 static unsigned int alpha_pattern = 0x40404040; /* 10000000... == @@@@... */ 99 100 /* Function prototypes */ 101 #ifdef __STDC__ 102 103 static int scan_repair(diskaddr_t bn, int mode); 104 static int analyze_blocks(int flags, diskaddr_t blkno, int blkcnt, 105 unsigned data, int init, int driver_flags, int *xfercntp); 106 static int handle_error_conditions(void); 107 static int verify_blocks(int flags, diskaddr_t blkno, int blkcnt, 108 unsigned data, int driver_flags, int *xfercntp); 109 #else /* __STDC__ */ 110 111 static int scan_repair(); 112 static int analyze_blocks(); 113 static int handle_error_conditions(); 114 static int verify_blocks(); 115 116 #endif /* __STDC__ */ 117 118 /* 119 * This routine performs a surface analysis based upon the global 120 * parameters. It is called from several commands in the defect menu, 121 * and from the format command in the command menu (if post-format 122 * analysis is enable). 123 */ 124 int 125 do_scan(flags, mode) 126 int flags, mode; 127 { 128 diskaddr_t start, end, curnt; 129 int pass, size, needinit, data; 130 int status, founderr, i, j; 131 int error = 0; 132 int pattern = 0; 133 int xfercnt; 134 135 /* 136 * Check to be sure we aren't correcting without a defect list 137 * if the controller can correct the defect. 138 */ 139 if (scan_correct && !EMBEDDED_SCSI && (cur_ops->op_repair != NULL) && 140 (cur_list.list == NULL)) { 141 err_print("Current Defect List must be initialized "); 142 err_print("to do automatic repair.\n"); 143 return (-1); 144 } 145 /* 146 * Define the bounds of the scan. 147 */ 148 if (scan_entire) { 149 start = 0; 150 if (cur_label == L_TYPE_SOLARIS) { 151 if (cur_ctype->ctype_flags & CF_SCSI) 152 end = datasects() - 1; 153 else 154 end = physsects() - 1; 155 } else if (cur_label == L_TYPE_EFI) { 156 end = cur_parts->etoc->efi_last_lba; 157 } 158 } else { 159 start = scan_lower; 160 end = scan_upper; 161 } 162 /* 163 * Make sure the user knows if we are scanning over a mounted 164 * partition. 165 */ 166 if ((flags & (SCAN_PATTERN | SCAN_WRITE)) && 167 (checkmount(start, end))) { 168 err_print("Cannot do analysis on a mounted partition.\n"); 169 return (-1); 170 } 171 172 /* 173 * Make sure the user knows if we are scanning over a 174 * partition being used for swapping. 175 */ 176 if ((flags & (SCAN_PATTERN | SCAN_WRITE)) && 177 (checkswap(start, end))) { 178 err_print("Cannot do analysis on a partition \ 179 which is currently being used for swapping.\n"); 180 return (-1); 181 } 182 183 /* 184 * If we are scanning destructively over certain sectors, 185 * we mark the defect list and/or label dirty so it will get rewritten. 186 */ 187 if (flags & (SCAN_PATTERN | SCAN_WRITE)) { 188 if (cur_label == L_TYPE_SOLARIS) { 189 if (start < (daddr_t)totalsects() && 190 end >= (daddr_t)datasects()) { 191 if (!EMBEDDED_SCSI) { 192 cur_list.flags |= LIST_DIRTY; 193 } 194 if (cur_disk->disk_flags & DSK_LABEL) 195 cur_flags |= LABEL_DIRTY; 196 } 197 } 198 if (start == 0) { 199 if (cur_disk->disk_flags & DSK_LABEL) 200 cur_flags |= LABEL_DIRTY; 201 } 202 } 203 /* 204 * Initialize the summary info on sectors repaired. 205 */ 206 scan_blocks_fixed = 0; 207 /* 208 * Loop through the passes of the scan. If required, loop forever. 209 */ 210 for (pass = 0; pass < scan_passes || scan_loop; pass++) { 211 /* 212 * Determine the data pattern to use if pattern testing 213 * is to be done. 214 */ 215 if (flags & SCAN_PATTERN) { 216 if (scan_random) 217 data = (int)mrand48(); 218 else 219 data = scan_patterns[pass % NPPATTERNS]; 220 221 if (flags & SCAN_PURGE) { 222 flags &= ~(SCAN_PURGE_READ_PASS 223 | SCAN_PURGE_ALPHA_PASS); 224 switch (pattern % (NPPATTERNS + 1)) { 225 case NPPATTERNS: 226 pattern = 0; 227 if (!error) { 228 fmt_print( 229 "\nThe last %d passes were successful, running alpha pattern pass", NPPATTERNS); 230 flags |= SCAN_PURGE_ALPHA_PASS; 231 data = alpha_pattern; 232 } else { 233 data = purge_patterns[pattern]; 234 pattern++; 235 }; 236 break; 237 case READPATTERN: 238 flags |= SCAN_PURGE_READ_PASS; 239 default: 240 data = purge_patterns[pattern]; 241 pattern++; 242 break; 243 } 244 } 245 fmt_print("\n pass %d", pass); 246 fmt_print(" - pattern = 0x%x", data); 247 } else 248 fmt_print("\n pass %d", pass); 249 250 fmt_print("\n"); 251 /* 252 * Mark the pattern buffer as corrupt, since it 253 * hasn't been initialized. 254 */ 255 needinit = 1; 256 /* 257 * Print the first block number to the log file if 258 * logging is on so there is some record of what 259 * analysis was performed. 260 */ 261 if (log_file) { 262 pr_dblock(log_print, start); 263 log_print("\n"); 264 } 265 /* 266 * Loop through this pass, each time analyzing an amount 267 * specified by the global parameters. 268 */ 269 xfercnt = 0; 270 for (curnt = start; curnt <= end; curnt += size) { 271 if ((end - curnt) < scan_size) 272 size = end - curnt + 1; 273 else 274 size = scan_size; 275 /* 276 * Print out where we are, so we don't look dead. 277 * Also store it in summary info for logging. 278 */ 279 scan_cur_block = curnt; 280 nolog_print(" "); 281 pr_dblock(nolog_print, curnt); 282 nolog_print(" \015"); 283 (void) fflush(stdout); 284 disk_error = 0; 285 /* 286 * Do the actual analysis. 287 */ 288 status = analyze_blocks(flags, (daddr_t)curnt, size, 289 (unsigned)data, needinit, (F_ALLERRS | F_SILENT), 290 &xfercnt); 291 /* 292 * If there were no errors, the pattern buffer is 293 * still initialized, and we just loop to next chunk. 294 */ 295 needinit = 0; 296 if (!status) 297 continue; 298 /* 299 * There was an error. Check if surface analysis 300 * can be continued. 301 */ 302 if (handle_error_conditions()) { 303 scan_blocks_fixed = scan_cur_block = -1; 304 return (-1); 305 } 306 /* 307 * There was an error. Mark the pattern buffer 308 * corrupt so it will get reinitialized. 309 */ 310 needinit = 1; 311 /* 312 * If it was not a media error, ignore it. 313 */ 314 if (!media_error) 315 continue; 316 /* 317 * Loop 5 times through each sector of the chunk, 318 * analyzing them individually. 319 */ 320 nolog_print(" "); 321 pr_dblock(nolog_print, curnt); 322 nolog_print(" \015"); 323 (void) fflush(stdout); 324 founderr = 0; 325 for (j = 0; j < size * 5; j++) { 326 i = j % size; 327 disk_error = 0; 328 status = analyze_blocks(flags, (daddr_t) 329 (curnt + i), 1, (unsigned)data, needinit, 330 F_ALLERRS, NULL); 331 needinit = 0; 332 if (!status) 333 continue; 334 /* 335 * There was an error. Check if surface analysis 336 * can be continued. 337 */ 338 if (handle_error_conditions()) { 339 scan_blocks_fixed = scan_cur_block = -1; 340 return (-1); 341 } 342 /* 343 * An error occurred. Mark the buffer 344 * corrupt and see if it was media 345 * related. 346 */ 347 needinit = 1; 348 if (!media_error) 349 continue; 350 /* 351 * We found a bad sector. Print out a message 352 * and fix it if required. 353 */ 354 founderr = 1; 355 if (scan_correct && (flags != SCAN_VALID)) { 356 if (scan_repair(curnt+i, mode)) { 357 error = -1; 358 } 359 } else 360 err_print("\n"); 361 /* 362 * Stop after the error if required. 363 */ 364 if (scan_stop) 365 goto out; 366 } 367 /* 368 * Mark the pattern buffer corrupt to be safe. 369 */ 370 needinit = 1; 371 /* 372 * We didn't find an individual sector that was bad. 373 * Print out a warning. 374 */ 375 if (!founderr) { 376 err_print("Warning: unable to pinpoint "); 377 err_print("defective block.\n"); 378 } 379 } 380 /* 381 * Print the end of each pass to the log file. 382 */ 383 enter_critical(); 384 if (log_file) { 385 pr_dblock(log_print, scan_cur_block); 386 log_print("\n"); 387 } 388 scan_cur_block = -1; 389 exit_critical(); 390 fmt_print("\n"); 391 392 /* 393 * alternate the read and write for SCAN_VERIFY test 394 */ 395 if (flags & SCAN_VERIFY) { 396 flags ^= SCAN_VERIFY_READ_PASS; 397 } 398 } 399 out: 400 /* 401 * We got here either by giving up after an error or falling 402 * through after all passes were completed. 403 */ 404 fmt_print("\n"); 405 enter_critical(); 406 /* 407 * If the defect list is dirty, write it to disk, 408 * if scan_restore_defects (the default) is true. 409 */ 410 if (!EMBEDDED_SCSI && (cur_list.flags & LIST_DIRTY) && 411 (scan_restore_defects)) { 412 cur_list.flags = 0; 413 write_deflist(&cur_list); 414 } 415 /* 416 * If the label is dirty, write it to disk. 417 * if scan_restore_label (the default) is true. 418 */ 419 if ((cur_flags & LABEL_DIRTY) && (scan_restore_label)) { 420 cur_flags &= ~LABEL_DIRTY; 421 (void) write_label(); 422 } 423 /* 424 * If we dropped down to here after an error, we need to write 425 * the final block number to the log file for record keeping. 426 */ 427 if (log_file && scan_cur_block >= 0) { 428 pr_dblock(log_print, scan_cur_block); 429 log_print("\n"); 430 } 431 fmt_print("Total of %lld defective blocks repaired.\n", 432 scan_blocks_fixed); 433 /* 434 * Reinitialize the logging variables so they don't get used 435 * when they are not really valid. 436 */ 437 scan_blocks_fixed = scan_cur_block = -1; 438 exit_critical(); 439 return (error); 440 } 441 442 443 /* 444 * This routine is called to repair a bad block discovered 445 * during a scan operation. Return 0 for success, 1 for failure. 446 * (This has been extracted out of do_scan(), to simplify it.) 447 */ 448 static int 449 scan_repair(bn, mode) 450 diskaddr_t bn; 451 int mode; 452 { 453 int status; 454 int result = 1; 455 char buf[SECSIZE]; 456 int buf_is_good; 457 int i; 458 459 if (cur_ops->op_repair == NULL) { 460 err_print("Warning: Controller does "); 461 err_print("not support repairing.\n\n"); 462 return (result); 463 } 464 465 enter_critical(); 466 467 /* 468 * Determine if the error appears to be hard or soft. We 469 * already assume there's an error. If we can get any 470 * good data out of the sector, write that data back 471 * after the repair. 472 */ 473 buf_is_good = 0; 474 for (i = 0; i < 5; i++) { 475 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, bn, 1, 476 buf, F_SILENT, NULL); 477 if (status == 0) { 478 buf_is_good = 1; 479 break; 480 } 481 } 482 483 fmt_print("Repairing %s error on %llu (", 484 buf_is_good ? "soft" : "hard", bn); 485 pr_dblock(fmt_print, bn); 486 fmt_print(")..."); 487 488 status = (*cur_ops->op_repair)(bn, mode); 489 if (status) { 490 /* 491 * If the repair failed, we note it and will return the 492 * failure. However, the analysis goes on. 493 */ 494 fmt_print("failed.\n\n"); 495 } else { 496 /* 497 * The repair worked. Write the good data we could 498 * recover from the failed block, if possible. 499 * If not, zero the block. In doing so, try to 500 * determine if the new block appears ok. 501 */ 502 if (!buf_is_good) { 503 bzero(buf, SECSIZE); 504 fmt_print("Warning: Block %llu zero-filled.\n", bn); 505 } else { 506 fmt_print("ok.\n"); 507 } 508 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, bn, 509 1, buf, (F_SILENT | F_ALLERRS), NULL); 510 if (status == 0) { 511 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, bn, 512 1, buf, (F_SILENT | F_ALLERRS), NULL); 513 } 514 if (status) { 515 fmt_print("The new block also appears defective.\n"); 516 } 517 fmt_print("\n"); 518 /* 519 * add the defect to the list and write the list out. 520 * Also, kill the working list so it will get resynced 521 * with the current list. 522 * 523 * For embedded scsi, we don't require a defect list. 524 * However, if we have one, add the defect if the 525 * list includes the grown list. If not, kill it 526 * to force a resync if we need the list later. 527 */ 528 if (EMBEDDED_SCSI) { 529 if (cur_list.list != NULL) { 530 if (cur_list.flags & LIST_PGLIST) { 531 add_ldef(bn, &cur_list); 532 } else { 533 kill_deflist(&cur_list); 534 } 535 } 536 /* 537 * The next "if" statement reflects the fix for 538 * bug id 1026096 where format keeps adding the 539 * same defect to the defect list. 540 */ 541 } else if (cur_ctype->ctype_flags & CF_WLIST) { 542 kill_deflist(&cur_list); 543 (*cur_ops->op_ex_cur)(&cur_list); 544 fmt_print("Current list updated\n"); 545 } else { 546 add_ldef(bn, &cur_list); 547 write_deflist(&cur_list); 548 } 549 kill_deflist(&work_list); 550 551 /* Log the repair. */ 552 scan_blocks_fixed++; 553 554 /* return ok */ 555 result = 0; 556 } 557 558 exit_critical(); 559 560 return (result); 561 } 562 563 564 /* 565 * This routine analyzes a set of sectors on the disk. It simply returns 566 * an error if a defect is found. It is called by do_scan(). 567 */ 568 static int 569 analyze_blocks(flags, blkno, blkcnt, data, init, driver_flags, xfercntp) 570 int flags, driver_flags, blkcnt, init; 571 register unsigned data; 572 diskaddr_t blkno; 573 int *xfercntp; 574 { 575 int corrupt = 0; 576 register int status, i, nints; 577 register unsigned *ptr = (uint_t *)pattern_buf; 578 579 media_error = 0; 580 if (flags & SCAN_VERIFY) { 581 return (verify_blocks(flags, blkno, blkcnt, data, 582 driver_flags, xfercntp)); 583 } 584 585 /* 586 * Initialize the pattern buffer if necessary. 587 */ 588 nints = blkcnt * SECSIZE / sizeof (int); 589 if ((flags & SCAN_PATTERN) && init) { 590 for (i = 0; i < nints; i++) 591 *((int *)((int *)pattern_buf + i)) = data; 592 } 593 /* 594 * Lock out interrupts so we can insure valid data will get 595 * restored. This is necessary because there are modes 596 * of scanning that corrupt the disk data then restore it at 597 * the end of the analysis. 598 */ 599 enter_critical(); 600 /* 601 * If the disk data is valid, read it into the data buffer. 602 */ 603 if (flags & SCAN_VALID) { 604 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, blkno, 605 blkcnt, (caddr_t)cur_buf, driver_flags, xfercntp); 606 if (status) 607 goto bad; 608 } 609 /* 610 * If we are doing pattern testing, write and read the pattern 611 * from the pattern buffer. 612 */ 613 if (flags & SCAN_PATTERN) { 614 /* 615 * If the disk data was valid, mark it corrupt so we know 616 * to restore it later. 617 */ 618 if (flags & SCAN_VALID) 619 corrupt++; 620 /* 621 * Only write if we're not on the read pass of SCAN_PURGE. 622 */ 623 if (!(flags & SCAN_PURGE_READ_PASS)) { 624 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 625 blkcnt, (caddr_t)pattern_buf, driver_flags, 626 xfercntp); 627 if (status) 628 goto bad; 629 } 630 /* 631 * Only read if we are on the read pass of SCAN_PURGE, if we 632 * are purging. 633 */ 634 if ((!(flags & SCAN_PURGE)) || (flags & SCAN_PURGE_READ_PASS)) { 635 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, blkno, 636 blkcnt, (caddr_t)pattern_buf, driver_flags, 637 xfercntp); 638 if (status) 639 goto bad; 640 } 641 } 642 /* 643 * If we are doing a data compare, make sure the pattern 644 * came back intact. 645 * Only compare if we are on the read pass of SCAN_PURGE, or 646 * we wrote random data instead of the expected data pattern. 647 */ 648 if ((flags & SCAN_COMPARE) || (flags & SCAN_PURGE_READ_PASS)) { 649 for (i = nints, ptr = (uint_t *)pattern_buf; i; i--) 650 if (*ptr++ != data) { 651 err_print("Data miscompare error (expecting "); 652 err_print("0x%x, got 0x%x) at ", data, 653 *((int *)((int *)pattern_buf + 654 (nints - i)))); 655 pr_dblock(err_print, blkno); 656 err_print(", offset = 0x%x.\n", 657 (nints - i) * sizeof (int)); 658 goto bad; 659 } 660 } 661 /* 662 * If we are supposed to write data out, do so. 663 */ 664 if (flags & SCAN_WRITE) { 665 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 666 blkcnt, (caddr_t)cur_buf, driver_flags, xfercntp); 667 if (status) 668 goto bad; 669 } 670 exit_critical(); 671 /* 672 * No errors occurred, return ok. 673 */ 674 return (0); 675 bad: 676 /* 677 * There was an error. If the data was corrupted, we write it 678 * out from the data buffer to restore it. 679 */ 680 if (corrupt) { 681 if ((*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 682 blkcnt, (caddr_t)cur_buf, F_NORMAL, xfercntp)) 683 err_print("Warning: unable to restore original data.\n"); 684 } 685 exit_critical(); 686 /* 687 * Return the error. 688 */ 689 return (-1); 690 } 691 692 693 /* 694 * This routine analyzes a set of sectors on the disk. It simply returns 695 * an error if a defect is found. It is called by analyze_blocks(). 696 * For simplicity, this is done as a separate function instead of 697 * making the analyze_block routine complex. 698 * 699 * This routine implements the 'verify' command. It writes the disk 700 * by writing unique data for each block; after the write pass, it 701 * reads the data and verifies for correctness. Note that the entire 702 * disk (or the range of disk) is fully written first and then read. 703 * This should eliminate any caching effect on the drives. 704 */ 705 static int 706 verify_blocks(int flags, 707 diskaddr_t blkno, 708 int blkcnt, 709 unsigned data, 710 int driver_flags, 711 int *xfercntp) 712 { 713 int status, i, nints; 714 unsigned *ptr = (uint_t *)pattern_buf; 715 716 nints = SECSIZE / sizeof (int); 717 718 /* 719 * Initialize the pattern buffer if we are in write pass. 720 * Use the block number itself as data, each block has unique 721 * buffer data that way. 722 */ 723 if (!(flags & SCAN_VERIFY_READ_PASS)) { 724 for (data = blkno; data < blkno + blkcnt; data++) { 725 for (i = 0; i < nints; i++) { 726 *ptr++ = data; 727 } 728 } 729 ptr = (uint_t *)pattern_buf; 730 } 731 732 /* 733 * Only write if we're not on the read pass of SCAN_VERIFY. 734 */ 735 if (!(flags & SCAN_VERIFY_READ_PASS)) { 736 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 737 blkcnt, (caddr_t)pattern_buf, driver_flags, xfercntp); 738 if (status) 739 goto bad; 740 } else { 741 /* 742 * Only read if we are on the read pass of SCAN_VERIFY 743 */ 744 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, blkno, 745 blkcnt, (caddr_t)pattern_buf, driver_flags, xfercntp); 746 if (status) 747 goto bad; 748 /* 749 * compare and make sure the pattern came back intact. 750 */ 751 for (data = blkno; data < blkno + blkcnt; data++) { 752 for (i = 0; i < nints; i++) { 753 if (*ptr++ != data) { 754 ptr--; 755 err_print("Data miscompare error (expecting " 756 "0x%x, got 0x%x) at ", data, *ptr); 757 pr_dblock(err_print, blkno); 758 err_print(", offset = 0x%x.\n", (ptr - 759 (uint_t *)pattern_buf) * sizeof (int)); 760 goto bad; 761 } 762 } 763 } 764 } 765 /* 766 * No errors occurred, return ok. 767 */ 768 return (0); 769 bad: 770 return (-1); 771 } 772 773 774 static int 775 handle_error_conditions() 776 { 777 778 /* 779 * Check if the errno is ENXIO. 780 */ 781 if (errno == ENXIO) { 782 fmt_print("\n\nWarning:Cannot access drive, "); 783 fmt_print("aborting surface analysis.\n"); 784 return (-1); 785 } 786 /* 787 * check for disk errors 788 */ 789 switch (disk_error) { 790 case DISK_STAT_RESERVED: 791 case DISK_STAT_UNAVAILABLE: 792 fmt_print("\n\nWarning:Drive may be reserved "); 793 fmt_print("or has been removed, "); 794 fmt_print("aborting surface analysis.\n"); 795 return (-1); 796 case DISK_STAT_NOTREADY: 797 fmt_print("\n\nWarning: Drive not ready, "); 798 fmt_print("aborting surface analysis.\n"); 799 return (-1); 800 case DISK_STAT_DATA_PROTECT: 801 fmt_print("\n\nWarning: Drive is write protected, "); 802 fmt_print("aborting surface analysis.\n"); 803 return (-1); 804 default: 805 break; 806 } 807 return (0); 808 } 809