Commit | Line | Data |
---|---|---|
0f3feeae | 1 | /* format.c 6.2 83/09/18 */ |
001cf9d7 SL |
2 | |
3 | /* | |
4 | * Standalone program to do media checking | |
5 | * and record bad block information on any | |
0f3feeae | 6 | * disk with the appropriate driver and RM03-style headers. |
001cf9d7 SL |
7 | */ |
8 | #include "../h/param.h" | |
9 | #include "../h/fs.h" | |
10 | #include "../h/inode.h" | |
11 | #include "../h/dkbad.h" | |
12 | #include "../h/vmmac.h" | |
13 | ||
14 | #include "saio.h" | |
15 | #include "savax.h" | |
16 | ||
17 | #define MAXBADDESC 126 /* size of bad block table */ | |
18 | #define CHUNK 48 /* max # of sectors/io operation */ | |
19 | #define SECTSIZ 512 /* standard sector size */ | |
20 | #define HDRSIZ 4 /* number of bytes in sector header */ | |
21 | ||
22 | #define SSERR 0 | |
23 | #define BSERR 1 | |
24 | ||
25 | #define SSDEV ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0)) | |
26 | ||
27 | struct sector { | |
28 | u_short header1; | |
29 | u_short header2; | |
30 | char buf[SECTSIZ]; | |
31 | }; | |
32 | ||
33 | struct dkbad dkbad; /* bad sector table */ | |
34 | struct dkbad sstab; /* skip sector table */ | |
35 | ||
36 | #define NERRORS 6 | |
c68cea4f SL |
37 | static char * |
38 | errornames[NERRORS] = { | |
0f3feeae | 39 | #define FE_BSE 0 |
001cf9d7 | 40 | "Bad sector", |
0f3feeae MK |
41 | #define FE_WCE 1 |
42 | "Write check", | |
001cf9d7 SL |
43 | #define FE_ECC 2 |
44 | "ECC", | |
45 | #define FE_HARD 3 | |
46 | "Other hard", | |
47 | #define FE_TOTAL 4 | |
48 | "Total", | |
49 | #define FE_SSE 5 | |
50 | "Skip sector", | |
51 | }; | |
52 | ||
53 | int errors[NERRORS]; /* histogram of errors */ | |
c68cea4f | 54 | int pattern; |
001cf9d7 SL |
55 | |
56 | char *malloc(); | |
57 | char *prompt(); | |
58 | extern int end; | |
59 | ||
60 | main() | |
61 | { | |
62 | register int sector, sn; | |
c68cea4f | 63 | int lastsector, tracksize; |
001cf9d7 SL |
64 | int unit, fd, resid, i, trk, cyl, debug; |
65 | struct st st; | |
66 | struct sector *bp, *cbp; | |
67 | char *cp; | |
68 | ||
69 | printf("Disk format/check utility\n\n"); | |
70 | ||
71 | again: | |
72 | cp = prompt("Enable debugging (1=bse, 2=ecc, 3=bse+ecc)? "); | |
73 | debug = atoi(cp); | |
74 | if (debug < 0) | |
75 | debug = 0; | |
76 | for (i = 0; i < NERRORS; i++) | |
77 | errors[i] = 0; | |
78 | fd = getdevice(); | |
79 | ioctl(fd, SAIODEVDATA, &st); | |
80 | printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n", | |
81 | st.ncyl, st.ntrak, st.nsect); | |
c68cea4f | 82 | if (getpattern()) |
001cf9d7 SL |
83 | goto again; |
84 | printf("Start formatting...make sure the drive is online\n"); | |
85 | ioctl(fd, SAIONOBAD, (char *)0); | |
86 | ioctl(fd, SAIOECCLIM, (char *)0); | |
87 | ioctl(fd, SAIODEBUG, (char *)debug); | |
88 | if (SSDEV) { | |
89 | ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */ | |
90 | st.nsect++; | |
91 | st.nspc += st.ntrak; | |
92 | } | |
93 | tracksize = sizeof (struct sector) * st.nsect; | |
94 | bp = (struct sector *)malloc(tracksize); | |
c68cea4f | 95 | bufinit(bp, tracksize); |
001cf9d7 SL |
96 | /* |
97 | * Begin check, for each track, | |
98 | * | |
99 | * 1) Write header and test pattern. | |
100 | * 2) Write check header and data. | |
101 | */ | |
102 | lastsector = st.nspc * st.ncyl; | |
103 | for (sector = 0; sector < lastsector; sector += st.nsect) { | |
104 | cyl = sector / st.nspc; | |
105 | trk = (sector % st.nspc) / st.nsect; | |
106 | for (i = 0; i < st.nsect; i++) { | |
107 | bp[i].header1 = | |
108 | (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT; | |
109 | bp[i].header2 = ((u_short)trk << 8) + i; | |
110 | } | |
111 | if (sector && (sector % (st.nspc * 10)) == 0) | |
58c60982 | 112 | printf("cylinder %d\n", cyl); |
001cf9d7 SL |
113 | /* |
114 | * Try and write the headers and data patterns into | |
115 | * each sector in the track. Continue until such | |
116 | * we're done, or until there's less than a sector's | |
117 | * worth of data to transfer. | |
118 | * | |
119 | * The lseek call is necessary because of | |
120 | * the odd sector size (516 bytes) | |
121 | */ | |
122 | for (resid = tracksize, cbp = bp, sn = sector;;) { | |
123 | int cc; | |
124 | ||
125 | lseek(fd, sn * SECTSIZ, 0); | |
126 | ioctl(fd, SAIOHDR, (char *)0); | |
127 | cc = write(fd, cbp, resid); | |
128 | if (cc == resid) | |
129 | break; | |
130 | /* | |
131 | * Don't record errors during write, | |
132 | * all errors will be found during | |
133 | * writecheck performed below. | |
134 | */ | |
135 | sn = iob[fd - 3].i_errblk; | |
136 | cbp += sn - sector; | |
137 | resid -= (sn - sector) * sizeof (struct sector); | |
138 | if (resid < sizeof (struct sector)) | |
139 | break; | |
140 | } | |
141 | /* | |
142 | * Write check headers and test patterns. | |
143 | * Retry remainder of track on error until | |
144 | * we're done, or until there's less than a | |
145 | * sector to verify. | |
146 | */ | |
147 | for (resid = tracksize, cbp = bp, sn = sector;;) { | |
148 | int cc; | |
149 | ||
150 | lseek(fd, sn * SECTSIZ, 0); | |
151 | ioctl(fd, SAIOHCHECK, (char *)0); | |
152 | cc = read(fd, cbp, resid); | |
153 | if (cc == resid) | |
154 | break; | |
155 | sn = iob[fd-3].i_errblk; | |
156 | printf("sector %d, write check error\n", sn); | |
157 | recorderror(fd, sn, &st); | |
158 | /* advance past bad sector */ | |
159 | sn++; | |
160 | cbp += sn - sector; | |
161 | resid -= (sn - sector) * sizeof (struct sector); | |
162 | if (resid < sizeof (struct sector)) | |
163 | break; | |
164 | } | |
165 | } | |
166 | /* | |
167 | * Checking finished. | |
168 | */ | |
169 | if (errors[FE_TOTAL] || errors[FE_SSE]) { | |
170 | printf("Errors:\n"); | |
171 | for (i = 0; i < NERRORS; i++) | |
172 | printf("%s: %d\n", errornames[i], errors[i]); | |
173 | printf("Total of %d hard errors found\n", | |
174 | errors[FE_TOTAL] + errors[FE_SSE]); | |
175 | /* change the headers of all the bad sectors */ | |
176 | writebb(fd, errors[FE_SSE], &sstab, &st, SSERR); | |
177 | writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR); | |
178 | } | |
179 | while (errors[FE_TOTAL] < MAXBADDESC) { | |
180 | int i = errors[FE_TOTAL]++; | |
181 | ||
182 | dkbad.bt_bad[i].bt_cyl = -1; | |
183 | dkbad.bt_bad[i].bt_trksec = -1; | |
184 | } | |
185 | printf("\nWriting bad sector table at sector #%d\n", | |
186 | st.ncyl * st.nspc - st.nsect); | |
187 | /* place on disk */ | |
188 | for (i = 0; i < 10; i += 2) { | |
189 | lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0); | |
190 | write(fd, &dkbad, sizeof (dkbad)); | |
191 | } | |
192 | printf("Done\n"); | |
193 | ioctl(fd,SAIONOSSI,(char *)0); | |
194 | close(fd); | |
195 | #ifndef JUSTEXIT | |
196 | goto again; | |
197 | #endif | |
198 | } | |
199 | ||
001cf9d7 SL |
200 | /* |
201 | * Write out the bad blocks. | |
202 | */ | |
203 | writebb(fd, nsects, dbad, st, sw) | |
204 | int nsects, fd; | |
205 | struct dkbad *dbad; | |
206 | register struct st *st; | |
207 | { | |
208 | struct sector bb_buf; /* buffer for one sector plus 4 byte header */ | |
209 | register int i; | |
210 | int bn, j; | |
211 | struct bt_bad *btp; | |
212 | ||
213 | for (i = 0; i < nsects; i++) { | |
214 | btp = &dbad->bt_bad[i]; | |
215 | if (sw == BSERR) { | |
216 | bb_buf.header1 = HDR1_FMT22|btp->bt_cyl; | |
217 | if (SSDEV) | |
218 | bb_buf.header1 |= HDR1_SSF; | |
219 | } else | |
220 | bb_buf.header1 = | |
221 | btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT; | |
222 | bb_buf.header2 = btp->bt_trksec; | |
223 | bn = st->nspc * btp->bt_cyl + | |
224 | st->nsect * (btp->bt_trksec >> 8) + | |
0f3feeae | 225 | (btp->bt_trksec & 0xff); |
001cf9d7 SL |
226 | lseek(fd, bn * SECTSIZ, 0); |
227 | ioctl(fd, SAIOHDR, (char *)0); | |
228 | write(fd, &bb_buf, sizeof (bb_buf)); | |
229 | if (!SSDEV) | |
230 | continue; | |
231 | /* | |
232 | * If skip sector, mark all remaining | |
233 | * sectors on the track. | |
234 | */ | |
0f3feeae | 235 | for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) { |
001cf9d7 SL |
236 | bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF; |
237 | ioctl(fd, SAIOHDR, (char *)0); | |
238 | write(fd, &bb_buf, sizeof (bb_buf)); | |
239 | } | |
240 | } | |
241 | } | |
242 | ||
243 | /* | |
244 | * Record an error, and if there's room, put | |
245 | * it in the appropriate bad sector table. | |
246 | */ | |
247 | recorderror(fd, bn, st) | |
248 | int fd, bn; | |
249 | register struct st *st; | |
250 | { | |
251 | int cn, tn, sn, strk; | |
252 | ||
253 | if (errors[FE_TOTAL] >= MAXBADDESC) { | |
254 | printf("Too many bad sectors\n"); | |
255 | return; | |
256 | } | |
257 | if (errors[FE_SSE] >= MAXBADDESC) { | |
258 | printf("Too many skip sector errors\n"); | |
259 | return; | |
260 | } | |
0f3feeae | 261 | if (errno < EBSE || errno > EHER) |
001cf9d7 | 262 | return; |
0f3feeae | 263 | errno -= EBSE; |
001cf9d7 SL |
264 | errors[errno]++; |
265 | cn = bn / st->nspc; | |
266 | sn = bn % st->nspc; | |
267 | tn = sn / st->nsect; | |
268 | sn %= st->nsect; | |
269 | if (SSDEV) { /* if drive has skip sector capability */ | |
270 | int ss = errors[FE_SSE]++; | |
271 | ||
272 | if (ss) | |
273 | strk = sstab.bt_bad[ss - 1].bt_trksec >> 8; | |
274 | else | |
275 | strk = -1; | |
276 | if (tn != strk) { /* only one skip sector/track */ | |
277 | sstab.bt_bad[ss].bt_cyl = cn; | |
278 | sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn; | |
279 | return; | |
280 | } | |
281 | cn = -cn; | |
282 | } | |
283 | /* record the bad sector address and continue */ | |
0f3feeae | 284 | dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn; |
001cf9d7 SL |
285 | dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn; |
286 | } | |
287 | ||
288 | /* | |
289 | * Allocate memory on a page-aligned address. | |
290 | * Round allocated chunk to a page multiple to | |
291 | * ease next request. | |
292 | */ | |
293 | char * | |
294 | malloc(size) | |
295 | int size; | |
296 | { | |
297 | char *result; | |
298 | static caddr_t last = 0; | |
299 | ||
300 | if (last == 0) | |
301 | last = (caddr_t)(((int)&end + 511) & ~0x1ff); | |
302 | size = (size + 511) & ~0x1ff; | |
303 | result = (char *)last; | |
304 | last += size; | |
305 | return (result); | |
306 | } | |
307 | ||
308 | /* | |
309 | * Prompt and verify a device name from the user. | |
310 | */ | |
311 | getdevice() | |
312 | { | |
313 | register char *cp; | |
314 | register struct devsw *dp; | |
315 | int fd; | |
316 | ||
317 | top: | |
318 | cp = prompt("Device to format? "); | |
319 | if ((fd = open(cp, 2)) < 0) { | |
320 | printf("Known devices are: "); | |
321 | for (dp = devsw; dp->dv_name; dp++) | |
322 | printf("%s ",dp->dv_name); | |
323 | printf("\n"); | |
324 | goto top; | |
325 | } | |
326 | printf("Formatting drive %d on %c%c%d ", | |
327 | iob[fd - 3].i_unit % 8, cp[0], cp[1], iob[fd - 3].i_unit / 8); | |
001cf9d7 SL |
328 | cp = prompt("verify (yes/no)? "); |
329 | while (*cp != 'y' && *cp != 'n') | |
330 | cp = prompt("Huh, yes or no? "); | |
331 | if (*cp == 'y') | |
332 | return (fd); | |
333 | goto top; | |
334 | } | |
335 | ||
c68cea4f SL |
336 | static struct pattern { |
337 | long pa_value; | |
338 | char *pa_name; | |
339 | } pat[] = { | |
340 | { 0xf00ff00f, "RH750 worst case" }, | |
341 | { 0xec6dec6d, "media worst case" }, | |
342 | { 0xa5a5a5a5, "alternate 1's and 0's" }, | |
343 | { 0, 0 }, | |
344 | }; | |
345 | ||
346 | getpattern() | |
347 | { | |
348 | register struct pattern *p; | |
349 | int npatterns; | |
350 | char *cp; | |
351 | ||
352 | printf("Available test patterns are:\n"); | |
353 | for (p = pat; p->pa_value; p++) | |
354 | printf("\t%d - (%x) %s\n", (p - pat) + 1, | |
355 | p->pa_value & 0xffff, p->pa_name); | |
356 | npatterns = p - pat; | |
357 | cp = prompt("Pattern (one of the above, other to restart)? "); | |
358 | pattern = atoi(cp) - 1; | |
359 | return (pattern < 0 || pattern >= npatterns); | |
360 | } | |
361 | ||
362 | struct xsect { | |
363 | u_short hd1; | |
364 | u_short hd2; | |
365 | long buf[128]; | |
366 | }; | |
367 | ||
368 | /* | |
369 | * Initialize the buffer with the requested pattern. | |
370 | */ | |
371 | bufinit(bp, size) | |
372 | register struct xsect *bp; | |
373 | int size; | |
374 | { | |
375 | register struct pattern *pptr; | |
376 | register long *pp, *last; | |
377 | register struct xsect *lastbuf; | |
378 | ||
379 | size /= sizeof (struct sector); | |
380 | lastbuf = bp + size; | |
381 | pptr = &pat[pattern]; | |
382 | while (bp < lastbuf) { | |
383 | last = &bp->buf[128]; | |
384 | for (pp = bp->buf; pp < last; pp++) | |
385 | *pp = pptr->pa_value; | |
386 | bp++; | |
387 | } | |
388 | } | |
389 | ||
001cf9d7 SL |
390 | char * |
391 | prompt(msg) | |
392 | char *msg; | |
393 | { | |
394 | static char buf[132]; | |
395 | ||
396 | printf("%s", msg); | |
397 | gets(buf); | |
398 | return (buf); | |
399 | } |