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