fixes from ghg
[unix-history] / usr / src / sys / vax / stand / format.c
CommitLineData
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
27struct sector {
28 u_short header1;
29 u_short header2;
30 char buf[SECTSIZ];
31};
32
33struct dkbad dkbad; /* bad sector table */
34struct dkbad sstab; /* skip sector table */
35
36#define NERRORS 6
c68cea4f
SL
37static char *
38errornames[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
53int errors[NERRORS]; /* histogram of errors */
c68cea4f 54int pattern;
001cf9d7
SL
55
56char *malloc();
57char *prompt();
58extern int end;
59
60main()
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
71again:
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 */
203writebb(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 */
247recorderror(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 */
293char *
294malloc(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 */
311getdevice()
312{
313 register char *cp;
314 register struct devsw *dp;
315 int fd;
316
317top:
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
336static 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
346getpattern()
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
362struct 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 */
371bufinit(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
390char *
391prompt(msg)
392 char *msg;
393{
394 static char buf[132];
395
396 printf("%s", msg);
397 gets(buf);
398 return (buf);
399}