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