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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Copyrighted as an unpublished work. 32 * (c) Copyright INTERACTIVE Systems Corporation 1986, 1988, 1990 33 * All rights reserved. 34 */ 35 36 #include <stdio.h> 37 #include <fcntl.h> 38 #include <memory.h> 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/stat.h> 42 #include <sys/mkdev.h> 43 #include <sys/vtoc.h> 44 #include <sys/dkio.h> 45 #include <errno.h> 46 #include <stdlib.h> 47 #include <strings.h> 48 #include <unistd.h> 49 #include <stropts.h> 50 #include <sys/scsi/generic/commands.h> 51 #include <sys/scsi/impl/commands.h> 52 #include <sys/scsi/impl/uscsi.h> 53 #include "badsec.h" 54 55 char *devname; /* name of device */ 56 int devfd; /* device file descriptor */ 57 struct dk_geom dkg; /* geometry */ 58 struct extvtoc vtoc; /* table of contents */ 59 char *progname; 60 61 extern struct badsec_lst *badsl_chain; 62 extern int badsl_chain_cnt; 63 extern struct badsec_lst *gbadsl_chain; 64 extern int gbadsl_chain_cnt; 65 extern int print_altsec(struct extpartition *); 66 extern int updatebadsec(struct extpartition *, int); 67 extern void wr_altsctr(void); 68 69 int alts_fd; 70 71 static void giveusage(void); 72 static void rd_gbad(FILE *badsecfd); 73 static void add_gbad(int badsec_entry); 74 static int try_hw_remap(void); 75 static int hardware_remap(blkaddr_t); 76 77 int 78 main(int argc, char *argv[]) 79 { 80 extern int optind; 81 extern char *optarg; 82 83 static char options[] = "Ipa:f:"; 84 char numbuf[100]; 85 char *nxtarg; 86 char *alts_name; 87 minor_t minor_val; 88 struct stat statbuf; 89 struct extpartition *part = NULL; 90 int alts_slice = -1; 91 int l; 92 int p; 93 int init_flag = 0; 94 int print_flag = 0; 95 int c; 96 int i; 97 FILE *badsecfd = NULL; 98 99 progname = argv[0]; 100 while ((c = getopt(argc, argv, options)) != EOF) { 101 switch (c) { 102 case 'I': 103 init_flag = 1; 104 break; 105 case 'p': 106 print_flag = 1; 107 break; 108 case 'a': 109 nxtarg = optarg; 110 for (; *nxtarg != '\0'; ) 111 add_gbad(strtol(nxtarg, &nxtarg, 0)); 112 break; 113 case 'f': 114 if ((badsecfd = fopen(optarg, "r")) == NULL) { 115 (void) fprintf(stderr, 116 "%s: unable to open %s file\n", 117 progname, optarg); 118 exit(1); 119 } 120 break; 121 default: 122 giveusage(); 123 exit(2); 124 } 125 } 126 127 /* get the last argument -- device stanza */ 128 if (argc != optind+1) { 129 (void) fprintf(stderr, "Missing disk device name\n"); 130 giveusage(); 131 exit(3); 132 } 133 devname = argv[optind]; 134 135 if (stat(devname, &statbuf)) { 136 (void) fprintf(stderr, "%s: invalid device %s, stat failed\n", 137 progname, devname); 138 giveusage(); 139 exit(4); 140 } 141 if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 142 (void) fprintf(stderr, "%s: device %s is not character" 143 " special\n", progname, devname); 144 giveusage(); 145 exit(5); 146 } 147 minor_val = minor(statbuf.st_rdev); 148 /* 149 * NEED A DEFINE FOR THE PHYSICAL BIT (0x10) 150 */ 151 if ((minor_val & 0x10) == 0) { 152 (void) fprintf(stderr, "%s: device %s is not a physical" 153 " slice\n", progname, devname); 154 giveusage(); 155 exit(6); 156 } 157 if ((minor_val % V_NUMPAR) != 0) { 158 (void) fprintf(stderr, "%s: device %s is not a slice 0" 159 " device\n", progname, devname); 160 giveusage(); 161 exit(7); 162 } 163 if ((devfd = open(devname, O_RDWR)) == -1) { 164 (void) fprintf(stderr, "%s: open of %s failed\n", 165 progname, devname); 166 perror(""); 167 exit(8); 168 } 169 if ((ioctl(devfd, DKIOCGGEOM, &dkg)) == -1) { 170 (void) fprintf(stderr, "%s: unable to get disk geometry.\n", 171 progname); 172 perror(""); 173 exit(9); 174 } 175 176 if (ioctl(devfd, DKIOCGEXTVTOC, &vtoc) == -1) { 177 (void) fprintf(stderr, "%s: could not get VTOC.\n", progname); 178 giveusage(); 179 exit(14); 180 } 181 182 if ((vtoc.v_sanity != VTOC_SANE) || (vtoc.v_version != V_VERSION)) { 183 (void) fprintf(stderr, "%s: invalid VTOC found.\n", progname); 184 giveusage(); 185 exit(15); 186 } 187 if (badsecfd) 188 rd_gbad(badsecfd); 189 190 #ifdef ADDBAD_DEBUG 191 { 192 struct badsec_lst *blc_p; 193 printf("\n main: Total bad sectors found= %d\n", gbadsl_chain_cnt); 194 for (blc_p = gbadsl_chain; blc_p; blc_p = blc_p->bl_nxt) { 195 for (i = 0; i < blc_p->bl_cnt; i++) 196 printf(" badsec=%d ", blc_p->bl_sec[i]); 197 } 198 printf("\n"); 199 } 200 #endif 201 #ifdef PPP 202 /* 203 * If init_flag is set, run to completion. 204 */ 205 if (gbadsl_chain_cnt == 0 && init_flag == 0) 206 /* 207 * No defects and not initializing 208 */ 209 exit(0); 210 #endif 211 if (gbadsl_chain_cnt != 0) 212 { 213 if (try_hw_remap() == SUCCESS) 214 exit(0); 215 } 216 /* 217 * get ALTS slice 218 */ 219 for (i = 0; i < V_NUMPAR && alts_slice == -1; i++) 220 { 221 if (vtoc.v_part[i].p_tag == V_ALTSCTR) 222 { 223 alts_slice = i; 224 part = &vtoc.v_part[i]; 225 } 226 } 227 if (alts_slice == -1) 228 { 229 (void) fprintf(stderr, "%s: No alternates slice.\n", progname); 230 exit(16); 231 } 232 l = strlen(devname); 233 (void) sprintf(numbuf, "%d", alts_slice); 234 p = strlen(numbuf); 235 alts_name = (char *)malloc(l + p); 236 (void) strcpy(alts_name, devname); 237 alts_name[l - 2] = 's'; 238 (void) strcpy(&alts_name[l - 1], numbuf); 239 alts_name[l + p - 1] = '\0'; 240 if ((alts_fd = open(alts_name, O_RDWR)) == -1) { 241 (void) fprintf(stderr, "%s: open of %s failed\n", 242 progname, alts_name); 243 perror(""); 244 exit(9); 245 } 246 if (print_flag) 247 { 248 (void) print_altsec(part); 249 exit(0); 250 } 251 (void) updatebadsec(part, init_flag); 252 wr_altsctr(); 253 254 if (ioctl(devfd, DKIOCADDBAD, NULL) == -1) { 255 (void) fprintf(stderr, "Warning: DKIOCADDBAD io control" 256 " failed. System must be re-booted\n"); 257 (void) fprintf(stderr, "for alternate sectors to be usable.\n"); 258 exit(17); 259 } 260 sync(); 261 262 (void) fclose(badsecfd); 263 (void) close(alts_fd); 264 (void) close(devfd); 265 return (0); 266 } 267 268 /* 269 * Giveusage () 270 * Give a (not so) concise message on how to use this program. 271 */ 272 static void 273 giveusage(void) 274 { 275 (void) fprintf(stderr, "%s [-p] [-a sector] [-f filename]" 276 " raw-device\n", progname); 277 (void) fprintf(stderr, " p - Print existing bad block map\n"); 278 (void) fprintf(stderr, " a - Add the given sectors to the" 279 " bad block list\n"); 280 (void) fprintf(stderr, " f - Add the sectors from <filename>" 281 " to the bad block list\n"); 282 if (devfd) 283 (void) close(devfd); 284 } 285 286 287 /* 288 * read in the additional growing bad sectors 289 */ 290 static void 291 rd_gbad(FILE *badsecfd) 292 { 293 int badsec_entry; 294 int status; 295 296 status = fscanf(badsecfd, "%d", &badsec_entry); 297 while (status != EOF) { 298 add_gbad(badsec_entry); 299 status = fscanf(badsecfd, "%d", &badsec_entry); 300 } 301 } 302 303 static void 304 add_gbad(int badsec_entry) 305 { 306 struct badsec_lst *blc_p; 307 308 if (!gbadsl_chain) { 309 blc_p = (struct badsec_lst *)malloc(BADSLSZ); 310 if (!blc_p) { 311 (void) fprintf(stderr, "Unable to allocate memory" 312 " for additional bad sectors\n"); 313 exit(18); 314 } 315 gbadsl_chain = blc_p; 316 blc_p->bl_cnt = 0; 317 blc_p->bl_nxt = 0; 318 } 319 for (blc_p = gbadsl_chain; blc_p->bl_nxt; ) 320 blc_p = blc_p->bl_nxt; 321 322 if (blc_p->bl_cnt == MAXBLENT) { 323 blc_p->bl_nxt = (struct badsec_lst *)malloc(BADSLSZ); 324 if (!blc_p->bl_nxt) { 325 (void) fprintf(stderr, "Unable to allocate memory" 326 " for additional bad sectors\n"); 327 exit(19); 328 } 329 blc_p = blc_p->bl_nxt; 330 blc_p->bl_cnt = 0; 331 blc_p->bl_nxt = 0; 332 } 333 blc_p->bl_sec[blc_p->bl_cnt++] = badsec_entry; 334 gbadsl_chain_cnt++; 335 } 336 337 /* 338 * Map a block using hardware (SCSI) techniques. 339 */ 340 /*ARGSUSED*/ 341 static int 342 hardware_remap(bn) 343 blkaddr_t bn; 344 { 345 uint_t byte_swap_32(uint_t); 346 ushort_t byte_swap_16(ushort_t); 347 348 struct uscsi_cmd ucmd; 349 union scsi_cdb cdb; 350 struct scsi_reassign_blk defect_list; 351 352 /* 353 * Build and execute the uscsi ioctl 354 */ 355 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 356 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 357 (void) memset((char *)&defect_list, 0, 358 sizeof (struct scsi_reassign_blk)); 359 cdb.scc_cmd = SCMD_REASSIGN_BLOCK; 360 ucmd.uscsi_cdb = (caddr_t)&cdb; 361 ucmd.uscsi_cdblen = CDB_GROUP0; 362 ucmd.uscsi_bufaddr = (caddr_t)&defect_list; 363 ucmd.uscsi_buflen = sizeof (struct scsi_reassign_blk); 364 defect_list.length = byte_swap_16(sizeof (defect_list.defect)); 365 defect_list.defect = byte_swap_32(bn); 366 /* 367 * Set function flags for driver. 368 */ 369 ucmd.uscsi_flags = USCSI_ISOLATE | USCSI_DIAGNOSE | USCSI_SILENT; 370 ucmd.uscsi_timeout = 30; /* 30 seconds */ 371 372 /* 373 * Execute the ioctl 374 */ 375 if (ioctl(devfd, USCSICMD, &ucmd) == -1) 376 { 377 if (errno != ENOTTY) 378 { 379 perror("SCSI hardware re-assign failed"); 380 /* 381 * It looks like a failure but by returning success 382 * the upper layer will not try to do 383 * software remapping. 384 */ 385 return (SUCCESS); 386 } 387 return (FAILURE); 388 } 389 return (SUCCESS); 390 } 391 392 uint_t 393 byte_swap_32(uint_t nav) 394 { 395 uint_t rc; 396 rc = ((nav & 0xff000000) >> 24) | ((nav & 0x00ff0000) >> 8) | 397 ((nav & 0x0000ff00) << 8) | ((nav & 0x000000ff) << 24); 398 return (rc); 399 } 400 401 ushort_t 402 byte_swap_16(ushort_t niv) 403 { 404 ushort_t rc; 405 rc = (ushort_t)((int)(niv & 0xff00) >> 8) | ((niv & 0x00ff) << 8); 406 return (rc); 407 } 408 409 static int 410 try_hw_remap() 411 { 412 struct badsec_lst *blc_p; 413 int i; 414 415 for (blc_p = gbadsl_chain; blc_p != 0; blc_p = blc_p->bl_nxt) { 416 for (i = 0; i < blc_p->bl_cnt; i++) 417 if (hardware_remap(blc_p->bl_sec[i]) == FAILURE) 418 return (FAILURE); 419 } 420 return (SUCCESS); 421 } 422