xref: /illumos-gate/usr/src/cmd/format/defect.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
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