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