1169689Skan/* 2169689Skan * Copyright (c) 2001 Joerg Wunsch 3169689Skan * 4169689Skan * All rights reserved. 5169689Skan * 6169689Skan * Redistribution and use in source and binary forms, with or without 7169689Skan * modification, are permitted provided that the following conditions 8169689Skan * are met: 9169689Skan * 1. Redistributions of source code must retain the above copyright 10169689Skan * notice, this list of conditions and the following disclaimer. 11169689Skan * 2. Redistributions in binary form must reproduce the above copyright 12169689Skan * notice, this list of conditions and the following disclaimer in the 13169689Skan * documentation and/or other materials provided with the distribution. 14169689Skan * 15169689Skan * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR 16169689Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17169689Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18169689Skan * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, 19169689Skan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20169689Skan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21169689Skan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22169689Skan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23169689Skan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24169689Skan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25169689Skan * 26169689Skan * $FreeBSD: releng/11.0/usr.sbin/fdread/fdutil.c 297962 2016-04-14 12:46:46Z araujo $ 27169689Skan */ 28169689Skan 29169689Skan#include <dev/ic/nec765.h> 30169689Skan 31169689Skan#include <sys/fdcio.h> 32169689Skan 33169689Skan#include <err.h> 34169689Skan#include <stdio.h> 35169689Skan#include <stdlib.h> 36169689Skan#include <string.h> 37169689Skan#include <sysexits.h> 38169689Skan 39169689Skan#include "fdutil.h" 40169689Skan 41169689Skan/* 42169689Skan * Decode the FDC status pointed to by `fdcsp', and print a textual 43169689Skan * translation to stderr. If `terse' is false, the numerical FDC 44169689Skan * register status is printed, too. 45169689Skan */ 46169689Skanvoid 47169689Skanprintstatus(struct fdc_status *fdcsp, int terse) 48169689Skan{ 49169689Skan char msgbuf[100]; 50169689Skan 51169689Skan if (!terse) 52169689Skan fprintf(stderr, 53169689Skan "\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n", 54169689Skan fdcsp->status[0] & 0xff, 55169689Skan fdcsp->status[1] & 0xff, 56169689Skan fdcsp->status[2] & 0xff, 57169689Skan fdcsp->status[3] & 0xff, 58169689Skan fdcsp->status[4] & 0xff, 59169689Skan fdcsp->status[5] & 0xff, 60169689Skan fdcsp->status[6] & 0xff); 61169689Skan 62169689Skan if ((fdcsp->status[0] & NE7_ST0_IC_RC) == 0) { 63169689Skan sprintf(msgbuf, "timeout"); 64169689Skan } else if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) { 65169689Skan sprintf(msgbuf, "unexcpted interrupt code %#x", 66169689Skan fdcsp->status[0] & NE7_ST0_IC_RC); 67169689Skan } else { 68169689Skan strcpy(msgbuf, "unexpected error code in ST1/ST2"); 69169689Skan 70169689Skan if (fdcsp->status[1] & NE7_ST1_EN) 71169689Skan strcpy(msgbuf, "end of cylinder (wrong format)"); 72169689Skan else if (fdcsp->status[1] & NE7_ST1_DE) { 73169689Skan if (fdcsp->status[2] & NE7_ST2_DD) 74169689Skan strcpy(msgbuf, "CRC error in data field"); 75169689Skan else 76169689Skan strcpy(msgbuf, "CRC error in ID field"); 77169689Skan } else if (fdcsp->status[1] & NE7_ST1_MA) { 78169689Skan if (fdcsp->status[2] & NE7_ST2_MD) 79169689Skan strcpy(msgbuf, "no address mark in data field"); 80169689Skan else 81169689Skan strcpy(msgbuf, "no address mark in ID field"); 82169689Skan } else if (fdcsp->status[2] & NE7_ST2_WC) 83169689Skan strcpy(msgbuf, "wrong cylinder (format mismatch)"); 84169689Skan else if (fdcsp->status[1] & NE7_ST1_ND) 85169689Skan strcpy(msgbuf, "no data (sector not found)"); 86169689Skan } 87169689Skan fputs(msgbuf, stderr); 88169689Skan} 89169689Skan 90169689Skanstatic struct fd_type fd_types_auto[1] = 91169689Skan { { 0,0,0,0,0,0,0,0,0,0,0,FL_AUTO } }; 92169689Skan 93169689Skan 94169689Skanstatic struct fd_type fd_types_288m[] = { 95169689Skan#ifndef PC98 96169689Skan#if 0 97169689Skan { FDF_3_2880 }, 98169689Skan#endif 99169689Skan { FDF_3_1722 }, 100169689Skan { FDF_3_1476 }, 101169689Skan { FDF_3_1440 }, 102169689Skan { FDF_3_1200 }, 103169689Skan { FDF_3_820 }, 104169689Skan { FDF_3_800 }, 105169689Skan { FDF_3_720 }, 106169689Skan#endif /* !PC98 */ 107169689Skan { 0,0,0,0,0,0,0,0,0,0,0,0 } 108169689Skan}; 109169689Skan 110169689Skanstatic struct fd_type fd_types_144m[] = { 111169689Skan#ifdef PC98 112169689Skan { FDF_3_1440 }, 113169689Skan { FDF_3_1200 }, 114169689Skan { FDF_3_720 }, 115169689Skan { FDF_3_360 }, 116169689Skan { FDF_3_640 }, 117169689Skan { FDF_3_1230 }, 118169689Skan { 0,0,0,0,0,0,0,0,0,0,0,0 } 119169689Skan#else 120169689Skan { FDF_3_1722 }, 121169689Skan { FDF_3_1476 }, 122169689Skan { FDF_3_1440 }, 123169689Skan { FDF_3_1200 }, 124169689Skan { FDF_3_820 }, 125169689Skan { FDF_3_800 }, 126169689Skan { FDF_3_720 }, 127169689Skan { 0,0,0,0,0,0,0,0,0,0,0,0 } 128169689Skan#endif 129169689Skan}; 130169689Skan 131169689Skanstatic struct fd_type fd_types_12m[] = { 132169689Skan#ifdef PC98 133169689Skan { FDF_5_1200 }, 134169689Skan { FDF_5_720 }, 135169689Skan { FDF_5_360 }, 136169689Skan { FDF_5_640 }, 137169689Skan { FDF_5_1230 }, 138169689Skan { 0,0,0,0,0,0,0,0,0,0,0,0 } 139169689Skan#else 140169689Skan { FDF_5_1200 }, 141169689Skan { FDF_5_1230 }, 142169689Skan { FDF_5_1480 }, 143169689Skan { FDF_5_1440 }, 144169689Skan { FDF_5_820 }, 145169689Skan { FDF_5_800 }, 146169689Skan { FDF_5_720 }, 147169689Skan { FDF_5_360 | FL_2STEP }, 148169689Skan { FDF_5_640 }, 149169689Skan { 0,0,0,0,0,0,0,0,0,0,0,0 } 150169689Skan#endif 151169689Skan}; 152169689Skan 153169689Skanstatic struct fd_type fd_types_720k[] = 154169689Skan{ 155169689Skan#ifndef PC98 156169689Skan { FDF_3_720 }, 157169689Skan#endif 158169689Skan { 0,0,0,0,0,0,0,0,0,0,0,0 } 159169689Skan}; 160169689Skan 161169689Skanstatic struct fd_type fd_types_360k[] = 162169689Skan{ 163169689Skan#ifndef PC98 164169689Skan { FDF_5_360 }, 165169689Skan#endif 166169689Skan { 0,0,0,0,0,0,0,0,0,0,0,0 } 167169689Skan}; 168169689Skan 169169689Skan 170169689Skan/* 171169689Skan * Parse a format string, and fill in the parameter pointed to by `out'. 172169689Skan * 173169689Skan * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...] 174169689Skan * 175169689Skan * sectrac = sectors per track 176169689Skan * secsize = sector size in bytes 177169689Skan * datalen = length of sector if secsize == 128 178169689Skan * gap = gap length when reading 179169689Skan * ncyls = number of cylinders 180169689Skan * speed = transfer speed 250/300/500/1000 KB/s 181169689Skan * heads = number of heads 182169689Skan * f_gap = gap length when formatting 183169689Skan * f_inter = sector interleave when formatting 184169689Skan * offs2 = offset of sectors on side 2 185169689Skan * flags = +/-mfm | +/-2step | +/-perpend 186169689Skan * mfm - use MFM recording 187169689Skan * 2step - use 2 steps between cylinders 188169689Skan * perpend - user perpendicular (vertical) recording 189169689Skan * 190169689Skan * Any omitted value will be passed on from parameter `in'. 191169689Skan */ 192169689Skanvoid 193169689Skanparse_fmt(const char *s, enum fd_drivetype type, 194169689Skan struct fd_type in, struct fd_type *out) 195169689Skan{ 196169689Skan int i, j; 197169689Skan const char *cp; 198169689Skan char *s1; 199169689Skan 200169689Skan *out = in; 201169689Skan 202169689Skan for (i = 0;; i++) { 203169689Skan if (s == NULL) 204169689Skan break; 205169689Skan 206169689Skan if ((cp = strchr(s, ',')) == NULL) { 207169689Skan s1 = strdup(s); 208169689Skan if (s1 == NULL) 209169689Skan abort(); 210169689Skan s = 0; 211169689Skan } else { 212169689Skan s1 = malloc(cp - s + 1); 213169689Skan if (s1 == NULL) 214169689Skan abort(); 215169689Skan memcpy(s1, s, cp - s); 216169689Skan s1[cp - s] = 0; 217169689Skan 218169689Skan s = cp + 1; 219169689Skan } 220169689Skan if (strlen(s1) == 0) { 221169689Skan free(s1); 222169689Skan continue; 223169689Skan } 224169689Skan 225169689Skan switch (i) { 226169689Skan case 0: /* sectrac */ 227169689Skan if (getnum(s1, &out->sectrac)) 228169689Skan errx(EX_USAGE, 229169689Skan "bad numeric value for sectrac: %s", s1); 230169689Skan break; 231169689Skan 232169689Skan case 1: /* secsize */ 233169689Skan if (getnum(s1, &j)) 234169689Skan errx(EX_USAGE, 235169689Skan "bad numeric value for secsize: %s", s1); 236169689Skan if (j == 128) out->secsize = 0; 237169689Skan else if (j == 256) out->secsize = 1; 238169689Skan else if (j == 512) out->secsize = 2; 239169689Skan else if (j == 1024) out->secsize = 3; 240169689Skan else 241169689Skan errx(EX_USAGE, "bad sector size %d", j); 242169689Skan break; 243169689Skan 244169689Skan case 2: /* datalen */ 245169689Skan if (getnum(s1, &j)) 246169689Skan errx(EX_USAGE, 247169689Skan "bad numeric value for datalen: %s", s1); 248169689Skan if (j >= 256) 249169689Skan errx(EX_USAGE, "bad datalen %d", j); 250169689Skan out->datalen = j; 251169689Skan break; 252169689Skan 253169689Skan case 3: /* gap */ 254169689Skan if (getnum(s1, &out->gap)) 255169689Skan errx(EX_USAGE, 256169689Skan "bad numeric value for gap: %s", s1); 257169689Skan break; 258169689Skan 259169689Skan case 4: /* ncyls */ 260169689Skan if (getnum(s1, &j)) 261169689Skan errx(EX_USAGE, 262169689Skan "bad numeric value for ncyls: %s", s1); 263169689Skan if (j > 85) 264169689Skan errx(EX_USAGE, "bad # of cylinders %d", j); 265169689Skan out->tracks = j; 266169689Skan break; 267169689Skan 268169689Skan case 5: /* speed */ 269169689Skan if (getnum(s1, &j)) 270169689Skan errx(EX_USAGE, 271169689Skan "bad numeric value for speed: %s", s1); 272169689Skan switch (type) { 273169689Skan default: 274169689Skan abort(); /* paranoia */ 275169689Skan 276169689Skan case FDT_360K: 277169689Skan case FDT_720K: 278169689Skan if (j == 250) 279169689Skan out->trans = FDC_250KBPS; 280169689Skan else 281169689Skan errx(EX_USAGE, "bad speed %d", j); 282169689Skan break; 283169689Skan 284169689Skan case FDT_12M: 285169689Skan if (j == 300) 286169689Skan out->trans = FDC_300KBPS; 287169689Skan else if (j == 250) 288169689Skan out->trans = FDC_250KBPS; 289169689Skan else if (j == 500) 290169689Skan out->trans = FDC_500KBPS; 291169689Skan else 292169689Skan errx(EX_USAGE, "bad speed %d", j); 293169689Skan break; 294169689Skan 295169689Skan case FDT_288M: 296169689Skan if (j == 1000) 297169689Skan out->trans = FDC_1MBPS; 298169689Skan /* FALLTHROUGH */ 299169689Skan case FDT_144M: 300169689Skan if (j == 250) 301169689Skan out->trans = FDC_250KBPS; 302169689Skan else if (j == 500) 303169689Skan out->trans = FDC_500KBPS; 304169689Skan else 305169689Skan errx(EX_USAGE, "bad speed %d", j); 306169689Skan break; 307169689Skan } 308169689Skan break; 309169689Skan 310169689Skan case 6: /* heads */ 311169689Skan if (getnum(s1, &j)) 312169689Skan errx(EX_USAGE, 313169689Skan "bad numeric value for heads: %s", s1); 314169689Skan if (j == 1 || j == 2) 315169689Skan out->heads = j; 316169689Skan else 317169689Skan errx(EX_USAGE, "bad # of heads %d", j); 318169689Skan break; 319169689Skan 320169689Skan case 7: /* f_gap */ 321169689Skan if (getnum(s1, &out->f_gap)) 322169689Skan errx(EX_USAGE, 323169689Skan "bad numeric value for f_gap: %s", s1); 324169689Skan break; 325169689Skan 326169689Skan case 8: /* f_inter */ 327169689Skan if (getnum(s1, &out->f_inter)) 328169689Skan errx(EX_USAGE, 329169689Skan "bad numeric value for f_inter: %s", s1); 330169689Skan break; 331169689Skan 332169689Skan case 9: /* offs2 */ 333169689Skan if (getnum(s1, &out->offset_side2)) 334169689Skan errx(EX_USAGE, 335169689Skan "bad numeric value for offs2: %s", s1); 336169689Skan break; 337169689Skan 338169689Skan default: 339169689Skan if (strcmp(s1, "+mfm") == 0) 340169689Skan out->flags |= FL_MFM; 341169689Skan else if (strcmp(s1, "-mfm") == 0) 342169689Skan out->flags &= ~FL_MFM; 343169689Skan else if (strcmp(s1, "+auto") == 0) 344169689Skan out->flags |= FL_AUTO; 345169689Skan else if (strcmp(s1, "-auto") == 0) 346169689Skan out->flags &= ~FL_AUTO; 347169689Skan else if (strcmp(s1, "+2step") == 0) 348169689Skan out->flags |= FL_2STEP; 349169689Skan else if (strcmp(s1, "-2step") == 0) 350169689Skan out->flags &= ~FL_2STEP; 351169689Skan else if (strcmp(s1, "+perpnd") == 0) 352169689Skan out->flags |= FL_PERPND; 353169689Skan else if (strcmp(s1, "-perpnd") == 0) 354169689Skan out->flags &= ~FL_PERPND; 355169689Skan else 356169689Skan errx(EX_USAGE, "bad flag: %s", s1); 357169689Skan break; 358169689Skan } 359169689Skan free(s1); 360169689Skan } 361169689Skan 362169689Skan out->size = out->tracks * out->heads * out->sectrac; 363169689Skan} 364169689Skan 365169689Skan/* 366169689Skan * Print a textual translation of the drive (density) type described 367169689Skan * by `in' to stdout. The string uses the same form that is parseable 368169689Skan * by parse_fmt(). 369169689Skan */ 370169689Skanvoid 371169689Skanprint_fmt(struct fd_type in) 372169689Skan{ 373169689Skan int secsize, speed; 374169689Skan 375169689Skan secsize = 128 << in.secsize; 376169689Skan switch (in.trans) { 377169689Skan case FDC_250KBPS: speed = 250; break; 378169689Skan case FDC_300KBPS: speed = 300; break; 379169689Skan case FDC_500KBPS: speed = 500; break; 380169689Skan case FDC_1MBPS: speed = 1000; break; 381169689Skan default: speed = 1; break; 382169689Skan } 383169689Skan 384169689Skan printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d", 385169689Skan in.sectrac, secsize, in.datalen, in.gap, in.tracks, 386169689Skan speed, in.heads, in.f_gap, in.f_inter, in.offset_side2); 387169689Skan if (in.flags & FL_MFM) 388169689Skan printf(",+mfm"); 389169689Skan if (in.flags & FL_2STEP) 390169689Skan printf(",+2step"); 391169689Skan if (in.flags & FL_PERPND) 392169689Skan printf(",+perpnd"); 393169689Skan if (in.flags & FL_AUTO) 394169689Skan printf(",+auto"); 395169689Skan putc('\n', stdout); 396169689Skan} 397169689Skan 398169689Skan/* 399169689Skan * Based on `size' (in kilobytes), walk through the table of known 400169689Skan * densities for drive type `type' and see if we can find one. If 401169689Skan * found, return it (as a pointer to static storage), otherwise return 402169689Skan * NULL. 403169689Skan */ 404169689Skanstruct fd_type * 405169689Skanget_fmt(int size, enum fd_drivetype type) 406169689Skan{ 407169689Skan int i, n; 408169689Skan struct fd_type *fdtp; 409169689Skan 410169689Skan switch (type) { 411169689Skan default: 412169689Skan return (0); 413169689Skan 414169689Skan case FDT_360K: 415169689Skan fdtp = fd_types_360k; 416169689Skan n = sizeof fd_types_360k / sizeof(struct fd_type); 417169689Skan break; 418169689Skan 419169689Skan case FDT_720K: 420169689Skan fdtp = fd_types_720k; 421169689Skan n = sizeof fd_types_720k / sizeof(struct fd_type); 422169689Skan break; 423169689Skan 424169689Skan case FDT_12M: 425169689Skan fdtp = fd_types_12m; 426169689Skan n = sizeof fd_types_12m / sizeof(struct fd_type); 427169689Skan break; 428169689Skan 429169689Skan case FDT_144M: 430169689Skan fdtp = fd_types_144m; 431169689Skan n = sizeof fd_types_144m / sizeof(struct fd_type); 432169689Skan break; 433169689Skan 434169689Skan case FDT_288M: 435169689Skan fdtp = fd_types_288m; 436169689Skan n = sizeof fd_types_288m / sizeof(struct fd_type); 437169689Skan break; 438169689Skan } 439169689Skan 440169689Skan if (size == -1) 441169689Skan return fd_types_auto; 442169689Skan 443169689Skan for (i = 0; i < n; i++, fdtp++) { 444169689Skan fdtp->size = fdtp->sectrac * fdtp->heads * fdtp->tracks; 445169689Skan if (((128 << fdtp->secsize) * fdtp->size / 1024) == size) 446169689Skan return (fdtp); 447169689Skan } 448169689Skan return (0); 449169689Skan} 450169689Skan 451169689Skan/* 452169689Skan * Parse a number from `s'. If the string cannot be converted into a 453169689Skan * number completely, return -1, otherwise 0. The result is returned 454169689Skan * in `*res'. 455169689Skan */ 456169689Skanint 457169689Skangetnum(const char *s, int *res) 458169689Skan{ 459169689Skan unsigned long ul; 460169689Skan char *cp; 461169689Skan 462169689Skan ul = strtoul(s, &cp, 0); 463169689Skan if (*cp != '\0') 464169689Skan return (-1); 465169689Skan 466169689Skan *res = (int)ul; 467169689Skan return (0); 468169689Skan} 469169689Skan 470169689Skan/* 471169689Skan * Return a short name and a verbose description for the drive 472169689Skan * described by `t'. 473169689Skan */ 474169689Skanvoid 475169689Skangetname(enum fd_drivetype t, const char **name, const char **descr) 476169689Skan{ 477169689Skan 478169689Skan switch (t) { 479169689Skan default: 480169689Skan *name = "unknown"; 481169689Skan *descr = "unknown drive type"; 482169689Skan break; 483169689Skan 484169689Skan case FDT_360K: 485169689Skan *name = "360K"; 486169689Skan *descr = "5.25\" double-density"; 487169689Skan break; 488169689Skan 489169689Skan case FDT_12M: 490169689Skan *name = "1.2M"; 491169689Skan *descr = "5.25\" high-density"; 492169689Skan break; 493169689Skan 494169689Skan case FDT_720K: 495169689Skan *name = "720K"; 496169689Skan *descr = "3.5\" double-density"; 497169689Skan break; 498169689Skan 499169689Skan case FDT_144M: 500169689Skan *name = "1.44M"; 501169689Skan *descr = "3.5\" high-density"; 502169689Skan break; 503169689Skan 504169689Skan case FDT_288M: 505169689Skan *name = "2.88M"; 506169689Skan *descr = "3.5\" extra-density"; 507169689Skan break; 508169689Skan } 509169689Skan} 510169689Skan