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