1 /* @(#)badblock.c	1.21 09/10/16 Copyright 1988-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)badblock.c	1.21 09/10/16 Copyright 1988-2009 J. Schilling";
6 #endif
7 /*
8  *	Handle defects (SCSI level)
9  *
10  *	Copyright (c) 1988-2009 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/stdio.h>
27 #include <schily/types.h>
28 #include <schily/stdlib.h>
29 #include <schily/standard.h>
30 #include <schily/schily.h>
31 
32 #include <scg/scsireg.h>
33 #include <scg/scsitransp.h>
34 
35 #include "scsicmds.h"
36 #include "defect.h"
37 #include <schily/intcvt.h>
38 #include "fmt.h"
39 
40 extern	int	reassign;
41 
42 extern	int	format_done;
43 
44 LOCAL	long	bad[1024];
45 LOCAL	int	maxbad	= (sizeof (bad)-sizeof (struct scsi_def_header))/sizeof (bad[0]);
46 LOCAL	int	num_bad;
47 
48 EXPORT	void	clear_bad		__PR((void));
49 EXPORT	int	get_nbad		__PR((void));
50 EXPORT	void	insert_bad		__PR((long baddr));
51 EXPORT	int	print_bad		__PR((void));
52 EXPORT	int	bad_to_def		__PR((SCSI *scgp));
53 EXPORT	void	reassign_bad		__PR((SCSI *scgp));
54 LOCAL	void	reassign_found_blocks	__PR((SCSI *scgp, int nbad));
55 EXPORT	void	repair_found_blocks	__PR((SCSI *scgp, int nbad));
56 EXPORT	void	reassign_one		__PR((SCSI *scgp));
57 EXPORT	int	reassign_one_block	__PR((SCSI *scgp, long n));
58 EXPORT	void	print_defect_list	__PR((struct scsi_def_list *l));
59 LOCAL	void	print_def_block		__PR((struct scsi_def_list *l));
60 EXPORT	void	print_def_bfi		__PR((struct scsi_def_list *l));
61 LOCAL	void	print_def_phys		__PR((struct scsi_def_list *l));
62 LOCAL	void	print_def_head		__PR((struct scsi_def_list *l, int ndef));
63 
64 EXPORT void
clear_bad()65 clear_bad()
66 {
67 	fillbytes((caddr_t)bad, sizeof (bad), '\0');
68 	num_bad = 0;
69 }
70 
71 EXPORT int
get_nbad()72 get_nbad()
73 {
74 	return (num_bad);
75 }
76 
77 EXPORT void
insert_bad(baddr)78 insert_bad(baddr)
79 	register long	baddr;
80 {
81 	register int	i;
82 	register long	x;
83 
84 	for (i = 1; i <= num_bad; i++) {
85 		x = a_to_4_byte(&bad[i]);
86 		if (x == baddr)
87 			return;
88 	}
89 	if (++num_bad > maxbad)
90 		comerrno(EX_BAD, "Too many bad blocks (max is %d)\n", maxbad);
91 	i_to_4_byte(&bad[num_bad], baddr);
92 }
93 
94 #ifdef	used
cmp_bad(ap,bp)95 cmp_bad(ap, bp)
96 	long	*ap;
97 	long	*bp;
98 {
99 	long	la;
100 	long	lb;
101 
102 	la = a_to_4_byte(ap);
103 	lb = a_to_4_byte(bp);
104 	return (la - lb);
105 }
106 
sort_bad()107 sort_bad()
108 {
109 	qsort((caddr_t)&bad[1], num_bad, sizeof (bad[0]), cmp_bad);
110 }
111 #endif
112 
113 EXPORT int
print_bad()114 print_bad()
115 {
116 	register int	i;
117 
118 	printf("Found %d defects:\n", num_bad);
119 	for (i = 1; i <= num_bad; i++)
120 		printf("%ld\n", a_to_4_byte(&bad[i]));
121 	return (num_bad);
122 }
123 
124 EXPORT int
bad_to_def(scgp)125 bad_to_def(scgp)
126 	SCSI	*scgp;
127 {
128 	register int	err	= 0;
129 	register int	n	= 0;
130 	register int	i;
131 	register int	j;
132 	struct scsi_def_list defl;
133 
134 	fillbytes((caddr_t)&defl, sizeof (defl), '\0');
135 	i = sizeof (struct scsi_def_bfi);	/* Ein Defekt */
136 	i_to_2_byte(defl.hd.length, i);
137 
138 	for (i = 1; i <= num_bad; i++) {
139 		if (translate(scgp, &defl.def_bfi[0],
140 						a_to_4_byte(&bad[i])) < 0) {
141 			scgp->silent++;
142 			for (j = 0; j < 16; j++) {
143 				if (translate(scgp, &defl.def_bfi[0],
144 						a_to_4_byte(&bad[i])) >= 0)
145 					break;
146 			}
147 			scgp->silent--;
148 			if (j == 16) {
149 				err++;
150 				error("Repair Block %ld by hand.\n\n",
151 						a_to_4_byte(&bad[i]));
152 				continue;
153 			}
154 		}
155 		n++;
156 		print_def_bfi(&defl);
157 		add_def_bfi(&defl.def_bfi[0]);
158 	}
159 	if (err) {
160 		printf("%d Block%s could not be translated.\n",
161 						err, err > 1 ? "s":"");
162 	}
163 	return (n);
164 }
165 
166 EXPORT void
reassign_bad(scgp)167 reassign_bad(scgp)
168 	SCSI	*scgp;
169 {
170 	if (format_done) {
171 #ifdef	this_really_is_correct
172 		/*
173 		 * Some disks (e.g. IBM) have problems when getting
174 		 * a list that contains more than one entry.
175 		 */
176 		(void) reassign_block((struct scsi_def_list *)bad, num_bad);
177 		(void) rezero_unit();
178 #else
179 		reassign_found_blocks(scgp, num_bad);
180 #endif
181 	} else if (yes("Reassign found bad blocks? ")) {
182 		printf("The disk has not been modified now.\n");
183 		printf("If the data may get entirely lost and you don't want to wait a long time\n");
184 		printf("for trying to retrieve old data, you may choose the quick way.\n");
185 		printf("NOTE: if the disk is not formatted after that, the blocks may remain bad.\n");
186 		if (yes("Quick reassign of bad blocks ?"))
187 			reassign_found_blocks(scgp, num_bad);
188 		else
189 			repair_found_blocks(scgp, num_bad);
190 	}
191 }
192 
193 #ifdef	used
copy_def_block()194 copy_def_block()
195 {
196 	register struct scsi_def_list *l;
197 	register int	ndef;
198 	register int	n;
199 	register int	i;
200 	register long	x;
201 
202 	l = (struct scsi_def_list *)Sbuf;
203 	i = a_to_u_2_byte(l->hd.length);
204 	ndef = i/sizeof (l->def_phys[0]);
205 
206 	for (n = 1, i = 0; i < ndef; i++) {
207 		x = a_to_4_byte(l->def_block[i]);
208 		if (x == -1)
209 			continue;
210 		i_to_4_byte(&bad[n++], x);
211 	}
212 	num_bad = --n;
213 }
214 #endif
215 
216 LOCAL void
reassign_found_blocks(scgp,nbad)217 reassign_found_blocks(scgp, nbad)
218 	SCSI	*scgp;
219 	int	nbad;
220 {
221 	int	i;
222 
223 	for (i = 1; i <= nbad; i++) {
224 		(void) reassign_one_block(scgp, a_to_4_byte(&bad[i]));
225 		(void) rezero_unit(scgp);
226 	}
227 }
228 
229 EXPORT void
repair_found_blocks(scgp,nbad)230 repair_found_blocks(scgp, nbad)
231 	SCSI	*scgp;
232 	int	nbad;
233 {
234 	int	i;
235 
236 	for (i = 1; i <= nbad; i++) {
237 		(void) ext_reassign_block(scgp, a_to_4_byte(&bad[i]));
238 		(void) rezero_unit(scgp);
239 	}
240 }
241 
242 EXPORT void
reassign_one(scgp)243 reassign_one(scgp)
244 	SCSI	*scgp;
245 {
246 	long	b = -1L;
247 
248 	if (!reassign) {
249 		error("WARNING: If you are no guru hit ^C and try -reassign option\n");
250 		getlong("Block Address", &b, 0L, scgp->cap->c_baddr);
251 		(void) reassign_one_block(scgp, b);
252 		(void) rezero_unit(scgp);
253 	} else {
254 		do {
255 			getlong("Block Address", &b, 0L, scgp->cap->c_baddr);
256 			(void) ext_reassign_block(scgp, b);
257 			(void) rezero_unit(scgp);
258 		} while (yes("Do you wish to reassign another block? "));
259 	}
260 	exit(0);
261 }
262 
263 EXPORT int
reassign_one_block(scgp,n)264 reassign_one_block(scgp, n)
265 	SCSI	*scgp;
266 	long	n;
267 {
268 	struct scsi_def_list d;
269 
270 	i_to_4_byte(d.def_list.list_block[0], n);
271 	return (reassign_block(scgp, &d, 1));
272 }
273 
274 EXPORT void
print_defect_list(l)275 print_defect_list(l)
276 	struct scsi_def_list	*l;
277 {
278 	printf("format: %d\n", (int)l->hd.format);
279 	switch (l->hd.format) {
280 
281 	case SC_DEF_BLOCK :
282 	case SC_DEF_BLOCK | 1 :
283 	case SC_DEF_BLOCK | 2 :
284 	case SC_DEF_BLOCK | 3 :
285 			print_def_block(l);
286 			return;
287 	case SC_DEF_BFI  :
288 			print_def_bfi(l);
289 			return;
290 	case SC_DEF_PHYS :
291 			print_def_phys(l);
292 			return;
293 	default:
294 			printf("Unknown defect list format\n");
295 			return;
296 	}
297 
298 }
299 
300 LOCAL void
print_def_block(l)301 print_def_block(l)
302 	register struct scsi_def_list *l;
303 {
304 	register int	ndef;
305 	register int	i;
306 
307 	i = a_to_u_2_byte(l->hd.length);
308 	ndef = i/sizeof (l->def_block[0]);
309 
310 	print_def_head(l, ndef);
311 	for (i = 0; i < ndef; i++) {
312 		printf("%3d Block %7ld\n", i, a_to_4_byte(l->def_block[i]));
313 	}
314 	flush();
315 }
316 
317 EXPORT void
print_def_bfi(l)318 print_def_bfi(l)
319 	register struct scsi_def_list *l;
320 {
321 	register int	ndef;
322 	register int	i;
323 
324 	i = a_to_u_2_byte(l->hd.length);
325 	ndef = i/sizeof (l->def_bfi[0]);
326 
327 	print_def_head(l, ndef);
328 	for (i = 0; i < ndef; i++) {
329 		printf("%3d Cyl %5lu  Head %2d  bfi %7ld\n",
330 			i,
331 			a_to_u_3_byte(l->def_bfi[i].cyl),
332 			l->def_bfi[i].head,
333 			a_to_4_byte(l->def_bfi[i].bfi));
334 	}
335 	flush();
336 }
337 
338 LOCAL void
print_def_phys(l)339 print_def_phys(l)
340 	register struct scsi_def_list *l;
341 {
342 	register int	ndef;
343 	register int	i;
344 
345 	i = a_to_u_2_byte(l->hd.length);
346 	ndef = i/sizeof (l->def_phys[0]);
347 
348 	print_def_head(l, ndef);
349 	for (i = 0; i < ndef; i++) {
350 		printf("%3d Cyl %5lu  Head %2d  Sec %2ld\n",
351 			i,
352 			a_to_u_3_byte(l->def_phys[i].cyl),
353 			l->def_phys[i].head,
354 			a_to_4_byte(l->def_phys[i].sec));
355 	}
356 	flush();
357 }
358 
359 LOCAL void
print_def_head(l,ndef)360 print_def_head(l, ndef)
361 	register struct scsi_def_list *l;
362 		int	ndef;
363 {
364 	if (l->hd.mdl)
365 		printf("Manufacturer defect list ");
366 	if (l->hd.gdl)
367 		printf("Grown defect list ");
368 	if (ndef > 1)
369 		printf("total of %d defects.\n", ndef);
370 	else if (l->hd.mdl || l->hd.gdl)
371 		printf("\n");
372 }
373