Merge commit '2cedd8f0ecbd2b29bf0aac72bb8b7413b0326938' into merges
[unleashed.git] / usr / src / cmd / format / defect.c
bloba2f77e1032ea69662d6235ff0682f31c5a12064f
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file contains routines that manipulate the defect list.
29 #include "global.h"
30 #include <sys/types.h>
31 #include <sys/param.h>
33 #if defined(sparc)
34 #include <sys/hdio.h>
35 #endif /* defined(sparc) */
37 #include <sys/buf.h>
38 #include <sys/ioctl.h>
39 #include <sys/uio.h>
40 #include <sys/fcntl.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <memory.h>
45 #if defined(sparc)
46 #include <sys/dkbad.h>
47 #endif /* defined(sparc) */
49 #include "misc.h"
50 #include "param.h"
53 #if defined(sparc)
55 * This structure is the bad block table for the current disk if
56 * the disk uses bad-144 defect mapping.
58 struct dkbad badmap;
59 #endif /* defined(sparc) */
62 * This routine reads the defect list off the disk. It also reads in the
63 * bad block table if the disk is a BAD144 type. The defect list is
64 * located on the first 2 tracks of the 2nd alternate cylinder of all
65 * disks. The bad block map is located on the first 5 even sectors of
66 * the last track of the last cylinder.
68 void
69 read_list(struct defect_list *list)
71 int size, head;
73 #if defined(sparc)
74 int sec, status;
75 struct bt_bad *bt;
76 #endif /* defined(sparc) */
78 assert(!EMBEDDED_SCSI);
81 * This flags has been introduced only for Sparc ATA IDE.
82 * This indicates that no list manipulation is done in this controller
83 * and hence return without any other checking.
85 if (cur_ctype->ctype_flags & CF_NOWLIST) {
86 return;
90 * Panther's working list is maintained by the controller
92 if (cur_ctype->ctype_flags & CF_WLIST) {
93 if (*cur_ops->op_ex_cur != NULL &&
94 ((*cur_ops->op_ex_cur)(list)) == 0) {
95 if (list->header.magicno != DEFECT_MAGIC) {
96 fmt_print("Defect list BAD\n");
97 } else {
98 fmt_print("Controller working list found\n");
100 return;
103 if (*cur_ops->op_ex_man != NULL &&
104 ((*cur_ops->op_ex_man)(list)) == 0) {
105 if (list->header.magicno != DEFECT_MAGIC) {
106 fmt_print("Defect list BAD\n");
107 } else {
108 fmt_print("MANUFACTURER's list found\n");
110 return;
112 fmt_print("No defect list found\n");
113 return;
117 * Loop for each copy of the defect list until we get a good one.
119 for (head = 0; head < LISTCOUNT; head++) {
121 * Try to read the list header.
123 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file,
124 (diskaddr_t)chs2bn(ncyl + 1, head, 0), 1,
125 (char *)&list->header, NULL), F_NORMAL)
126 continue;
128 * If the magic number is wrong, this copy is corrupt.
130 if (list->header.magicno != DEFECT_MAGIC)
131 continue;
133 * Allocate space for the rest of the list.
135 size = deflist_size(cur_blksz, list->header.count);
136 list->list = (struct defect_entry *)zalloc(size * cur_blksz);
138 * Try to read in the rest of the list. If there is an
139 * error, or the checksum is wrong, this copy is corrupt.
141 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file,
142 (diskaddr_t)chs2bn(ncyl + 1, head, 1), size,
143 (char *)list->list, F_NORMAL, NULL) ||
144 checkdefsum(list, CK_CHECKSUM)) {
146 * Destroy the list and go on.
148 kill_deflist(list);
149 continue;
152 * Got a good copy, stop searching.
154 break;
156 #if defined(sparc)
157 if (!(cur_ctlr->ctlr_flags & DKI_BAD144))
158 return;
160 * The disk uses BAD144, read in the bad-block table.
162 for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) {
163 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file,
164 (diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1,
165 &badmap, F_NORMAL, NULL);
166 if (status)
167 continue;
169 * Do a sanity check on the list read in. If it passes,
170 * stop searching.
172 if (badmap.bt_mbz != 0)
173 continue;
174 for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++) {
175 if (bt->bt_cyl < 0)
176 break;
177 if (bt->bt_trksec < 0)
178 continue;
179 head = bt->bt_trksec >> 8;
180 if ((bt->bt_cyl >= pcyl) || (head >= nhead) ||
181 ((bt->bt_trksec & 0xff) >= sectors(head))) {
182 status = -1;
183 break;
186 if (status)
187 continue;
188 return;
191 * If we couldn't find the bad block table, initialize it to
192 * zero entries.
194 for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++)
195 bt->bt_cyl = bt->bt_trksec = -1;
196 badmap.bt_mbz = badmap.bt_csn = badmap.bt_flag = 0;
197 #endif /* defined(sparc) */
201 * This routine either checks or calculates the checksum for a defect
202 * list, depending on the mode parameter. In check mode, it returns
203 * whether or not the checksum is correct.
206 checkdefsum(struct defect_list *list, int mode)
208 register int *lp, i, sum = 0;
211 * Perform the rolling xor to get what the checksum should be.
213 lp = (int *)list->list;
214 for (i = 0; i < (list->header.count *
215 sizeof (struct defect_entry) / sizeof (int)); i++)
216 sum ^= *(lp + i);
218 * If in check mode, return whether header checksum was correct.
220 if (mode == CK_CHECKSUM)
221 return (sum != list->header.cksum);
223 * If in create mode, set the header checksum.
225 else {
226 list->header.cksum = sum;
227 return (0);
232 * This routine prints a single defect to stdout in a readable format.
234 void
235 pr_defect(struct defect_entry *def, int num)
239 * Make defect numbering look 1 relative.
241 ++num;
243 * Print out common values.
245 fmt_print("%4d%8d%7d", num, def->cyl, def->head);
247 * The rest of the values may be unknown. If they are, just
248 * print blanks instead. Also, only print length only if bfi is
249 * known, and assume that a known bfi implies an unknown sect.
251 if (def->bfi != UNKNOWN) {
252 fmt_print("%8d", def->bfi);
253 if (def->nbits != UNKNOWN)
254 fmt_print("%8d", def->nbits);
255 } else {
256 fmt_print(" ");
257 fmt_print("%8d", def->sect);
258 fmt_print("%8llu", chs2bn(def->cyl, def->head, def->sect));
260 fmt_print("\n");
264 * This routine calculates where in a defect list a given defect should
265 * be sorted. It returns the index that the defect should become. The
266 * algorithm used sorts all bfi based defects by cylinder/head/bfi, and
267 * adds all logical sector defects to the end of the list. This is
268 * necessary because the ordering of logical sector defects is significant
269 * when sector slipping is employed.
272 sort_defect(struct defect_entry *def, struct defect_list *list)
274 struct defect_entry *ptr;
277 * If it's a logical sector defect, return the entry at the end
278 * of the list.
280 if (def->bfi == UNKNOWN)
281 return (list->header.count);
283 * It's a bfi defect. Loop through the defect list.
285 for (ptr = list->list; ptr - list->list < list->header.count; ptr++) {
287 * If we get to a logical sector defect, put this defect
288 * right before it.
290 if (ptr->bfi == UNKNOWN)
291 goto found;
293 * If we get to a defect that is past this one in
294 * cylinder/head/bfi, put this defect right before it.
296 if (def->cyl < ptr->cyl)
297 goto found;
298 if (def->cyl != ptr->cyl)
299 continue;
300 if (def->head < ptr->head)
301 goto found;
302 if (def->head != ptr->head)
303 continue;
304 if (def->bfi < ptr->bfi)
305 goto found;
307 found:
309 * Return the index to put the defect at.
311 return (ptr - list->list);
315 * This routine writes the defect list on the back on the disk. It also
316 * writes the bad block table to disk if bad-144 mapping applies to the
317 * current disk.
319 void
320 write_deflist(struct defect_list *list)
322 int size, head, status;
324 #if defined(sparc)
325 int sec;
326 caddr_t bad_ptr = (caddr_t)&badmap;
327 #endif /* defined(sparc) */
329 assert(!EMBEDDED_SCSI);
332 * Sparc ATA IDE.
333 * This indicates that no list manipulation is done in this controller
334 * and hence return without any other checking.
336 if (cur_ctype->ctype_flags & CF_NOWLIST) {
337 return;
341 * Panther's working list is maintained by the controller
343 if (cur_ctype->ctype_flags & CF_WLIST) {
344 (*cur_ops->op_wr_cur)(list);
345 return;
349 * If the list is null, there is nothing to write.
351 if (list->list != NULL) {
353 * calculate how many sectors the defect list will occupy.
355 size = deflist_size(cur_blksz, list->header.count);
357 * Loop for each copy of the list to be written. Write
358 * out the header of the list followed by the data.
360 for (head = 0; head < LISTCOUNT; head++) {
361 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
362 (diskaddr_t)chs2bn(ncyl + 1, head, 0), 1,
363 (char *)&list->header, F_NORMAL, NULL);
364 if (status) {
365 err_print(
366 "Warning: error saving defect list.\n");
367 continue;
369 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
370 (diskaddr_t)chs2bn(ncyl + 1, head, 1), size,
371 (char *)list->list, F_NORMAL, NULL);
372 if (status)
373 err_print(
374 "Warning: error saving defect list.\n");
377 if (!(cur_ctlr->ctlr_flags & DKI_BAD144))
378 return;
379 #if defined(sparc)
381 * Current disk uses bad-144 mapping. Loop for each copy of the
382 * bad block table to be written and write it out.
384 for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) {
385 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
386 (diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1,
387 &badmap, F_NORMAL, NULL);
388 if (status) {
389 err_print(
390 "Warning: error saving bad block map table.\n");
391 continue;
395 * Execute an ioctl to tell unix about the new bad block table.
397 if (ioctl(cur_file, HDKIOCSBAD, &bad_ptr))
398 err_print(
399 "Warning: error telling SunOS bad block map table.\n");
400 #endif /* defined(sparc) */
404 * This routine adds a logical sector to the given defect list.
406 void
407 add_ldef(diskaddr_t blkno, struct defect_list *list)
409 struct defect_entry def;
410 int index;
414 * Calculate the fields for the defect struct.
416 def.cyl = bn2c(blkno);
417 def.head = bn2h(blkno);
418 def.sect = bn2s(blkno);
420 * Initialize the unknown fields.
422 def.bfi = def.nbits = UNKNOWN;
424 * Calculate the index into the list that the defect belongs at.
426 index = sort_defect(&def, list);
428 * Add the defect to the list.
430 add_def(&def, list, index);
434 * This routine adds the given defect struct to the defect list at
435 * a precalculated index.
437 void
438 add_def(struct defect_entry *def, struct defect_list *list, int index)
440 int count, i;
443 * If adding this defect makes the list overflow into another
444 * sector, allocate the necessary space.
446 count = list->header.count;
447 if (deflist_size(cur_blksz, count + 1) > deflist_size(cur_blksz, count))
448 list->list = (struct defect_entry *)rezalloc((void *)list->list,
449 deflist_size(cur_blksz, count + 1) * cur_blksz);
451 * Slip all the defects after this one down one slot in the list.
453 for (i = count; i > index; i--)
454 *(list->list + i) = *(list->list + i - 1);
456 * Fill in the created hole with this defect.
458 *(list->list + i) = *def;
460 * Increment the count and calculate a new checksum.
462 list->header.count++;
463 (void) checkdefsum(list, CK_MAKESUM);
467 * This routine sets the given defect list back to null.
469 void
470 kill_deflist(struct defect_list *list)
474 * If it's already null, we're done.
476 if (list->list == NULL)
477 return;
479 * Free the malloc'd space it's using.
481 destroy_data((char *)list->list);
483 * Mark it as null, and clear any flags.
485 list->list = NULL;
486 list->flags = 0;
490 * This routine returns the defect list size
491 * according to the sector size.
494 deflist_size(int secsz, int sz)
496 int rval;
498 if (secsz == 0) {
499 secsz = SECSIZE;
502 rval = sz ? ((sz * sizeof (struct defect_entry) +
503 secsz - 1) / secsz) : 1;
505 return (rval);