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