1 /* 2 * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: src/usr.sbin/fdformat/fdformat.c,v 1.11.2.4 2001/07/19 13:20:42 joerg Exp $ 27 */ 28 29 /* 30 * FreeBSD: 31 * format a floppy disk 32 * 33 * Added FD_GTYPE ioctl, verifying, proportional indicators. 34 * Serge Vakulenko, vak@zebub.msk.su 35 * Sat Dec 18 17:45:47 MSK 1993 36 * 37 * Final adaptation, change format/verify logic, add separate 38 * format gap/interleave values 39 * Andrew A. Chernov, ache@astral.msk.su 40 * Thu Jan 27 00:47:24 MSK 1994 41 */ 42 43 #include <ctype.h> 44 #include <err.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <paths.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <strings.h> 51 #include <unistd.h> 52 53 #include <machine/ioctl_fd.h> 54 55 static void 56 format_track(int fd, int cyl, int secs, int head, int rate, 57 int gaplen, int secsize, int fill,int interleave) 58 { 59 struct fd_formb f; 60 register int i,j; 61 int il[FD_MAX_NSEC + 1]; 62 63 memset(il,0,sizeof il); 64 for(j = 0, i = 1; i <= secs; i++) { 65 while(il[(j%secs)+1]) j++; 66 il[(j%secs)+1] = i; 67 j += interleave; 68 } 69 70 f.format_version = FD_FORMAT_VERSION; 71 f.head = head; 72 f.cyl = cyl; 73 f.transfer_rate = rate; 74 75 f.fd_formb_secshift = secsize; 76 f.fd_formb_nsecs = secs; 77 f.fd_formb_gaplen = gaplen; 78 f.fd_formb_fillbyte = fill; 79 for(i = 0; i < secs; i++) { 80 f.fd_formb_cylno(i) = cyl; 81 f.fd_formb_headno(i) = head; 82 f.fd_formb_secno(i) = il[i+1]; 83 f.fd_formb_secsize(i) = secsize; 84 } 85 if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) 86 err(1, "ioctl(FD_FORM)"); 87 } 88 89 static int 90 verify_track(int fd, int track, int tracksize) 91 { 92 static char *buf = 0; 93 static int bufsz = 0; 94 int fdopts = -1, ofdopts, rv = 0; 95 96 if (ioctl(fd, FD_GOPTS, &fdopts) < 0) 97 warn("warning: ioctl(FD_GOPTS)"); 98 else { 99 ofdopts = fdopts; 100 fdopts |= FDOPT_NORETRY; 101 (void)ioctl(fd, FD_SOPTS, &fdopts); 102 } 103 104 if (bufsz < tracksize) { 105 if (buf) 106 free (buf); 107 bufsz = tracksize; 108 buf = 0; 109 } 110 if (! buf) 111 buf = malloc (bufsz); 112 if (! buf) 113 errx(2, "out of memory"); 114 if (lseek (fd, (long) track*tracksize, 0) < 0) 115 rv = -1; 116 /* try twice reading it, without using the normal retrier */ 117 else if (read (fd, buf, tracksize) != tracksize 118 && read (fd, buf, tracksize) != tracksize) 119 rv = -1; 120 if(fdopts != -1) 121 (void)ioctl(fd, FD_SOPTS, &ofdopts); 122 return (rv); 123 } 124 125 static const char * 126 makename(const char *arg, const char *suffix) 127 { 128 static char namebuff[20]; /* big enough for "/dev/fd0a"... */ 129 130 memset(namebuff, 0, 20); 131 if(*arg == '\0') /* ??? */ 132 return arg; 133 if(*arg == '/') /* do not convert absolute pathnames */ 134 return arg; 135 strcpy(namebuff, _PATH_DEV); 136 strncat(namebuff, arg, 3); 137 strcat(namebuff, suffix); 138 return namebuff; 139 } 140 141 static void 142 usage (void) 143 { 144 fprintf(stderr, "%s\n%s\n", 145 "usage: fdformat [-y] [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]", 146 " [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname"); 147 exit(2); 148 } 149 150 static int 151 yes (void) 152 { 153 char reply [256], *p; 154 155 reply[sizeof(reply)-1] = 0; 156 for (;;) { 157 fflush(stdout); 158 if (! fgets (reply, sizeof(reply)-1, stdin)) 159 return (0); 160 for (p=reply; *p==' ' || *p=='\t'; ++p) 161 continue; 162 if (*p=='y' || *p=='Y') 163 return (1); 164 if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') 165 return (0); 166 printf("Answer `yes' or `no': "); 167 } 168 } 169 170 /* 171 * Some definitions imported from /sys/isa/ic/nec765.h for convenience. 172 */ 173 174 /* Status register ST0 */ 175 #define NE7_ST0_IC 0xc0 /* interrupt completion code */ 176 #define NE7_ST0_IC_AT 0x40 /* abnormal termination, check error stat */ 177 #define NE7_ST0_IC_RC 0xc0 /* terminated due to ready changed, n/a */ 178 179 /* Status register ST1 */ 180 #define NE7_ST1_EN 0x80 /* end of cylinder, access past last record */ 181 #define NE7_ST1_DE 0x20 /* data error, CRC fail in ID or data */ 182 #define NE7_ST1_ND 0x04 /* no data, sector not found or CRC in ID f. */ 183 #define NE7_ST1_MA 0x01 /* missing address mark (in ID or data field)*/ 184 185 /* Status register ST2 */ 186 #define NE7_ST2_DD 0x20 /* data error in data field, CRC fail */ 187 #define NE7_ST2_WC 0x10 /* wrong cylinder, ID field mismatches cmd */ 188 #define NE7_ST2_MD 0x01 /* missing address mark in data field */ 189 190 /* 191 * Decode the FDC status pointed to by `fdcsp', and print a textual 192 * translation to stderr. 193 */ 194 static void 195 printstatus(struct fdc_status *fdcsp) 196 { 197 char msgbuf[100]; 198 199 if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) { 200 sprintf(msgbuf, "unexcpted interrupt code %#x", 201 fdcsp->status[0] & NE7_ST0_IC_RC); 202 } else { 203 strcpy(msgbuf, "unexpected error code in ST1/ST2"); 204 205 if (fdcsp->status[1] & NE7_ST1_EN) 206 strcpy(msgbuf, "end of cylinder (wrong format)"); 207 else if (fdcsp->status[1] & NE7_ST1_DE) { 208 if (fdcsp->status[2] & NE7_ST2_DD) 209 strcpy(msgbuf, "CRC error in data field"); 210 else 211 strcpy(msgbuf, "CRC error in ID field"); 212 } else if (fdcsp->status[1] & NE7_ST1_MA) { 213 if (fdcsp->status[2] & NE7_ST2_MD) 214 strcpy(msgbuf, "no address mark in data field"); 215 else 216 strcpy(msgbuf, "no address mark in ID field"); 217 } else if (fdcsp->status[2] & NE7_ST2_WC) 218 strcpy(msgbuf, "wrong cylinder (format mismatch)"); 219 else if (fdcsp->status[1] & NE7_ST1_ND) 220 strcpy(msgbuf, "no data (sector not found)"); 221 } 222 fputs(msgbuf, stderr); 223 } 224 225 int 226 main(int argc, char **argv) 227 { 228 int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1; 229 int rate = -1, gaplen = -1, secsize = -1, steps = -1; 230 int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0, confirm = 0; 231 int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs; 232 int fdopts; 233 const char *devname, *suffix; 234 struct fd_type fdt; 235 #define MAXPRINTERRS 10 236 struct fdc_status fdcs[MAXPRINTERRS]; 237 238 while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qyvn")) != -1) 239 switch(c) { 240 case 'f': /* format in kilobytes */ 241 format = atoi(optarg); 242 break; 243 244 case 'c': /* # of cyls */ 245 cyls = atoi(optarg); 246 break; 247 248 case 's': /* # of secs per track */ 249 secs = atoi(optarg); 250 break; 251 252 case 'h': /* # of heads */ 253 heads = atoi(optarg); 254 break; 255 256 case 'r': /* transfer rate, kilobyte/sec */ 257 rate = atoi(optarg); 258 break; 259 260 case 'g': /* length of GAP3 to format with */ 261 gaplen = atoi(optarg); 262 break; 263 264 case 'S': /* sector size shift factor (1 << S)*128 */ 265 secsize = atoi(optarg); 266 break; 267 268 case 'F': /* fill byte, C-like notation allowed */ 269 fill = (int)strtol(optarg, (char **)0, 0); 270 break; 271 272 case 't': /* steps per track */ 273 steps = atoi(optarg); 274 break; 275 276 case 'i': /* interleave factor */ 277 intleave = atoi(optarg); 278 break; 279 280 case 'q': 281 quiet = 1; 282 break; 283 284 case 'y': 285 confirm = 1; 286 break; 287 288 case 'n': 289 verify = 0; 290 break; 291 292 case 'v': 293 verify = 1; 294 verify_only = 1; 295 break; 296 297 case '?': default: 298 usage(); 299 } 300 301 if(optind != argc - 1) 302 usage(); 303 304 switch(format) { 305 default: 306 errx(2, "bad floppy size: %dK", format); 307 case -1: suffix = ""; break; 308 case 360: suffix = ".360"; break; 309 case 640: suffix = ".640"; break; 310 case 720: suffix = ".720"; break; 311 case 800: suffix = ".800"; break; 312 case 820: suffix = ".820"; break; 313 case 1200: suffix = ".1200"; break; 314 case 1232: suffix = ".1232"; break; 315 case 1440: suffix = ".1440"; break; 316 case 1480: suffix = ".1480"; break; 317 case 1720: suffix = ".1720"; break; 318 } 319 320 devname = makename(argv[optind], suffix); 321 322 if((fd = open(devname, O_RDWR)) < 0) 323 err(1, "%s", devname); 324 325 if(ioctl(fd, FD_GTYPE, &fdt) < 0) 326 errx(1, "not a floppy disk: %s", devname); 327 fdopts = FDOPT_NOERRLOG; 328 if (ioctl(fd, FD_SOPTS, &fdopts) == -1) 329 err(1, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)"); 330 331 switch(rate) { 332 case -1: break; 333 case 250: fdt.trans = FDC_250KBPS; break; 334 case 300: fdt.trans = FDC_300KBPS; break; 335 case 500: fdt.trans = FDC_500KBPS; break; 336 default: 337 errx(2, "invalid transfer rate: %d", rate); 338 } 339 340 if (cyls >= 0) fdt.tracks = cyls; 341 if (secs >= 0) fdt.sectrac = secs; 342 if (fdt.sectrac > FD_MAX_NSEC) 343 errx(2, "too many sectors per track, max value is %d", FD_MAX_NSEC); 344 if (heads >= 0) fdt.heads = heads; 345 if (gaplen >= 0) fdt.f_gap = gaplen; 346 if (secsize >= 0) fdt.secsize = secsize; 347 if (steps >= 0) fdt.steptrac = steps; 348 if (intleave >= 0) fdt.f_inter = intleave; 349 350 bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128; 351 352 /* XXX 20/40 = 0.5 */ 353 tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 354 355 if (verify_only) { 356 if(!quiet) 357 printf("Verify %dK floppy `%s'.\n", 358 fdt.tracks * fdt.heads * bytes_per_track / 1024, 359 devname); 360 } 361 else if(!quiet && !confirm) { 362 printf("Format %dK floppy `%s'? (y/n): ", 363 fdt.tracks * fdt.heads * bytes_per_track / 1024, 364 devname); 365 if(! yes ()) { 366 printf("Not confirmed.\n"); 367 return 3; 368 } 369 } 370 371 /* 372 * Formatting. 373 */ 374 if(!quiet) { 375 int i; 376 377 printf("Processing "); 378 for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 379 putchar('-'); 380 printf("\rProcessing "); 381 fflush(stdout); 382 } 383 384 error = errs = 0; 385 386 for (track = 0; track < fdt.tracks * fdt.heads; track++) { 387 if (!verify_only) { 388 format_track(fd, track / fdt.heads, fdt.sectrac, 389 track % fdt.heads, fdt.trans, fdt.f_gap, 390 fdt.secsize, fill, fdt.f_inter); 391 if(!quiet && !((track + 1) % tracks_per_dot)) { 392 putchar('F'); 393 fflush(stdout); 394 } 395 } 396 if (verify) { 397 if (verify_track(fd, track, bytes_per_track) < 0) { 398 error = 1; 399 if (errs < MAXPRINTERRS && errno == EIO) { 400 if (ioctl(fd, FD_GSTAT, fdcs + errs) == 401 -1) 402 errx(1, 403 "floppy IO error, but no FDC status"); 404 errs++; 405 } 406 } 407 if(!quiet && !((track + 1) % tracks_per_dot)) { 408 if (!verify_only) 409 putchar('\b'); 410 if (error) { 411 putchar('E'); 412 error = 0; 413 } 414 else 415 putchar('V'); 416 fflush(stdout); 417 } 418 } 419 } 420 if(!quiet) 421 printf(" done.\n"); 422 423 if (!quiet && errs) { 424 fflush(stdout); 425 fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 426 for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 427 fprintf(stderr, " %2d %2d %2d ", 428 fdcs[i].status[3], fdcs[i].status[4], 429 fdcs[i].status[5]); 430 printstatus(fdcs + i); 431 putc('\n', stderr); 432 } 433 if (errs >= MAXPRINTERRS) 434 fprintf(stderr, "(Further errors not printed.)\n"); 435 } 436 437 return errs != 0; 438 } 439 /* 440 * Local Variables: 441 * c-indent-level: 8 442 * c-continued-statement-offset: 8 443 * c-continued-brace-offset: 0 444 * c-brace-offset: -8 445 * c-brace-imaginary-offset: 0 446 * c-argdecl-indent: 8 447 * c-label-offset: -8 448 * c++-hanging-braces: 1 449 * c++-access-specifier-offset: -8 450 * c++-empty-arglist-indent: 8 451 * c++-friend-offset: 0 452 * End: 453 */ 454