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