xref: /netbsd-src/sys/arch/acorn32/mainbus/fd.c (revision 13a5afa916a6322aeb5e5335b5ab61c01c5d0376)
1 /*	$NetBSD: fd.c,v 1.65 2023/08/28 17:53:46 andvar Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*-
33  * Copyright (c) 1990 The Regents of the University of California.
34  * All rights reserved.
35  *
36  * This code is derived from software contributed to Berkeley by
37  * Don Ahn.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. Neither the name of the University nor the names of its contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  *
63  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
64  *	from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
65  */
66 
67 /*
68  * Floppy formatting facilities merged from FreeBSD fd.c driver:
69  *	Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
70  * which carries the same copyright/redistribution notice as shown above with
71  * the addition of the following statement before the "Redistribution and
72  * use ..." clause:
73  *
74  * Copyright (c) 1993, 1994 by
75  *  jc@irbs.UUCP (John Capo)
76  *  vak@zebub.msk.su (Serge Vakulenko)
77  *  ache@astral.msk.su (Andrew A. Chernov)
78  *
79  * Copyright (c) 1993, 1994, 1995 by
80  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
81  *  dufault@hda.com (Peter Dufault)
82  */
83 
84 #include <sys/cdefs.h>
85 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.65 2023/08/28 17:53:46 andvar Exp $");
86 
87 #include "opt_ddb.h"
88 
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/callout.h>
92 #include <sys/kernel.h>
93 #include <sys/file.h>
94 #include <sys/ioctl.h>
95 #include <sys/device.h>
96 #include <sys/disklabel.h>
97 #include <sys/disk.h>
98 #include <sys/buf.h>
99 #include <sys/bufq.h>
100 #include <sys/kmem.h>
101 #include <sys/uio.h>
102 #include <sys/syslog.h>
103 #include <sys/queue.h>
104 #include <sys/proc.h>
105 #include <sys/fdio.h>
106 #include <sys/conf.h>
107 #include <sys/bus.h>
108 
109 #include <uvm/uvm_extern.h>
110 
111 #include <arm/fiq.h>
112 
113 #include <machine/cpu.h>
114 #include <machine/intr.h>
115 #include <machine/io.h>
116 
117 #include <arm/iomd/iomdreg.h>
118 #include <arm/iomd/iomdvar.h>
119 
120 #include <acorn32/mainbus/piocvar.h>
121 #include <acorn32/mainbus/fdreg.h>
122 
123 #include "locators.h"
124 
125 #define NE7CMD_CONFIGURE 0x13
126 
127 #define FDUNIT(dev)	(minor(dev) / 8)
128 #define FDTYPE(dev)	(minor(dev) % 8)
129 
130 /* (mis)use device use flag to identify format operation */
131 #define B_FORMAT B_DEVPRIVATE
132 
133 enum fdc_state {
134 	DEVIDLE = 0,
135 	MOTORWAIT,
136 	DOSEEK,
137 	SEEKWAIT,
138 	SEEKTIMEDOUT,
139 	SEEKCOMPLETE,
140 	DOIO,
141 	IOCOMPLETE,
142 	IOTIMEDOUT,
143 	DORESET,
144 	RESETCOMPLETE,
145 	RESETTIMEDOUT,
146 	DORECAL,
147 	RECALWAIT,
148 	RECALTIMEDOUT,
149 	RECALCOMPLETE,
150 };
151 
152 /* software state, per controller */
153 struct fdc_softc {
154 	device_t sc_dev;		/* boilerplate */
155 	void *sc_ih;
156 
157 	bus_space_tag_t sc_iot;		/* ISA i/o space identifier */
158 	bus_space_handle_t   sc_ioh;	/* ISA io handle */
159 
160 	struct callout sc_timo_ch;	/* timeout callout */
161 	struct callout sc_intr_ch;	/* pseudo-intr callout */
162 
163 	/* ...for pseudo-DMA... */
164 	struct fiqhandler sc_fh;	/* FIQ handler descriptor */
165 	struct fiqregs sc_fr;		/* FIQ handler reg context */
166 	int sc_drq;
167 
168 	struct fd_softc *sc_fd[4];	/* pointers to children */
169 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
170 	enum fdc_state sc_state;
171 	int sc_errors;			/* number of retries so far */
172 	u_char sc_status[7];		/* copy of registers */
173 };
174 
175 /* controller driver configuration */
176 int fdcprobe(device_t, cfdata_t, void *);
177 int fdprint(void *, const char *);
178 void fdcattach(device_t, device_t, void *);
179 
180 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc),
181     fdcprobe, fdcattach, NULL, NULL);
182 
183 /*
184  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
185  * we tell them apart.
186  */
187 struct fd_type {
188 	int	sectrac;	/* sectors per track */
189 	int	heads;		/* number of heads */
190 	int	seccyl;		/* sectors per cylinder */
191 	int	secsize;	/* size code for sectors */
192 	int	datalen;	/* data len when secsize = 0 */
193 	int	steprate;	/* step rate and head unload time */
194 	int	gap1;		/* gap len between sectors */
195 	int	gap2;		/* formatting gap */
196 	int	cyls;		/* total num of cylinders */
197 	int	size;		/* size of disk in sectors */
198 	int	step;		/* steps per cylinder */
199 	int	rate;		/* transfer speed code */
200 	u_char	fillbyte;	/* format fill byte */
201 	u_char	interleave;	/* interleave factor (formatting) */
202 	const char *name;
203 };
204 
205 /* The order of entries in the following table is important -- BEWARE! */
206 struct fd_type fd_types[] = {
207 	{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB"    }, /* 1.44MB diskette */
208 	{ 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB"    }, /* 1.2 MB AT-diskettes */
209 	{  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
210 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
211 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB"    }, /* 3.5" 720kB diskette */
212 	{  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x"  }, /* 720kB in 1.2MB drive */
213 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x"  }, /* 360kB in 720kB drive */
214 };
215 
216 /* software state, per disk (with up to 4 disks per ctlr) */
217 struct fd_softc {
218 	device_t sc_dev;
219 	struct disk sc_dk;
220 
221 	struct fd_type *sc_deftype;	/* default type descriptor */
222 	struct fd_type *sc_type;	/* current type descriptor */
223 	struct fd_type sc_type_copy;	/* copy for fiddling when formatting */
224 
225 	struct callout sc_motoron_ch;
226 	struct callout sc_motoroff_ch;
227 
228 	daddr_t	sc_blkno;	/* starting block number */
229 	int sc_bcount;		/* byte count left */
230  	int sc_opts;			/* user-set options */
231 	int sc_skip;		/* bytes already transferred */
232 	int sc_nblks;		/* number of blocks currently transferring */
233 	int sc_nbytes;		/* number of bytes currently transferring */
234 
235 	int sc_drive;		/* physical unit number */
236 	int sc_flags;
237 #define	FD_OPEN		0x01		/* it's open */
238 #define	FD_MOTOR	0x02		/* motor should be on */
239 #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
240 	int sc_cylin;		/* where we think the head is */
241 
242 	void *sc_sdhook;	/* saved shutdown hook for drive. */
243 
244 	TAILQ_ENTRY(fd_softc) sc_drivechain;
245 	int sc_ops;		/* I/O ops since last switch */
246 	struct bufq_state *sc_q;/* pending I/O requests */
247 	int sc_active;		/* number of active I/O operations */
248 };
249 
250 /* floppy driver configuration */
251 int fdprobe(device_t, cfdata_t, void *);
252 void fdattach(device_t, device_t, void *);
253 
254 extern char floppy_read_fiq[], floppy_read_fiq_end[];
255 extern char floppy_write_fiq[], floppy_write_fiq_end[];
256 
257 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
258     fdprobe, fdattach, NULL, NULL);
259 
260 extern struct cfdriver fd_cd;
261 
262 dev_type_open(fdopen);
263 dev_type_close(fdclose);
264 dev_type_read(fdread);
265 dev_type_write(fdwrite);
266 dev_type_ioctl(fdioctl);
267 dev_type_strategy(fdstrategy);
268 
269 const struct bdevsw fd_bdevsw = {
270 	.d_open = fdopen,
271 	.d_close = fdclose,
272 	.d_strategy = fdstrategy,
273 	.d_ioctl = fdioctl,
274 	.d_dump = nodump,
275 	.d_psize = nosize,
276 	.d_discard = nodiscard,
277 	.d_flag = D_DISK
278 };
279 
280 const struct cdevsw fd_cdevsw = {
281 	.d_open = fdopen,
282 	.d_close = fdclose,
283 	.d_read = fdread,
284 	.d_write = fdwrite,
285 	.d_ioctl = fdioctl,
286 	.d_stop = nostop,
287 	.d_tty = notty,
288 	.d_poll = nopoll,
289 	.d_mmap = nommap,
290 	.d_kqfilter = nokqfilter,
291 	.d_discard = nodiscard,
292 	.d_flag = D_DISK
293 };
294 
295 void fdgetdisklabel(struct fd_softc *);
296 int fd_get_parms(struct fd_softc *);
297 void fdstart(struct fd_softc *);
298 
299 struct dkdriver fddkdriver = {
300 	.d_strategy = fdstrategy
301 };
302 
303 struct fd_type *fd_nvtotype(const char *, int, int);
304 void fd_set_motor(struct fdc_softc *fdc, int reset);
305 void fd_motor_off(void *arg);
306 void fd_motor_on(void *arg);
307 int fdcresult(struct fdc_softc *fdc);
308 int out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x);
309 void fdcstart(struct fdc_softc *fdc);
310 void fdcstatus(device_t dv, int n, const char *s);
311 void fdctimeout(void *arg);
312 void fdcpseudointr(void *arg);
313 int fdcintr(void *);
314 void fdcretry(struct fdc_softc *fdc);
315 void fdfinish(struct fd_softc *fd, struct buf *bp);
316 static struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
317 int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *);
318 
319 int
fdcprobe(device_t parent,cfdata_t cf,void * aux)320 fdcprobe(device_t parent, cfdata_t cf, void *aux)
321 {
322 	struct pioc_attach_args *pa = aux;
323 	bus_space_tag_t iot;
324 	bus_space_handle_t ioh;
325 	int rv;
326 
327 	if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0)
328 		return(0);
329 
330 	iot = pa->pa_iot;
331 	rv = 0;
332 
333 	/* Map the i/o space. */
334 	if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
335 		return 0;
336 
337 	/* reset */
338 	bus_space_write_2(iot, ioh, fdout, 0);
339 	delay(100);
340 	bus_space_write_2(iot, ioh, fdout, FDO_FRST);
341 
342 	/* see if it can handle a command */
343 	if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
344 		goto out;
345 	out_fdc(iot, ioh, 0xdf);
346 	out_fdc(iot, ioh, 2);
347 
348 	rv = 1;
349 	pa->pa_iosize = FDC_NPORT;
350 
351  out:
352 	bus_space_unmap(iot, ioh, FDC_NPORT);
353 	return rv;
354 }
355 
356 /*
357  * Arguments passed between fdcattach and fdprobe.
358  */
359 struct fdc_attach_args {
360 	int fa_drive;
361 	struct fd_type *fa_deftype;
362 };
363 
364 /*
365  * Print the location of a disk drive (called just before attaching the
366  * the drive).  If `fdc' is not NULL, the drive was found but was not
367  * in the system config file; print the drive name as well.
368  * Return QUIET (config_find ignores this if the device was configured) to
369  * avoid printing `fdN not configured' messages.
370  */
371 int
fdprint(void * aux,const char * fdc)372 fdprint(void *aux, const char *fdc)
373 {
374 	register struct fdc_attach_args *fa = aux;
375 
376 	if (!fdc)
377 		aprint_normal(" drive %d", fa->fa_drive);
378 	return QUIET;
379 }
380 
381 void
fdcattach(device_t parent,device_t self,void * aux)382 fdcattach(device_t parent, device_t self, void *aux)
383 {
384 	struct fdc_softc *fdc = device_private(self);
385 	bus_space_tag_t iot;
386 	bus_space_handle_t ioh;
387 	struct pioc_attach_args *pa = aux;
388 	struct fdc_attach_args fa;
389 	int type;
390 
391 	iot = pa->pa_iot;
392 
393 	/* Re-map the I/O space. */
394 	if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
395 		panic("fdcattach: couldn't map I/O ports");
396 
397 	fdc->sc_dev = self;
398 	fdc->sc_iot = iot;
399 	fdc->sc_ioh = ioh;
400 
401 	fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq;
402 	fdc->sc_state = DEVIDLE;
403 	TAILQ_INIT(&fdc->sc_drives);
404 
405 	printf("\n");
406 
407 	callout_init(&fdc->sc_timo_ch, 0);
408 	callout_init(&fdc->sc_intr_ch, 0);
409 
410 	fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc", fdcintr, fdc);
411 	if (!fdc->sc_ih)
412 		panic("%s: Cannot claim IRQ %d",
413 		    device_xname(self), pa->pa_irq);
414 
415 #if 0
416 	/*
417 	 * The NVRAM info only tells us about the first two disks on the
418 	 * `primary' floppy controller.
419 	 */
420 	if (device_unit(fdc->sc_dev) == 0)
421 		type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
422 	else
423 		type = -1;
424 #endif
425 	type = 0x10;	/* XXX - hardcoded for 1 floppy */
426 
427 	/* physical limit: four drives per controller. */
428 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
429 		if (type >= 0 && fa.fa_drive < 2)
430 			fa.fa_deftype = fd_nvtotype(device_xname(fdc->sc_dev),
431 			    type, fa.fa_drive);
432 		else
433 			fa.fa_deftype = NULL;		/* unknown */
434 		(void)config_found(self, (void *)&fa, fdprint, CFARGS_NONE);
435 	}
436 }
437 
438 int
fdprobe(device_t parent,cfdata_t cf,void * aux)439 fdprobe(device_t parent, cfdata_t cf, void *aux)
440 {
441 	struct fdc_softc *fdc = device_private(parent);
442 	struct fdc_attach_args *fa = aux;
443 	int drive = fa->fa_drive;
444 	bus_space_tag_t iot = fdc->sc_iot;
445 	bus_space_handle_t ioh = fdc->sc_ioh;
446 	int n;
447 
448 	if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT
449 	  && cf->cf_loc[FDCCF_DRIVE] != drive)
450 		return 0;
451 	/*
452 	 * XXX
453 	 * This is to work around some odd interactions between this driver
454 	 * and SMC Ethernet cards.
455 	 */
456 
457 	/* Don't need this for arm32 port but leave for the time being (it won't hurt) */
458 
459 	if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
460 		return 0;
461 
462 	/* select drive and turn on motor */
463 	bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
464 	/* wait for motor to spin up */
465 	delay(250000);
466 	out_fdc(iot, ioh, NE7CMD_RECAL);
467 	out_fdc(iot, ioh, drive);
468 	/* wait for recalibrate */
469 	delay(2000000);
470 	out_fdc(iot, ioh, NE7CMD_SENSEI);
471 	n = fdcresult(fdc);
472 #ifdef FD_DEBUG
473 	{
474 		int i;
475 		printf("fdprobe: status");
476 		for (i = 0; i < n; i++)
477 			printf(" %x", fdc->sc_status[i]);
478 		printf("\n");
479 	}
480 #endif
481 	/* turn off motor */
482 	bus_space_write_1(iot, ioh, fdout, FDO_FRST);
483 
484 	if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
485 		return 0;
486 
487 	return 1;
488 }
489 
490 /*
491  * Controller is working, and drive responded.  Attach it.
492  */
493 void
fdattach(device_t parent,device_t self,void * aux)494 fdattach(device_t parent, device_t self, void *aux)
495 {
496 	struct fdc_softc *fdc = device_private(parent);
497 	struct fd_softc *fd = device_private(self);
498 	struct fdc_attach_args *fa = aux;
499 	struct fd_type *type = fa->fa_deftype;
500 	int drive = fa->fa_drive;
501 
502 	fd->sc_dev = self;
503 
504 	callout_init(&fd->sc_motoron_ch, 0);
505 	callout_init(&fd->sc_motoroff_ch, 0);
506 
507 	/* XXX Allow `flags' to override device type? */
508 
509 	if (type)
510 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
511 		    type->cyls, type->heads, type->sectrac);
512 	else
513 		printf(": density unknown\n");
514 
515 	bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
516 	fd->sc_cylin = -1;
517 	fd->sc_drive = drive;
518 	fd->sc_deftype = type;
519 	fdc->sc_fd[drive] = fd;
520 
521 	/*
522 	 * Initialize and attach the disk structure.
523 	 */
524 	disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
525 	disk_attach(&fd->sc_dk);
526 
527 	/* Needed to power off if the motor is on when we halt. */
528 
529 }
530 
531 /*
532  * Translate nvram type into internal data structure.  Return NULL for
533  * none/unknown/unusable.
534  */
535 struct fd_type *
fd_nvtotype(const char * fdc,int nvraminfo,int drive)536 fd_nvtotype(const char *fdc, int nvraminfo, int drive)
537 {
538 	int type;
539 
540 	type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
541 	switch (type) {
542 #ifndef RC7500
543 	case 0x00 :
544 		return NULL;
545 #else
546 	case 0x00 :
547 #endif	/* !RC7500 */
548 	case 0x10 :
549 		return &fd_types[0];
550 	default:
551 		printf("%s: drive %d: unknown device type 0x%x\n",
552 		    fdc, drive, type);
553 		return NULL;
554 	}
555 }
556 
557 static struct fd_type *
fd_dev_to_type(struct fd_softc * fd,dev_t dev)558 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
559 {
560 	int type = FDTYPE(dev);
561 
562 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
563 		return NULL;
564 	return type ? &fd_types[type - 1] : fd->sc_deftype;
565 }
566 
567 void
fdstrategy(struct buf * bp)568 fdstrategy(struct buf *bp)
569 {
570 	struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(bp->b_dev));
571 	int sz;
572  	int s;
573 
574 	/* Valid unit, controller, and request? */
575 	if (bp->b_blkno < 0 ||
576 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
577 	     (bp->b_flags & B_FORMAT) == 0)) {
578 		bp->b_error = EINVAL;
579 		goto done;
580 	}
581 
582 	/* If it's a null transfer, return immediately. */
583 	if (bp->b_bcount == 0)
584 		goto done;
585 
586 	sz = howmany(bp->b_bcount, FDC_BSIZE);
587 
588 	if (bp->b_blkno + sz > fd->sc_type->size) {
589 		sz = fd->sc_type->size - bp->b_blkno;
590 		if (sz == 0) {
591 			/* If exactly at end of disk, return EOF. */
592 			goto done;
593 		}
594 		if (sz < 0) {
595 			/* If past end of disk, return EINVAL. */
596 			bp->b_error = EINVAL;
597 			goto done;
598 		}
599 		/* Otherwise, truncate request. */
600 		bp->b_bcount = sz << DEV_BSHIFT;
601 	}
602 
603 	bp->b_rawblkno = bp->b_blkno;
604  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
605 
606 #ifdef FD_DEBUG
607 	printf("fdstrategy: b_blkno %lld b_bcount %d blkno %lld cylin %d sz %d\n",
608 	    bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
609 #endif
610 
611 	/* Queue transfer on drive, activate drive and controller if idle. */
612 	s = splbio();
613 	bufq_put(fd->sc_q, bp);
614 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
615 	if (fd->sc_active == 0)
616 		fdstart(fd);
617 #ifdef DIAGNOSTIC
618 	else {
619 		struct fdc_softc *fdc =
620 		    device_private(device_parent(fd->sc_dev));
621 		if (fdc->sc_state == DEVIDLE) {
622 			printf("fdstrategy: controller inactive\n");
623 			fdcstart(fdc);
624 		}
625 	}
626 #endif
627 	splx(s);
628 	return;
629 
630 done:
631 	/* Toss transfer; we're done early. */
632 	bp->b_resid = bp->b_bcount;
633 	biodone(bp);
634 }
635 
636 void
fdstart(struct fd_softc * fd)637 fdstart(struct fd_softc *fd)
638 {
639 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
640 	int active = fdc->sc_drives.tqh_first != 0;
641 
642 	/* Link into controller queue. */
643 	fd->sc_active = 1;
644 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
645 
646 	/* If controller not already active, start it. */
647 	if (!active)
648 		fdcstart(fdc);
649 }
650 
651 void
fdfinish(struct fd_softc * fd,struct buf * bp)652 fdfinish(struct fd_softc *fd, struct buf *bp)
653 {
654 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
655 
656 	/*
657 	 * Move this drive to the end of the queue to give others a `fair'
658 	 * chance.  We only force a switch if N operations are completed while
659 	 * another drive is waiting to be serviced, since there is a long motor
660 	 * startup delay whenever we switch.
661 	 */
662 	(void)bufq_get(fd->sc_q);
663 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
664 		fd->sc_ops = 0;
665 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
666 		if (bufq_peek(fd->sc_q) != NULL)
667 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
668 		else
669 			fd->sc_active = 0;
670 	}
671 	bp->b_resid = fd->sc_bcount;
672 	fd->sc_skip = 0;
673 
674 	biodone(bp);
675 	/* turn off motor 5s from now */
676 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
677 	fdc->sc_state = DEVIDLE;
678 }
679 
680 int
fdread(dev_t dev,struct uio * uio,int flags)681 fdread(dev_t dev, struct uio *uio, int flags)
682 {
683 
684 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
685 }
686 
687 int
fdwrite(dev_t dev,struct uio * uio,int flags)688 fdwrite(dev_t dev, struct uio *uio, int flags)
689 {
690 
691 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
692 }
693 
694 void
fd_set_motor(struct fdc_softc * fdc,int reset)695 fd_set_motor(struct fdc_softc *fdc, int reset)
696 {
697 	struct fd_softc *fd;
698 	u_char status;
699 	int n;
700 
701 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
702 		status = fd->sc_drive;
703 	else
704 		status = 0;
705 	if (!reset)
706 		status |= FDO_FRST | FDO_FDMAEN;
707 	for (n = 0; n < 4; n++)
708 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
709 			status |= FDO_MOEN(n);
710 	bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
711 }
712 
713 void
fd_motor_off(void * arg)714 fd_motor_off(void *arg)
715 {
716 	struct fd_softc *fd = arg;
717 	int s;
718 
719 	s = splbio();
720 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
721 	fd_set_motor(device_private(device_parent(fd->sc_dev)), 0);
722 	splx(s);
723 }
724 
725 void
fd_motor_on(void * arg)726 fd_motor_on(void *arg)
727 {
728 	struct fd_softc *fd = arg;
729 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
730 	int s;
731 
732 	s = splbio();
733 	fd->sc_flags &= ~FD_MOTOR_WAIT;
734 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
735 		(void) fdcintr(fdc);
736 	splx(s);
737 }
738 
739 int
fdcresult(struct fdc_softc * fdc)740 fdcresult(struct fdc_softc *fdc)
741 {
742 	bus_space_tag_t iot = fdc->sc_iot;
743 	bus_space_handle_t ioh = fdc->sc_ioh;
744 	u_char i;
745 	int j = 100000,
746 	    n = 0;
747 
748 	for (; j; j--) {
749 		i = bus_space_read_1(iot, ioh, fdsts) &
750 		    (NE7_DIO | NE7_RQM | NE7_CB);
751 		if (i == NE7_RQM)
752 			return n;
753 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
754 			if (n >= sizeof(fdc->sc_status)) {
755 				log(LOG_ERR, "fdcresult: overrun\n");
756 				return -1;
757 			}
758 			fdc->sc_status[n++] =
759 			    bus_space_read_1(iot, ioh, fddata);
760 		}
761 		delay(10);
762 	}
763 	log(LOG_ERR, "fdcresult: timeout\n");
764 	return -1;
765 }
766 
767 int
out_fdc(bus_space_tag_t iot,bus_space_handle_t ioh,u_char x)768 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
769 {
770 	int i = 100000;
771 
772 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
773 	if (i <= 0)
774 		return -1;
775 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
776 	if (i <= 0)
777 		return -1;
778 	bus_space_write_2(iot, ioh, fddata, x);
779 	return 0;
780 }
781 
782 int
fdopen(dev_t dev,int flags,int mode,struct lwp * l)783 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
784 {
785 	struct fd_softc *fd;
786 	struct fd_type *type;
787 
788 	fd = device_lookup_private(&fd_cd, FDUNIT(dev));
789 	if (fd == NULL)
790 		return ENXIO;
791 	type = fd_dev_to_type(fd, dev);
792 	if (type == NULL)
793 		return ENXIO;
794 
795 	if ((fd->sc_flags & FD_OPEN) != 0 &&
796 	    memcmp(fd->sc_type, type, sizeof(*type)))
797 		return EBUSY;
798 
799 	fd->sc_type_copy = *type;
800 	fd->sc_type = &fd->sc_type_copy;
801 	fd->sc_cylin = -1;
802 	fd->sc_flags |= FD_OPEN;
803 
804 	return 0;
805 }
806 
807 int
fdclose(dev_t dev,int flags,int mode,struct lwp * l)808 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
809 {
810 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
811 
812 	fd->sc_flags &= ~FD_OPEN;
813 	fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
814 	return 0;
815 }
816 
817 void
fdcstart(struct fdc_softc * fdc)818 fdcstart(struct fdc_softc *fdc)
819 {
820 
821 #ifdef DIAGNOSTIC
822 	/* only got here if controller's drive queue was inactive; should
823 	   be in idle state */
824 	if (fdc->sc_state != DEVIDLE) {
825 		printf("fdcstart: not idle\n");
826 		return;
827 	}
828 #endif
829 	(void) fdcintr(fdc);
830 }
831 
832 static void
fdcpstatus(int n,struct fdc_softc * fdc)833 fdcpstatus(int n, struct fdc_softc *fdc)
834 {
835 	char bits[64];
836 
837 	switch (n) {
838 	case 0:
839 		printf("\n");
840 		break;
841 	case 2:
842 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
843 		printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
844 		break;
845 	case 7:
846 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
847 		printf(" (st0 %s", bits);
848 		snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
849 		printf(" st1 %s", bits);
850 		snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
851 		printf(" st2 %s", bits);
852 		printf(" cyl %d head %d sec %d)\n",
853 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
854 		break;
855 #ifdef DIAGNOSTIC
856 	default:
857 		printf("\nfdcstatus: weird size");
858 		break;
859 #endif
860 	}
861 }
862 
863 void
fdcstatus(device_t dv,int n,const char * s)864 fdcstatus(device_t dv, int n, const char *s)
865 {
866 	struct fdc_softc *fdc = device_private(device_parent(dv));
867 
868 	if (n == 0) {
869 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
870 		(void) fdcresult(fdc);
871 		n = 2;
872 	}
873 
874 	printf("%s: %s", device_xname(dv), s);
875 	fdcpstatus(n, fdc);
876 }
877 
878 void
fdctimeout(void * arg)879 fdctimeout(void *arg)
880 {
881 	struct fdc_softc *fdc = arg;
882 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
883 	int s;
884 
885 	s = splbio();
886 #ifdef DEBUG
887 	log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
888 #endif
889 	fdcstatus(fd->sc_dev, 0, "timeout");
890 
891 	if (bufq_peek(fd->sc_q) != NULL)
892 		fdc->sc_state++;
893 	else
894 		fdc->sc_state = DEVIDLE;
895 
896 	(void) fdcintr(fdc);
897 	splx(s);
898 }
899 
900 void
fdcpseudointr(void * arg)901 fdcpseudointr(void *arg)
902 {
903 	int s;
904 
905 	/* Just ensure it has the right spl. */
906 	s = splbio();
907 	(void) fdcintr(arg);
908 	splx(s);
909 }
910 
911 int
fdcintr(void * arg)912 fdcintr(void *arg)
913 {
914 	struct fdc_softc *fdc = arg;
915 #define	st0	fdc->sc_status[0]
916 #define	cyl	fdc->sc_status[1]
917 	struct fd_softc *fd;
918 	struct buf *bp;
919 	bus_space_tag_t iot = fdc->sc_iot;
920 	bus_space_handle_t ioh = fdc->sc_ioh;
921 	int read, head, sec, i, nblks;
922 	struct fd_type *type;
923 	struct ne7_fd_formb *finfo = NULL;
924 
925 loop:
926 	/* Is there a drive for the controller to do a transfer with? */
927 	fd = fdc->sc_drives.tqh_first;
928 	if (fd == NULL) {
929 		fdc->sc_state = DEVIDLE;
930  		return 1;
931 	}
932 
933 	/* Is there a transfer to this drive?  If not, deactivate drive. */
934 	bp = bufq_peek(fd->sc_q);
935 	if (bp == NULL) {
936 		fd->sc_ops = 0;
937 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
938 		fd->sc_active = 0;
939 		goto loop;
940 	}
941 
942 	if (bp->b_flags & B_FORMAT)
943 		finfo = (struct ne7_fd_formb *)bp->b_data;
944 
945 	switch (fdc->sc_state) {
946 	case DEVIDLE:
947 		fdc->sc_errors = 0;
948 		fd->sc_skip = 0;
949 		fd->sc_bcount = bp->b_bcount;
950 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
951 		callout_stop(&fd->sc_motoroff_ch);
952 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
953 			fdc->sc_state = MOTORWAIT;
954 			return 1;
955 		}
956 		if ((fd->sc_flags & FD_MOTOR) == 0) {
957 			/* Turn on the motor, being careful about pairing. */
958 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
959 			if (ofd && ofd->sc_flags & FD_MOTOR) {
960 				callout_stop(&ofd->sc_motoroff_ch);
961 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
962 			}
963 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
964 			fd_set_motor(fdc, 0);
965 			fdc->sc_state = MOTORWAIT;
966 			/* Allow .25s for motor to stabilize. */
967 			callout_reset(&fd->sc_motoron_ch, hz / 4,
968 			    fd_motor_on, fd);
969 			return 1;
970 		}
971 		/* Make sure the right drive is selected. */
972 		fd_set_motor(fdc, 0);
973 
974 		/* fall through */
975 	case DOSEEK:
976 	doseek:
977 		if (fd->sc_cylin == bp->b_cylinder)
978 			goto doio;
979 
980 #if 1
981 		out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
982 		out_fdc(iot, ioh, 0);
983 		out_fdc(iot, ioh, 0x18);
984 		out_fdc(iot, ioh, 0);
985 #endif
986 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
987 		out_fdc(iot, ioh, fd->sc_type->steprate);
988 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
989 
990 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
991 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
992 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
993 
994 		fd->sc_cylin = -1;
995 		fdc->sc_state = SEEKWAIT;
996 
997 		iostat_seek(fd->sc_dk.dk_stats);
998 		disk_busy(&fd->sc_dk);
999 
1000 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1001 		return 1;
1002 
1003 	case DOIO:
1004 	doio:
1005 		type = fd->sc_type;
1006 		if (finfo)
1007 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1008 				      (char *)finfo;
1009 		sec = fd->sc_blkno % type->seccyl;
1010 		nblks = type->seccyl - sec;
1011 		nblks = uimin(nblks, fd->sc_bcount / FDC_BSIZE);
1012 		nblks = uimin(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1013 		fd->sc_nblks = nblks;
1014 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1015 		head = sec / type->sectrac;
1016 		sec -= head * type->sectrac;
1017 #ifdef DIAGNOSTIC
1018 		{daddr_t  block;
1019 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
1020 		 if (block != fd->sc_blkno) {
1021 			 printf("fdcintr: block %" PRId64
1022 			     " != blkno %" PRId64 "\n",
1023 				block, fd->sc_blkno);
1024 #ifdef DDB
1025 			 Debugger();
1026 #endif
1027 		 }}
1028 #endif
1029 		read = bp->b_flags & B_READ;
1030 		if (read) {
1031 			fdc->sc_fh.fh_func = floppy_read_fiq;
1032 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
1033 			    floppy_read_fiq;
1034 		} else {
1035 			fdc->sc_fh.fh_func = floppy_write_fiq;
1036 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
1037 			    floppy_read_fiq;
1038 		}
1039 		fdc->sc_fh.fh_flags = 0;
1040 		fdc->sc_fh.fh_regs = &fdc->sc_fr;
1041 		fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
1042 		fdc->sc_fr.fr_r10 = fd->sc_nbytes;
1043 		fdc->sc_fr.fr_r11 =
1044 		    (u_int)((uintptr_t)bp->b_data + fd->sc_skip);
1045 		fdc->sc_fr.fr_r12 = fdc->sc_drq;
1046 #ifdef FD_DEBUG
1047 		printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
1048 		    fdc->sc_fr.fr_r9, fdc->sc_fr.fr_r10, fdc->sc_fr.fr_r11,
1049 		    fdc->sc_fr.fr_r12, (u_int)bp->b_data, fd->sc_skip);
1050 #endif
1051 		if (fiq_claim(&fdc->sc_fh) == -1)
1052 			panic("%s: Cannot claim FIQ vector",
1053 			    device_xname(fdc->sc_dev));
1054 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
1055 		bus_space_write_2(iot, ioh, fdctl, type->rate);
1056 #ifdef FD_DEBUG
1057 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1058 			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1059 			head, sec, nblks);
1060 #endif
1061 		if (finfo) {
1062 			/* formatting */
1063 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1064 				fdc->sc_errors = 4;
1065 				fdcretry(fdc);
1066 				goto loop;
1067 			}
1068 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1069 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
1070 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1071 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1072 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1073 		} else {
1074 			if (read)
1075 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
1076 			else
1077 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1078 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1079 			out_fdc(iot, ioh, fd->sc_cylin); /* track */
1080 			out_fdc(iot, ioh, head);
1081 			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
1082 			out_fdc(iot, ioh, type->secsize);/* sector size */
1083 			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1084 			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
1085 			out_fdc(iot, ioh, type->datalen);/* data length */
1086 		}
1087 		fdc->sc_state = IOCOMPLETE;
1088 
1089 		disk_busy(&fd->sc_dk);
1090 
1091 		/* allow 2 seconds for operation */
1092 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1093 		return 1;				/* will return later */
1094 
1095 	case SEEKWAIT:
1096 		callout_stop(&fdc->sc_timo_ch);
1097 		fdc->sc_state = SEEKCOMPLETE;
1098 		/* allow 1/50 second for heads to settle */
1099 #if 0
1100 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1101 #endif
1102 		return 1;
1103 
1104 	case SEEKCOMPLETE:
1105 		/* no data on seek */
1106 		disk_unbusy(&fd->sc_dk, 0, 0);
1107 
1108 		/* Make sure seek really happened. */
1109 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1110 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1111 		    cyl != bp->b_cylinder * fd->sc_type->step) {
1112 #ifdef FD_DEBUG
1113 			fdcstatus(fd->sc_dev, 2, "seek failed");
1114 #endif
1115 			fdcretry(fdc);
1116 			goto loop;
1117 		}
1118 		fd->sc_cylin = bp->b_cylinder;
1119 		goto doio;
1120 
1121 	case IOTIMEDOUT:
1122 		fiq_release(&fdc->sc_fh);
1123 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1124 	case SEEKTIMEDOUT:
1125 	case RECALTIMEDOUT:
1126 	case RESETTIMEDOUT:
1127 		fdcretry(fdc);
1128 		goto loop;
1129 
1130 	case IOCOMPLETE: /* IO DONE, post-analyze */
1131 		callout_stop(&fdc->sc_timo_ch);
1132 
1133 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1134 		    (bp->b_flags & B_READ));
1135 
1136 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1137 			fiq_release(&fdc->sc_fh);
1138 			IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1139 #ifdef FD_DEBUG
1140 			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
1141 			    "read failed" : "write failed");
1142 			printf("blkno %lld nblks %d\n",
1143 			    fd->sc_blkno, fd->sc_nblks);
1144 #endif
1145 			fdcretry(fdc);
1146 			goto loop;
1147 		}
1148 		fiq_release(&fdc->sc_fh);
1149 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1150 		if (fdc->sc_errors) {
1151 #if 0
1152 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1153 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1154 			printf("\n");
1155 #endif
1156 			fdc->sc_errors = 0;
1157 		}
1158 		fd->sc_blkno += fd->sc_nblks;
1159 		fd->sc_skip += fd->sc_nbytes;
1160 		fd->sc_bcount -= fd->sc_nbytes;
1161 		if (!finfo && fd->sc_bcount > 0) {
1162 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1163 			goto doseek;
1164 		}
1165 		fdfinish(fd, bp);
1166 		goto loop;
1167 
1168 	case DORESET:
1169 		/* try a reset, keep motor on */
1170 		fd_set_motor(fdc, 1);
1171 		delay(100);
1172 		fd_set_motor(fdc, 0);
1173 		fdc->sc_state = RESETCOMPLETE;
1174 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1175 		return 1;			/* will return later */
1176 
1177 	case RESETCOMPLETE:
1178 		callout_stop(&fdc->sc_timo_ch);
1179 		/* clear the controller output buffer */
1180 		for (i = 0; i < 4; i++) {
1181 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1182 			(void) fdcresult(fdc);
1183 		}
1184 
1185 		/* fall through */
1186 	case DORECAL:
1187 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
1188 		out_fdc(iot, ioh, fd->sc_drive);
1189 		fdc->sc_state = RECALWAIT;
1190 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1191 		return 1;			/* will return later */
1192 
1193 	case RECALWAIT:
1194 		callout_stop(&fdc->sc_timo_ch);
1195 		fdc->sc_state = RECALCOMPLETE;
1196 		/* allow 1/30 second for heads to settle */
1197 #if 0
1198 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1199 #endif
1200 		return 1;			/* will return later */
1201 
1202 	case RECALCOMPLETE:
1203 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1204 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1205 #ifdef FD_DEBUG
1206 			fdcstatus(fd->sc_dev, 2, "recalibrate failed");
1207 #endif
1208 			fdcretry(fdc);
1209 			goto loop;
1210 		}
1211 		fd->sc_cylin = 0;
1212 		goto doseek;
1213 
1214 	case MOTORWAIT:
1215 		if (fd->sc_flags & FD_MOTOR_WAIT)
1216 			return 1;		/* time's not up yet */
1217 		goto doseek;
1218 
1219 	default:
1220 		fdcstatus(fd->sc_dev, 0, "stray interrupt");
1221 		return 1;
1222 	}
1223 #ifdef DIAGNOSTIC
1224 	panic("fdcintr: impossible");
1225 #endif
1226 #undef	st0
1227 #undef	cyl
1228 }
1229 
1230 void
fdcretry(struct fdc_softc * fdc)1231 fdcretry(struct fdc_softc *fdc)
1232 {
1233 	struct fd_softc *fd;
1234 	struct buf *bp;
1235 
1236 	fd = fdc->sc_drives.tqh_first;
1237 	bp = bufq_peek(fd->sc_q);
1238 
1239 	if (fd->sc_opts & FDOPT_NORETRY)
1240 	    goto fail;
1241 	switch (fdc->sc_errors) {
1242 	case 0:
1243 		/* try again */
1244 		fdc->sc_state = DOSEEK;
1245 		break;
1246 
1247 	case 1: case 2: case 3:
1248 		/* didn't work; try recalibrating */
1249 		fdc->sc_state = DORECAL;
1250 		break;
1251 
1252 	case 4:
1253 		/* still no go; reset the bastard */
1254 		fdc->sc_state = DORESET;
1255 		break;
1256 
1257 	default:
1258 	fail:
1259 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1260 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
1261 				fd->sc_skip / FDC_BSIZE,
1262 				(struct disklabel *)NULL);
1263 			fdcpstatus(7, fdc);
1264 		}
1265 
1266 		bp->b_error = EIO;
1267 		fdfinish(fd, bp);
1268 	}
1269 	fdc->sc_errors++;
1270 }
1271 
1272 int
fdioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)1273 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1274 {
1275 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1276 	struct fdformat_parms *form_parms;
1277 	struct fdformat_cmd *form_cmd;
1278 	struct ne7_fd_formb *fd_formb;
1279 	struct disklabel buffer;
1280 	int error;
1281 	unsigned int scratch;
1282 	int il[FD_MAX_NSEC + 1];
1283 	register int i, j;
1284 
1285 	switch (cmd) {
1286 	case DIOCGDINFO:
1287 		memset(&buffer, 0, sizeof(buffer));
1288 
1289 		buffer.d_secpercyl = fd->sc_type->seccyl;
1290 		buffer.d_type = DKTYPE_FLOPPY;
1291 		buffer.d_secsize = FDC_BSIZE;
1292 
1293 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1294 			return EINVAL;
1295 
1296 		*(struct disklabel *)addr = buffer;
1297 		return 0;
1298 
1299 	case DIOCWLABEL:
1300 		if ((flag & FWRITE) == 0)
1301 			return EBADF;
1302 		/* XXX do something */
1303 		return 0;
1304 
1305 	case DIOCWDINFO:
1306 		if ((flag & FWRITE) == 0)
1307 			return EBADF;
1308 
1309 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1310 		if (error)
1311 			return error;
1312 
1313 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1314 		return error;
1315 
1316 	case FDIOCGETFORMAT:
1317 		form_parms = (struct fdformat_parms *)addr;
1318 		form_parms->fdformat_version = FDFORMAT_VERSION;
1319 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1320 		form_parms->ncyl = fd->sc_type->cyls;
1321 		form_parms->nspt = fd->sc_type->sectrac;
1322 		form_parms->ntrk = fd->sc_type->heads;
1323 		form_parms->stepspercyl = fd->sc_type->step;
1324 		form_parms->gaplen = fd->sc_type->gap2;
1325 		form_parms->fillbyte = fd->sc_type->fillbyte;
1326 		form_parms->interleave = fd->sc_type->interleave;
1327 		switch (fd->sc_type->rate) {
1328 		case FDC_500KBPS:
1329 			form_parms->xfer_rate = 500 * 1024;
1330 			break;
1331 		case FDC_300KBPS:
1332 			form_parms->xfer_rate = 300 * 1024;
1333 			break;
1334 		case FDC_250KBPS:
1335 			form_parms->xfer_rate = 250 * 1024;
1336 			break;
1337 		default:
1338 			return EINVAL;
1339 		}
1340 		return 0;
1341 
1342 	case FDIOCSETFORMAT:
1343 		if((flag & FWRITE) == 0)
1344 			return EBADF;	/* must be opened for writing */
1345 		form_parms = (struct fdformat_parms *)addr;
1346 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
1347 			return EINVAL;	/* wrong version of formatting prog */
1348 
1349 		scratch = form_parms->nbps >> 7;
1350 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1351 		    scratch & ~(1 << (ffs(scratch)-1)))
1352 			/* not a power-of-two multiple of 128 */
1353 			return EINVAL;
1354 
1355 		switch (form_parms->xfer_rate) {
1356 		case 500 * 1024:
1357 			fd->sc_type->rate = FDC_500KBPS;
1358 			break;
1359 		case 300 * 1024:
1360 			fd->sc_type->rate = FDC_300KBPS;
1361 			break;
1362 		case 250 * 1024:
1363 			fd->sc_type->rate = FDC_250KBPS;
1364 			break;
1365 		default:
1366 			return EINVAL;
1367 		}
1368 
1369 		if (form_parms->nspt > FD_MAX_NSEC ||
1370 		    form_parms->fillbyte > 0xff ||
1371 		    form_parms->interleave > 0xff)
1372 			return EINVAL;
1373 		fd->sc_type->sectrac = form_parms->nspt;
1374 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1375 			return EINVAL;
1376 		fd->sc_type->heads = form_parms->ntrk;
1377 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1378 		fd->sc_type->secsize = ffs(scratch)-1;
1379 		fd->sc_type->gap2 = form_parms->gaplen;
1380 		fd->sc_type->cyls = form_parms->ncyl;
1381 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1382 			form_parms->nbps / DEV_BSIZE;
1383 		fd->sc_type->step = form_parms->stepspercyl;
1384 		fd->sc_type->fillbyte = form_parms->fillbyte;
1385 		fd->sc_type->interleave = form_parms->interleave;
1386 		return 0;
1387 
1388 	case FDIOCFORMAT_TRACK:
1389 		if((flag & FWRITE) == 0)
1390 			return EBADF;	/* must be opened for writing */
1391 		form_cmd = (struct fdformat_cmd *)addr;
1392 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1393 			return EINVAL;	/* wrong version of formatting prog */
1394 
1395 		if (form_cmd->head >= fd->sc_type->heads ||
1396 		    form_cmd->cylinder >= fd->sc_type->cyls) {
1397 			return EINVAL;
1398 		}
1399 
1400 		fd_formb = kmem_alloc(sizeof(*fd_formb), KM_SLEEP);
1401 		fd_formb->head = form_cmd->head;
1402 		fd_formb->cyl = form_cmd->cylinder;
1403 		fd_formb->transfer_rate = fd->sc_type->rate;
1404 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1405 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1406 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1407 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1408 
1409 		memset(il, 0, sizeof il);
1410 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1411 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
1412 				j++;
1413 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1414 			j += fd->sc_type->interleave;
1415 		}
1416 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1417 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1418 			fd_formb->fd_formb_headno(i) = form_cmd->head;
1419 			fd_formb->fd_formb_secno(i) = il[i+1];
1420 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1421 		}
1422 
1423 		error = fdformat(dev, fd_formb, l);
1424 		kmem_free(fd_formb, sizeof(*fd_formb));
1425 		return error;
1426 
1427 	case FDIOCGETOPTS:		/* get drive options */
1428 		*(int *)addr = fd->sc_opts;
1429 		return 0;
1430 
1431 	case FDIOCSETOPTS:		/* set drive options */
1432 		fd->sc_opts = *(int *)addr;
1433 		return 0;
1434 
1435 	default:
1436 		return ENOTTY;
1437 	}
1438 
1439 #ifdef DIAGNOSTIC
1440 	panic("fdioctl: impossible");
1441 #endif
1442 }
1443 
1444 int
fdformat(dev_t dev,struct ne7_fd_formb * finfo,struct lwp * l)1445 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
1446 {
1447 	int rv = 0;
1448 	struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev));
1449 	struct fd_type *type = fd->sc_type;
1450 	struct buf *bp;
1451 
1452 	/* set up a buffer header for fdstrategy() */
1453 	bp = getiobuf(NULL, false);
1454 	if(bp == 0)
1455 		return ENOBUFS;
1456 	bp->b_flags = B_PHYS | B_FORMAT;
1457 	bp->b_cflags |= BC_BUSY;
1458 	bp->b_proc = l->l_proc;
1459 	bp->b_dev = dev;
1460 
1461 	/*
1462 	 * calculate a fake blkno, so fdstrategy() would initiate a
1463 	 * seek to the requested cylinder
1464 	 */
1465 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1466 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1467 
1468 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1469 	bp->b_data = (void *)finfo;
1470 
1471 #ifdef DEBUG
1472 	printf("fdformat: blkno %llx count %x\n",
1473 	    (unsigned long long)bp->b_blkno, bp->b_bcount);
1474 #endif
1475 
1476 	/* now do the format */
1477 	fdstrategy(bp);
1478 
1479 	/* ...and wait for it to complete */
1480 	/* XXX very dodgy */
1481 	mutex_enter(bp->b_objlock);
1482 	while (!(bp->b_oflags & BO_DONE)) {
1483 		rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
1484 		if (rv == EWOULDBLOCK)
1485 			break;
1486 	}
1487 	mutex_exit(bp->b_objlock);
1488 
1489 	if (rv == EWOULDBLOCK) {
1490 		/* timed out */
1491 		rv = EIO;
1492 		biodone(bp);
1493 	} else if (bp->b_error != 0)
1494 		rv = bp->b_error;
1495 	putiobuf(bp);
1496 	return rv;
1497 }
1498 
1499 #include <dev/md.h>
1500 
1501 int load_memory_disc_from_floppy(struct md_conf *md, dev_t dev);
1502 
1503 int
load_memory_disc_from_floppy(struct md_conf * md,dev_t dev)1504 load_memory_disc_from_floppy(struct md_conf *md, dev_t dev)
1505 {
1506 	struct buf *bp;
1507 	int loop;
1508 	int s;
1509 	int type;
1510 	int floppysize;
1511 
1512 	if (bdevsw_lookup(dev) != &fd_bdevsw)
1513 		return(EINVAL);
1514 
1515 	if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
1516 		return(EBUSY);
1517 
1518 	type = FDTYPE(dev) - 1;
1519 	if (type < 0) type = 0;
1520 	floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
1521 
1522 	if (md->md_size < floppysize) {
1523 		printf("Memory disc is not big enough for floppy image\n");
1524 		return(EINVAL);
1525 	}
1526 
1527 /* We have the memory disk ! */
1528 
1529 	printf("Loading memory disc : %4dK ", 0);
1530 
1531 /* obtain a buffer */
1532 
1533 	bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
1534 
1535 /* request no partition relocation by driver on I/O operations */
1536 
1537 	bp->b_dev = dev;
1538 
1539 	s = splbio();
1540 
1541 	if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
1542 		brelse(bp, 0);
1543 		printf("Cannot open floppy device\n");
1544 			return(EINVAL);
1545 	}
1546 
1547 	for (loop = 0;
1548 	    loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
1549 	    ++loop) {
1550 		printf("\x08\x08\x08\x08\x08\x08%4dK ",
1551 		    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1552 		bp->b_blkno = loop * fd_types[type].sectrac;
1553 		bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
1554 		bp->b_flags |= B_READ;
1555 		bp->b_error = 0;
1556 		bp->b_resid = 0;
1557 		fdstrategy(bp);
1558 
1559 		if (biowait(bp))
1560 			panic("Cannot load floppy image");
1561 
1562 		memcpy((char *)md->md_addr + loop * fd_types[type].sectrac
1563 		    * DEV_BSIZE, (void *)bp->b_data,
1564 		    fd_types[type].sectrac * DEV_BSIZE);
1565 	}
1566 	printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1567 	    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1568 
1569 	fdclose(bp->b_dev, 0, 0, curlwp);
1570 
1571 	brelse(bp, 0);
1572 
1573 	splx(s);
1574 	return(0);
1575 }
1576