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 1998-2003 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 that manipulate the defect list. 31 */ 32 #include "global.h" 33 #include <sys/types.h> 34 #include <sys/param.h> 35 36 #if defined(sparc) 37 #include <sys/hdio.h> 38 #endif /* defined(sparc) */ 39 40 #include <sys/buf.h> 41 #include <sys/ioctl.h> 42 #include <sys/uio.h> 43 #include <sys/fcntl.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include <memory.h> 47 48 #if defined(sparc) 49 #include <sys/dkbad.h> 50 #include <sys/scsi/targets/sddef.h> 51 #endif /* defined(sparc) */ 52 53 #include "misc.h" 54 #include "param.h" 55 56 57 #if defined(sparc) 58 /* 59 * This structure is the bad block table for the current disk if 60 * the disk uses bad-144 defect mapping. 61 */ 62 struct dkbad badmap; 63 #endif /* defined(sparc) */ 64 65 /* 66 * This routine reads the defect list off the disk. It also reads in the 67 * bad block table if the disk is a BAD144 type. The defect list is 68 * located on the first 2 tracks of the 2nd alternate cylinder of all 69 * disks. The bad block map is located on the first 5 even sectors of 70 * the last track of the last cylinder. 71 */ 72 void 73 read_list(struct defect_list *list) 74 { 75 int size, head; 76 77 #if defined(sparc) 78 int sec, status; 79 struct bt_bad *bt; 80 #endif /* defined(sparc) */ 81 82 assert(!EMBEDDED_SCSI); 83 84 /* 85 * This flags has been introduced only for Sparc ATA IDE. 86 * This indicates that no list manipulation is done in this controller 87 * and hence return without any other checking. 88 */ 89 if (cur_ctype->ctype_flags & CF_NOWLIST) { 90 return; 91 } 92 93 /* 94 * Panther's working list is maintained by the controller 95 */ 96 if (cur_ctype->ctype_flags & CF_WLIST) { 97 if (*cur_ops->op_ex_cur != NULL && 98 ((*cur_ops->op_ex_cur)(list)) == 0) { 99 if (list->header.magicno != DEFECT_MAGIC) { 100 fmt_print("Defect list BAD\n"); 101 } else { 102 fmt_print("Controller working list found\n"); 103 } 104 return; 105 } 106 107 if (*cur_ops->op_ex_man != NULL && 108 ((*cur_ops->op_ex_man)(list)) == 0) { 109 if (list->header.magicno != DEFECT_MAGIC) { 110 fmt_print("Defect list BAD\n"); 111 } else { 112 fmt_print("MANUFACTURER's list found\n"); 113 } 114 return; 115 } 116 fmt_print("No defect list found\n"); 117 return; 118 } 119 120 /* 121 * Loop for each copy of the defect list until we get a good one. 122 */ 123 for (head = 0; head < LISTCOUNT; head++) { 124 /* 125 * Try to read the list header. 126 */ 127 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file, 128 (diskaddr_t)chs2bn(ncyl + 1, head, 0), 1, 129 (char *)&list->header, NULL), F_NORMAL) 130 continue; 131 /* 132 * If the magic number is wrong, this copy is corrupt. 133 */ 134 if (list->header.magicno != DEFECT_MAGIC) 135 continue; 136 /* 137 * Allocate space for the rest of the list. 138 */ 139 size = LISTSIZE(list->header.count); 140 list->list = (struct defect_entry *)zalloc(size * SECSIZE); 141 /* 142 * Try to read in the rest of the list. If there is an 143 * error, or the checksum is wrong, this copy is corrupt. 144 */ 145 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file, 146 (diskaddr_t)chs2bn(ncyl + 1, head, 1), size, 147 (char *)list->list, F_NORMAL, NULL) || 148 checkdefsum(list, CK_CHECKSUM)) { 149 /* 150 * Destroy the list and go on. 151 */ 152 kill_deflist(list); 153 continue; 154 } 155 /* 156 * Got a good copy, stop searching. 157 */ 158 break; 159 } 160 #if defined(sparc) 161 if (!(cur_ctlr->ctlr_flags & DKI_BAD144)) 162 return; 163 /* 164 * The disk uses BAD144, read in the bad-block table. 165 */ 166 for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) { 167 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, 168 (diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1, 169 &badmap, F_NORMAL, NULL); 170 if (status) 171 continue; 172 /* 173 * Do a sanity check on the list read in. If it passes, 174 * stop searching. 175 */ 176 if (badmap.bt_mbz != 0) 177 continue; 178 for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++) { 179 if (bt->bt_cyl < 0) 180 break; 181 if (bt->bt_trksec < 0) 182 continue; 183 head = bt->bt_trksec >> 8; 184 if ((bt->bt_cyl >= pcyl) || (head >= nhead) || 185 ((bt->bt_trksec & 0xff) >= sectors(head))) { 186 status = -1; 187 break; 188 } 189 } 190 if (status) 191 continue; 192 return; 193 } 194 /* 195 * If we couldn't find the bad block table, initialize it to 196 * zero entries. 197 */ 198 for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++) 199 bt->bt_cyl = bt->bt_trksec = -1; 200 badmap.bt_mbz = badmap.bt_csn = badmap.bt_flag = 0; 201 #endif /* defined(sparc) */ 202 } 203 204 /* 205 * This routine either checks or calculates the checksum for a defect 206 * list, depending on the mode parameter. In check mode, it returns 207 * whether or not the checksum is correct. 208 */ 209 int 210 checkdefsum(struct defect_list *list, int mode) 211 { 212 register int *lp, i, sum = 0; 213 214 /* 215 * Perform the rolling xor to get what the checksum should be. 216 */ 217 lp = (int *)list->list; 218 for (i = 0; i < (list->header.count * 219 sizeof (struct defect_entry) / sizeof (int)); i++) 220 sum ^= *(lp + i); 221 /* 222 * If in check mode, return whether header checksum was correct. 223 */ 224 if (mode == CK_CHECKSUM) 225 return (sum != list->header.cksum); 226 /* 227 * If in create mode, set the header checksum. 228 */ 229 else { 230 list->header.cksum = sum; 231 return (0); 232 } 233 } 234 235 /* 236 * This routine prints a single defect to stdout in a readable format. 237 */ 238 void 239 pr_defect(struct defect_entry *def, int num) 240 { 241 242 /* 243 * Make defect numbering look 1 relative. 244 */ 245 ++num; 246 /* 247 * Print out common values. 248 */ 249 fmt_print("%4d%8d%7d", num, def->cyl, def->head); 250 /* 251 * The rest of the values may be unknown. If they are, just 252 * print blanks instead. Also, only print length only if bfi is 253 * known, and assume that a known bfi implies an unknown sect. 254 */ 255 if (def->bfi != UNKNOWN) { 256 fmt_print("%8d", def->bfi); 257 if (def->nbits != UNKNOWN) 258 fmt_print("%8d", def->nbits); 259 } else { 260 fmt_print(" "); 261 fmt_print("%8d", def->sect); 262 fmt_print("%8lu", chs2bn(def->cyl, def->head, def->sect)); 263 } 264 fmt_print("\n"); 265 } 266 267 /* 268 * This routine calculates where in a defect list a given defect should 269 * be sorted. It returns the index that the defect should become. The 270 * algorithm used sorts all bfi based defects by cylinder/head/bfi, and 271 * adds all logical sector defects to the end of the list. This is 272 * necessary because the ordering of logical sector defects is significant 273 * when sector slipping is employed. 274 */ 275 int 276 sort_defect(struct defect_entry *def, struct defect_list *list) 277 { 278 struct defect_entry *ptr; 279 280 /* 281 * If it's a logical sector defect, return the entry at the end 282 * of the list. 283 */ 284 if (def->bfi == UNKNOWN) 285 return (list->header.count); 286 /* 287 * It's a bfi defect. Loop through the defect list. 288 */ 289 for (ptr = list->list; ptr - list->list < list->header.count; ptr++) { 290 /* 291 * If we get to a logical sector defect, put this defect 292 * right before it. 293 */ 294 if (ptr->bfi == UNKNOWN) 295 goto found; 296 /* 297 * If we get to a defect that is past this one in 298 * cylinder/head/bfi, put this defect right before it. 299 */ 300 if (def->cyl < ptr->cyl) 301 goto found; 302 if (def->cyl != ptr->cyl) 303 continue; 304 if (def->head < ptr->head) 305 goto found; 306 if (def->head != ptr->head) 307 continue; 308 if (def->bfi < ptr->bfi) 309 goto found; 310 } 311 found: 312 /* 313 * Return the index to put the defect at. 314 */ 315 return (ptr - list->list); 316 } 317 318 /* 319 * This routine writes the defect list on the back on the disk. It also 320 * writes the bad block table to disk if bad-144 mapping applies to the 321 * current disk. 322 */ 323 void 324 write_deflist(struct defect_list *list) 325 { 326 int size, head, status; 327 328 #if defined(sparc) 329 int sec; 330 caddr_t bad_ptr = (caddr_t)&badmap; 331 #endif /* defined(sparc) */ 332 333 assert(!EMBEDDED_SCSI); 334 335 /* 336 * Sparc ATA IDE. 337 * This indicates that no list manipulation is done in this controller 338 * and hence return without any other checking. 339 */ 340 if (cur_ctype->ctype_flags & CF_NOWLIST) { 341 return; 342 } 343 344 /* 345 * Panther's working list is maintained by the controller 346 */ 347 if (cur_ctype->ctype_flags & CF_WLIST) { 348 (*cur_ops->op_wr_cur)(list); 349 return; 350 } 351 352 /* 353 * If the list is null, there is nothing to write. 354 */ 355 if (list->list != NULL) { 356 /* 357 * calculate how many sectors the defect list will occupy. 358 */ 359 size = LISTSIZE(list->header.count); 360 /* 361 * Loop for each copy of the list to be written. Write 362 * out the header of the list followed by the data. 363 */ 364 for (head = 0; head < LISTCOUNT; head++) { 365 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, 366 (diskaddr_t)chs2bn(ncyl + 1, head, 0), 1, 367 (char *)&list->header, F_NORMAL, NULL); 368 if (status) { 369 err_print( 370 "Warning: error saving defect list.\n"); 371 continue; 372 } 373 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, 374 (diskaddr_t)chs2bn(ncyl + 1, head, 1), size, 375 (char *)list->list, F_NORMAL, NULL); 376 if (status) 377 err_print( 378 "Warning: error saving defect list.\n"); 379 } 380 } 381 if (!(cur_ctlr->ctlr_flags & DKI_BAD144)) 382 return; 383 #if defined(sparc) 384 /* 385 * Current disk uses bad-144 mapping. Loop for each copy of the 386 * bad block table to be written and write it out. 387 */ 388 for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) { 389 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, 390 (diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1, 391 &badmap, F_NORMAL, NULL); 392 if (status) { 393 err_print( 394 "Warning: error saving bad block map table.\n"); 395 continue; 396 } 397 } 398 /* 399 * Execute an ioctl to tell unix about the new bad block table. 400 */ 401 if (ioctl(cur_file, HDKIOCSBAD, &bad_ptr)) 402 err_print( 403 "Warning: error telling SunOS bad block map table.\n"); 404 #endif /* defined(sparc) */ 405 } 406 407 /* 408 * This routine adds a logical sector to the given defect list. 409 */ 410 void 411 add_ldef(diskaddr_t blkno, struct defect_list *list) 412 { 413 struct defect_entry def; 414 int index; 415 416 417 /* 418 * Calculate the fields for the defect struct. 419 */ 420 def.cyl = bn2c(blkno); 421 def.head = bn2h(blkno); 422 def.sect = bn2s(blkno); 423 /* 424 * Initialize the unknown fields. 425 */ 426 def.bfi = def.nbits = UNKNOWN; 427 /* 428 * Calculate the index into the list that the defect belongs at. 429 */ 430 index = sort_defect(&def, list); 431 /* 432 * Add the defect to the list. 433 */ 434 add_def(&def, list, index); 435 } 436 437 /* 438 * This routine adds the given defect struct to the defect list at 439 * a precalculated index. 440 */ 441 void 442 add_def(struct defect_entry *def, struct defect_list *list, int index) 443 { 444 int count, i; 445 446 /* 447 * If adding this defect makes the list overflow into another 448 * sector, allocate the necessary space. 449 */ 450 count = list->header.count; 451 if (LISTSIZE(count + 1) > LISTSIZE(count)) 452 list->list = (struct defect_entry *)rezalloc((void *)list->list, 453 LISTSIZE(count + 1) * SECSIZE); 454 /* 455 * Slip all the defects after this one down one slot in the list. 456 */ 457 for (i = count; i > index; i--) 458 *(list->list + i) = *(list->list + i - 1); 459 /* 460 * Fill in the created hole with this defect. 461 */ 462 *(list->list + i) = *def; 463 /* 464 * Increment the count and calculate a new checksum. 465 */ 466 list->header.count++; 467 (void) checkdefsum(list, CK_MAKESUM); 468 } 469 470 /* 471 * This routine sets the given defect list back to null. 472 */ 473 void 474 kill_deflist(struct defect_list *list) 475 { 476 477 /* 478 * If it's already null, we're done. 479 */ 480 if (list->list == NULL) 481 return; 482 /* 483 * Free the malloc'd space it's using. 484 */ 485 destroy_data((char *)list->list); 486 /* 487 * Mark it as null, and clear any flags. 488 */ 489 list->list = NULL; 490 list->flags = 0; 491 } 492