1 /* 2 * Copyright (c) 2001 Joerg Wunsch 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <dev/ic/nec765.h> 30 31 #include <sys/fdcio.h> 32 33 #include <err.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sysexits.h> 38 39 #include "fdutil.h" 40 41 /* 42 * Decode the FDC status pointed to by `fdcsp', and print a textual 43 * translation to stderr. If `terse' is false, the numerical FDC 44 * register status is printed, too. 45 */ 46 void 47 printstatus(struct fdc_status *fdcsp, int terse) 48 { 49 char msgbuf[100]; 50 51 if (!terse) 52 fprintf(stderr, 53 "\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n", 54 fdcsp->status[0] & 0xff, 55 fdcsp->status[1] & 0xff, 56 fdcsp->status[2] & 0xff, 57 fdcsp->status[3] & 0xff, 58 fdcsp->status[4] & 0xff, 59 fdcsp->status[5] & 0xff, 60 fdcsp->status[6] & 0xff); 61 62 if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) { 63 sprintf(msgbuf, "unexcpted interrupt code %#x", 64 fdcsp->status[0] & NE7_ST0_IC_RC); 65 } else { 66 strcpy(msgbuf, "unexpected error code in ST1/ST2"); 67 68 if (fdcsp->status[1] & NE7_ST1_EN) 69 strcpy(msgbuf, "end of cylinder (wrong format)"); 70 else if (fdcsp->status[1] & NE7_ST1_DE) { 71 if (fdcsp->status[2] & NE7_ST2_DD) 72 strcpy(msgbuf, "CRC error in data field"); 73 else 74 strcpy(msgbuf, "CRC error in ID field"); 75 } else if (fdcsp->status[1] & NE7_ST1_MA) { 76 if (fdcsp->status[2] & NE7_ST2_MD) 77 strcpy(msgbuf, "no address mark in data field"); 78 else 79 strcpy(msgbuf, "no address mark in ID field"); 80 } else if (fdcsp->status[2] & NE7_ST2_WC) 81 strcpy(msgbuf, "wrong cylinder (format mismatch)"); 82 else if (fdcsp->status[1] & NE7_ST1_ND) 83 strcpy(msgbuf, "no data (sector not found)"); 84 } 85 fputs(msgbuf, stderr); 86 } 87 88 static struct fd_type fd_types_288m[] = 89 { 90 #if 0 91 { 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /*2.88M*/ 92 #endif 93 { 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */ 94 { 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */ 95 { 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */ 96 { 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */ 97 { 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */ 98 { 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */ 99 { 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */ 100 }; 101 102 static struct fd_type fd_types_144m[] = 103 { 104 { 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */ 105 { 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */ 106 { 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */ 107 { 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */ 108 { 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */ 109 { 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */ 110 { 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */ 111 }; 112 113 static struct fd_type fd_types_12m[] = 114 { 115 { 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */ 116 { 8,3,0xFF,0x35,77,1232,FDC_500KBPS,2,0x74,1,0,FL_MFM }, /* 1.23M */ 117 { 18,2,0xFF,0x02,82,2952,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.48M */ 118 { 18,2,0xFF,0x02,80,2880,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.44M */ 119 { 10,2,0xFF,0x10,82,1640,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */ 120 { 10,2,0xFF,0x10,80,1600,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */ 121 { 9,2,0xFF,0x20,80,1440,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 720K */ 122 { 9,2,0xFF,0x23,40, 720,FDC_300KBPS,2,0x50,1,0,FL_MFM|FL_2STEP }, /* 360K */ 123 { 8,2,0xFF,0x2A,80,1280,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 640K */ 124 }; 125 126 static struct fd_type fd_types_720k[] = 127 { 128 { 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */ 129 }; 130 131 static struct fd_type fd_types_360k[] = 132 { 133 { 9,2,0xFF,0x2A,40, 720,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 360K */ 134 }; 135 136 /* 137 * Parse a format string, and fill in the parameter pointed to by `out'. 138 * 139 * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...] 140 * 141 * sectrac = sectors per track 142 * secsize = sector size in bytes 143 * datalen = length of sector if secsize == 128 144 * gap = gap length when reading 145 * ncyls = number of cylinders 146 * speed = transfer speed 250/300/500/1000 KB/s 147 * heads = number of heads 148 * f_gap = gap length when formatting 149 * f_inter = sector interleave when formatting 150 * offs2 = offset of sectors on side 2 151 * flags = +/-mfm | +/-2step | +/-perpend 152 * mfm - use MFM recording 153 * 2step - use 2 steps between cylinders 154 * perpend - user perpendicular (vertical) recording 155 * 156 * Any omitted value will be passed on from parameter `in'. 157 */ 158 void 159 parse_fmt(const char *s, enum fd_drivetype type, 160 struct fd_type in, struct fd_type *out) 161 { 162 int i, j; 163 const char *cp; 164 char *s1; 165 166 *out = in; 167 168 for (i = 0;; i++) { 169 if (s == 0) 170 break; 171 172 if ((cp = strchr(s, ',')) == 0) { 173 s1 = strdup(s); 174 if (s1 == NULL) 175 abort(); 176 s = 0; 177 } else { 178 s1 = malloc(cp - s + 1); 179 if (s1 == NULL) 180 abort(); 181 memcpy(s1, s, cp - s); 182 s1[cp - s] = 0; 183 184 s = cp + 1; 185 } 186 if (strlen(s1) == 0) { 187 free(s1); 188 continue; 189 } 190 191 switch (i) { 192 case 0: /* sectrac */ 193 if (getnum(s1, &out->sectrac)) 194 errx(EX_USAGE, 195 "bad numeric value for sectrac: %s", s1); 196 break; 197 198 case 1: /* secsize */ 199 if (getnum(s1, &j)) 200 errx(EX_USAGE, 201 "bad numeric value for secsize: %s", s1); 202 if (j == 128) out->secsize = 0; 203 else if (j == 256) out->secsize = 1; 204 else if (j == 512) out->secsize = 2; 205 else if (j == 1024) out->secsize = 3; 206 else 207 errx(EX_USAGE, "bad sector size %d", j); 208 break; 209 210 case 2: /* datalen */ 211 if (getnum(s1, &j)) 212 errx(EX_USAGE, 213 "bad numeric value for datalen: %s", s1); 214 if (j >= 256) 215 errx(EX_USAGE, "bad datalen %d", j); 216 out->datalen = j; 217 break; 218 219 case 3: /* gap */ 220 if (getnum(s1, &out->gap)) 221 errx(EX_USAGE, 222 "bad numeric value for gap: %s", s1); 223 break; 224 225 case 4: /* ncyls */ 226 if (getnum(s1, &j)) 227 errx(EX_USAGE, 228 "bad numeric value for ncyls: %s", s1); 229 if (j > 85) 230 errx(EX_USAGE, "bad # of cylinders %d", j); 231 out->tracks = j; 232 break; 233 234 case 5: /* speed */ 235 if (getnum(s1, &j)) 236 errx(EX_USAGE, 237 "bad numeric value for speed: %s", s1); 238 switch (type) { 239 default: 240 abort(); /* paranoia */ 241 242 case FDT_360K: 243 case FDT_720K: 244 if (j == 250) 245 out->trans = FDC_250KBPS; 246 else { 247 badspeed: 248 errx(EX_USAGE, "bad speed %d", j); 249 } 250 break; 251 252 case FDT_12M: 253 if (j == 300) 254 out->trans = FDC_300KBPS; 255 else if (j == 500) 256 out->trans = FDC_500KBPS; 257 else 258 goto badspeed; 259 break; 260 261 case FDT_288M: 262 if (j == 1000) 263 out->trans = FDC_1MBPS; 264 /* FALLTHROUGH */ 265 case FDT_144M: 266 if (j == 250) 267 out->trans = FDC_250KBPS; 268 else if (j == 500) 269 out->trans = FDC_500KBPS; 270 else 271 goto badspeed; 272 break; 273 } 274 break; 275 276 case 6: /* heads */ 277 if (getnum(s1, &j)) 278 errx(EX_USAGE, 279 "bad numeric value for heads: %s", s1); 280 if (j == 1 || j == 2) 281 out->heads = j; 282 else 283 errx(EX_USAGE, "bad # of heads %d", j); 284 break; 285 286 case 7: /* f_gap */ 287 if (getnum(s1, &out->f_gap)) 288 errx(EX_USAGE, 289 "bad numeric value for f_gap: %s", s1); 290 break; 291 292 case 8: /* f_inter */ 293 if (getnum(s1, &out->f_inter)) 294 errx(EX_USAGE, 295 "bad numeric value for f_inter: %s", s1); 296 break; 297 298 case 9: /* offs2 */ 299 if (getnum(s1, &out->offset_side2)) 300 errx(EX_USAGE, 301 "bad numeric value for offs2: %s", s1); 302 break; 303 304 default: 305 if (strcmp(s1, "+mfm") == 0) 306 out->flags |= FL_MFM; 307 else if (strcmp(s1, "-mfm") == 0) 308 out->flags &= ~FL_MFM; 309 else if (strcmp(s1, "+2step") == 0) 310 out->flags |= FL_2STEP; 311 else if (strcmp(s1, "-2step") == 0) 312 out->flags &= ~FL_2STEP; 313 else if (strcmp(s1, "+perpnd") == 0) 314 out->flags |= FL_PERPND; 315 else if (strcmp(s1, "-perpnd") == 0) 316 out->flags &= ~FL_PERPND; 317 else 318 errx(EX_USAGE, "bad flag: %s", s1); 319 break; 320 } 321 free(s1); 322 } 323 324 out->size = out->tracks * out->heads * out->sectrac * 325 (128 << out->secsize) / 512; 326 } 327 328 /* 329 * Print a textual translation of the drive (density) type described 330 * by `in' to stdout. The string uses the same form that is parseable 331 * by parse_fmt(). 332 */ 333 void 334 print_fmt(struct fd_type in) 335 { 336 int secsize, speed; 337 338 secsize = 128 << in.secsize; 339 switch (in.trans) { 340 case FDC_250KBPS: speed = 250; break; 341 case FDC_300KBPS: speed = 300; break; 342 case FDC_500KBPS: speed = 500; break; 343 case FDC_1MBPS: speed = 1000; break; 344 default: speed = 1; break; 345 } 346 347 printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d", 348 in.sectrac, secsize, in.datalen, in.gap, in.tracks, 349 speed, in.heads, in.f_gap, in.f_inter, in.offset_side2); 350 if (in.flags & FL_MFM) 351 printf(",+mfm"); 352 if (in.flags & FL_2STEP) 353 printf(",+2step"); 354 if (in.flags & FL_PERPND) 355 printf(",+perpnd"); 356 putc('\n', stdout); 357 } 358 359 /* 360 * Based on `size' (in kilobytes), walk through the table of known 361 * densities for drive type `type' and see if we can find one. If 362 * found, return it (as a pointer to static storage), otherwise return 363 * NULL. 364 */ 365 struct fd_type * 366 get_fmt(int size, enum fd_drivetype type) 367 { 368 int i, n; 369 struct fd_type *fdtp; 370 371 switch (type) { 372 default: 373 return (0); 374 375 case FDT_360K: 376 fdtp = fd_types_360k; 377 n = sizeof fd_types_360k / sizeof(struct fd_type); 378 break; 379 380 case FDT_720K: 381 fdtp = fd_types_720k; 382 n = sizeof fd_types_720k / sizeof(struct fd_type); 383 break; 384 385 case FDT_12M: 386 fdtp = fd_types_12m; 387 n = sizeof fd_types_12m / sizeof(struct fd_type); 388 break; 389 390 case FDT_144M: 391 fdtp = fd_types_144m; 392 n = sizeof fd_types_144m / sizeof(struct fd_type); 393 break; 394 395 case FDT_288M: 396 fdtp = fd_types_288m; 397 n = sizeof fd_types_288m / sizeof(struct fd_type); 398 break; 399 } 400 401 for (i = 0; i < n; i++, fdtp++) 402 if (fdtp->size / 2 == size) 403 return (fdtp); 404 405 return (0); 406 } 407 408 /* 409 * Parse a number from `s'. If the string cannot be converted into a 410 * number completely, return -1, otherwise 0. The result is returned 411 * in `*res'. 412 */ 413 int 414 getnum(const char *s, int *res) 415 { 416 unsigned long ul; 417 char *cp; 418 419 ul = strtoul(s, &cp, 0); 420 if (*cp != '\0') 421 return (-1); 422 423 *res = (int)ul; 424 return (0); 425 } 426 427 /* 428 * Return a short name and a verbose description for the drive 429 * described by `t'. 430 */ 431 void 432 getname(enum fd_drivetype t, const char **name, const char **descr) 433 { 434 435 switch (t) { 436 default: 437 *name = "unknown"; 438 *descr = "unknown drive type"; 439 break; 440 441 case FDT_360K: 442 *name = "360K"; 443 *descr = "5.25\" double-density"; 444 break; 445 446 case FDT_12M: 447 *name = "1.2M"; 448 *descr = "5.25\" high-density"; 449 break; 450 451 case FDT_720K: 452 *name = "720K"; 453 *descr = "3.5\" double-density"; 454 break; 455 456 case FDT_144M: 457 *name = "1.44M"; 458 *descr = "3.5\" high-density"; 459 break; 460 461 case FDT_288M: 462 *name = "2.88M"; 463 *descr = "3.5\" extra-density"; 464 break; 465 } 466 } 467