xref: /netbsd-src/sys/arch/x68k/dev/fd.c (revision 6b664a713479c31d4f17b38b42182a5d5fa21802)
1 /*	$NetBSD: fd.c,v 1.129 2024/01/07 07:58:33 isaki 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 and Minoura Makoto.
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  */
65 
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.129 2024/01/07 07:58:33 isaki Exp $");
68 
69 #include "opt_ddb.h"
70 #include "opt_m68k_arch.h"
71 
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/bus.h>
75 #include <sys/callout.h>
76 #include <sys/kernel.h>
77 #include <sys/conf.h>
78 #include <sys/file.h>
79 #include <sys/stat.h>
80 #include <sys/ioctl.h>
81 #include <sys/malloc.h>
82 #include <sys/device.h>
83 #include <sys/disklabel.h>
84 #include <sys/disk.h>
85 #include <sys/buf.h>
86 #include <sys/bufq.h>
87 #include <sys/uio.h>
88 #include <sys/syslog.h>
89 #include <sys/queue.h>
90 #include <sys/proc.h>
91 #include <sys/fdio.h>
92 #include <sys/rndsource.h>
93 
94 #include <dev/cons.h>
95 
96 #include <machine/cpu.h>
97 
98 #include <arch/x68k/dev/intiovar.h>
99 #include <arch/x68k/dev/dmacvar.h>
100 #include <arch/x68k/dev/fdreg.h>
101 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
102 
103 #include "locators.h"
104 #include "ioconf.h"
105 
106 #ifdef FDDEBUG
107 #define DPRINTF(x)      if (fddebug) printf x
108 int     fddebug = 0;
109 #else
110 #define DPRINTF(x)
111 #endif
112 
113 #define FDUNIT(dev)	(minor(dev) / 8)
114 #define FDTYPE(dev)	(minor(dev) % 8)
115 
116 /* (mis)use device use flag to identify format operation */
117 #define B_FORMAT B_DEVPRIVATE
118 
119 enum fdc_state {
120 	DEVIDLE = 0,
121 	MOTORWAIT,
122 	DOSEEK,
123 	SEEKWAIT,
124 	SEEKTIMEDOUT,
125 	SEEKCOMPLETE,
126 	DOIO,
127 	IOCOMPLETE,
128 	IOTIMEDOUT,
129 	DORESET,
130 	RESETCOMPLETE,
131 	RESETTIMEDOUT,
132 	DORECAL,
133 	RECALWAIT,
134 	RECALTIMEDOUT,
135 	RECALCOMPLETE,
136 	DOCOPY,
137 	DOIOHALF,
138 	COPYCOMPLETE,
139 };
140 
141 /* software state, per controller */
142 struct fdc_softc {
143 	bus_space_tag_t sc_iot;		/* intio i/o space identifier */
144 	bus_space_handle_t sc_ioh;	/* intio io handle */
145 
146 	struct callout sc_timo_ch;	/* timeout callout */
147 	struct callout sc_intr_ch;	/* pseudo-intr callout */
148 
149 	bus_dma_tag_t sc_dmat;		/* intio DMA tag */
150 	bus_dmamap_t sc_dmamap;		/* DMA map */
151 	uint8_t *sc_addr;		/* physical address */
152 	struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
153 	struct dmac_dma_xfer *sc_xfer;	/* DMA transfer */
154 	int sc_read;
155 
156 	struct fd_softc *sc_fd[4];	/* pointers to children */
157 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
158 	enum fdc_state sc_state;
159 	int sc_errors;			/* number of retries so far */
160 	uint8_t sc_status[7];		/* copy of registers */
161 };
162 
163 static int fdcintr(void *);
164 static void fdcreset(struct fdc_softc *);
165 
166 /* controller driver configuration */
167 static int fdcprobe(device_t, cfdata_t, void *);
168 static void fdcattach(device_t, device_t, void *);
169 static int fdprint(void *, const char *);
170 
171 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc),
172     fdcprobe, fdcattach, NULL, NULL);
173 
174 /*
175  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
176  * we tell them apart.
177  */
178 struct fd_type {
179 	int	sectrac;	/* sectors per track */
180 	int	heads;		/* number of heads */
181 	int	seccyl;		/* sectors per cylinder */
182 	int	secsize;	/* size code for sectors */
183 	int	datalen;	/* data len when secsize = 0 */
184 	int	steprate;	/* step rate and head unload time */
185 	int	gap1;		/* gap len between sectors */
186 	int	gap2;		/* formatting gap */
187 	int	cyls;		/* total num of cylinders */
188 	int	size;		/* size of disk in sectors */
189 	int	step;		/* steps per cylinder */
190 	int	rate;		/* transfer speed code */
191 	uint8_t	fillbyte;	/* format fill byte */
192 	uint8_t	interleave;	/* interleave factor (formatting) */
193 	const char *name;
194 };
195 
196 /* The order of entries in the following table is important -- BEWARE! */
197 static struct fd_type fd_types[] = {
198 	{  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, 0xf6, 1,
199 	    "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
200 	{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS, 0xf6, 1,
201 	    "1.44MB"    }, /* 1.44MB diskette */
202 	{ 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, 0xf6, 1,
203 	    "1.2MB"    }, /* 1.2 MB AT-diskettes */
204 	{  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, 0xf6, 1,
205 	    "360KB/AT" }, /* 360kB in 1.2MB drive */
206 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, 0xf6, 1,
207 	    "360KB/PC" }, /* 360kB PC diskettes */
208 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, 0xf6, 1,
209 	    "720KB"    }, /* 3.5" 720kB diskette */
210 	{  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, 0xf6, 1,
211 	    "720KB/x"  }, /* 720kB in 1.2MB drive */
212 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, 0xf6, 1,
213 	    "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 
224 #if 0	/* see comments in fd_motor_on() */
225 	struct callout sc_motoron_ch;
226 #endif
227 	struct callout sc_motoroff_ch;
228 
229 	daddr_t	sc_blkno;	/* starting block number */
230 	int sc_bcount;		/* byte count left */
231 	int sc_opts;		/* user-set options */
232 	int sc_skip;		/* bytes already transferred */
233 	int sc_nblks;		/* number of blocks currently transferring */
234 	int sc_nbytes;		/* number of bytes currently transferring */
235 
236 	int sc_drive;		/* physical unit number */
237 	int sc_flags;
238 #define	FD_BOPEN	0x01		/* it's open */
239 #define	FD_COPEN	0x02		/* it's open */
240 #define	FD_OPEN		(FD_BOPEN|FD_COPEN)	/* it's open */
241 #define	FD_MOTOR	0x04		/* motor should be on */
242 #define	FD_MOTOR_WAIT	0x08		/* motor coming up */
243 #define	FD_ALIVE	0x10		/* alive */
244 	int sc_cylin;		/* where we think the head is */
245 
246 	TAILQ_ENTRY(fd_softc) sc_drivechain;
247 	int sc_ops;		/* I/O ops since last switch */
248 	struct bufq_state *sc_q;/* pending I/O requests */
249 	int sc_active;		/* number of active I/O operations */
250 	uint8_t *sc_copybuf;	/* for secsize >=3 */
251 	uint8_t sc_part;	/* for secsize >=3 */
252 #define	SEC_P10	0x02		/* first part */
253 #define	SEC_P01	0x01		/* second part */
254 #define	SEC_P11	0x03		/* both part */
255 
256 	krndsource_t	rnd_source;
257 };
258 
259 /* floppy driver configuration */
260 static int fdprobe(device_t, cfdata_t, void *);
261 static void fdattach(device_t, device_t, void *);
262 
263 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
264     fdprobe, fdattach, NULL, NULL);
265 
266 static dev_type_open(fdopen);
267 static dev_type_close(fdclose);
268 static dev_type_read(fdread);
269 static dev_type_write(fdwrite);
270 static dev_type_ioctl(fdioctl);
271 static dev_type_strategy(fdstrategy);
272 
273 const struct bdevsw fd_bdevsw = {
274 	.d_open = fdopen,
275 	.d_close = fdclose,
276 	.d_strategy = fdstrategy,
277 	.d_ioctl = fdioctl,
278 	.d_dump = nodump,
279 	.d_psize = nosize,
280 	.d_discard = nodiscard,
281 	.d_flag = D_DISK
282 };
283 
284 const struct cdevsw fd_cdevsw = {
285 	.d_open = fdopen,
286 	.d_close = fdclose,
287 	.d_read = fdread,
288 	.d_write = fdwrite,
289 	.d_ioctl = fdioctl,
290 	.d_stop = nostop,
291 	.d_tty = notty,
292 	.d_poll = nopoll,
293 	.d_mmap = nommap,
294 	.d_kqfilter = nokqfilter,
295 	.d_discard = nodiscard,
296 	.d_flag = D_DISK
297 };
298 
299 static void fdstart(struct fd_softc *);
300 
301 struct dkdriver fddkdriver = {
302 	.d_strategy = fdstrategy
303 };
304 
305 static void fd_set_motor(struct fdc_softc *, int);
306 static void fd_motor_off(void *);
307 #if 0
308 static void fd_motor_on(void *);
309 #endif
310 static int fdcresult(struct fdc_softc *);
311 static int out_fdc(bus_space_tag_t, bus_space_handle_t, uint8_t);
312 static void fdcstart(struct fdc_softc *);
313 static void fdcstatus(device_t, int, const char *);
314 static void fdctimeout(void *);
315 #if 0
316 static void fdcpseudointr(void *);
317 #endif
318 static void fdcretry(struct fdc_softc *);
319 static void fdfinish(struct fd_softc *, struct buf *);
320 static struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
321 static int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *);
322 static int fdcpoll(struct fdc_softc *);
323 static int fdgetdisklabel(struct fd_softc *, dev_t);
324 static void fd_do_eject(struct fdc_softc *, int);
325 
326 static void fd_mountroot_hook(device_t);
327 
328 /* DMA transfer routines */
329 inline static void fdc_dmastart(struct fdc_softc *, int, void *, vsize_t);
330 inline static void fdc_dmaabort(struct fdc_softc *);
331 static int fdcdmaintr(void *);
332 static int fdcdmaerrintr(void *);
333 
334 inline static void
fdc_dmastart(struct fdc_softc * fdc,int read,void * addr,vsize_t count)335 fdc_dmastart(struct fdc_softc *fdc, int read, void *addr, vsize_t count)
336 {
337 	int error;
338 
339 	DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
340 	    read ? "read" : "write", (void *)addr, count));
341 
342 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
343 	    0, BUS_DMA_NOWAIT);
344 	if (error) {
345 		panic("fdc_dmastart: cannot load dmamap");
346 	}
347 
348 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
349 	    read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
350 
351 	/*
352 	 * Note 1:
353 	 *  uPD72065 ignores A0 input (connected to x68k bus A1)
354 	 *  during DMA xfer access, but it's better to explicitly
355 	 *  specify FDC data register address for clarification.
356 	 * Note 2:
357 	 *  FDC is connected to LSB 8 bits of X68000 16 bit bus
358 	 *  (as BUS_SPACE_MAP_SHIFTED_ODD defined in bus.h)
359 	 *  so each FDC register is mapped at sparse odd address.
360 	 *
361 	 * XXX: No proper API to get DMA address of FDC register for DMAC.
362 	 */
363 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
364 	    fdc->sc_dmamap,
365 	    read ? DMAC_OCR_DIR_DTM : DMAC_OCR_DIR_MTD,
366 	    DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT,
367 	    fdc->sc_addr + fddata * 2 + 1);
368 
369 	fdc->sc_read = read;
370 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
371 }
372 
373 inline static void
fdc_dmaabort(struct fdc_softc * fdc)374 fdc_dmaabort(struct fdc_softc *fdc)
375 {
376 
377 	dmac_abort_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
378 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
379 }
380 
381 static int
fdcdmaintr(void * arg)382 fdcdmaintr(void *arg)
383 {
384 	struct fdc_softc *fdc = arg;
385 
386 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap,
387 	    0, fdc->sc_dmamap->dm_mapsize,
388 	    fdc->sc_read ?
389 	    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
390 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
391 
392 	return 0;
393 }
394 
395 static int
fdcdmaerrintr(void * dummy)396 fdcdmaerrintr(void *dummy)
397 {
398 
399 	DPRINTF(("fdcdmaerrintr\n"));
400 
401 	return 0;
402 }
403 
404 /* ARGSUSED */
405 static int
fdcprobe(device_t parent,cfdata_t cf,void * aux)406 fdcprobe(device_t parent, cfdata_t cf, void *aux)
407 {
408 	struct intio_attach_args *ia = aux;
409 
410 	if (strcmp(ia->ia_name, "fdc") != 0)
411 		return 0;
412 
413 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
414 		ia->ia_addr = FDC_ADDR;
415 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
416 		ia->ia_intr = FDC_INTR;
417 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
418 		ia->ia_dma = FDC_DMA;
419 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
420 		ia->ia_dmaintr = FDC_DMAINTR;
421 
422 	if ((ia->ia_intr & 0x03) != 0)
423 		return 0;
424 
425 	ia->ia_size = FDC_MAPSIZE;
426 	if (intio_map_allocate_region(parent, ia, INTIO_MAP_TESTONLY))
427 		return 0;
428 
429 	/* builtin device; always there */
430 	return 1;
431 }
432 
433 /*
434  * Arguments passed between fdcattach and fdprobe.
435  */
436 struct fdc_attach_args {
437 	int fa_drive;
438 	struct fd_type *fa_deftype;
439 };
440 
441 /*
442  * Print the location of a disk drive (called just before attaching the
443  * the drive).  If `fdc' is not NULL, the drive was found but was not
444  * in the system config file; print the drive name as well.
445  * Return QUIET (config_find ignores this if the device was configured) to
446  * avoid printing `fdN not configured' messages.
447  */
448 static int
fdprint(void * aux,const char * fdc)449 fdprint(void *aux, const char *fdc)
450 {
451 	struct fdc_attach_args *fa = aux;
452 
453 	if (fdc == NULL)
454 		aprint_normal(" drive %d", fa->fa_drive);
455 	return QUIET;
456 }
457 
458 static void
fdcattach(device_t parent,device_t self,void * aux)459 fdcattach(device_t parent, device_t self, void *aux)
460 {
461 	struct fdc_softc *fdc = device_private(self);
462 	bus_space_tag_t iot;
463 	bus_space_handle_t ioh;
464 	struct intio_attach_args *ia = aux;
465 	struct fdc_attach_args fa;
466 
467 	iot = ia->ia_bst;
468 
469 	aprint_normal("\n");
470 
471 	/* Re-map the I/O space. */
472 	if (bus_space_map(iot, ia->ia_addr, ia->ia_size,
473 	    BUS_SPACE_MAP_SHIFTED_ODD, &ioh) != 0) {
474 		aprint_error_dev(self, "unable to map I/O space\n");
475 		return;
476 	}
477 
478 	callout_init(&fdc->sc_timo_ch, 0);
479 	callout_init(&fdc->sc_intr_ch, 0);
480 
481 	fdc->sc_iot = iot;
482 	fdc->sc_ioh = ioh;
483 	fdc->sc_addr = (void *)ia->ia_addr;
484 
485 	fdc->sc_dmat = ia->ia_dmat;
486 	fdc->sc_state = DEVIDLE;
487 	TAILQ_INIT(&fdc->sc_drives);
488 
489 	/* Initialize DMAC channel */
490 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
491 	    ia->ia_dmaintr, fdcdmaintr, fdc,
492 	    ia->ia_dmaintr + 1, fdcdmaerrintr, fdc,
493 	    (DMAC_DCR_XRM_CSWH | DMAC_DCR_OTYP_EASYNC | DMAC_DCR_OPS_8BIT),
494 	    (DMAC_OCR_SIZE_BYTE | DMAC_OCR_REQG_EXTERNAL));
495 
496 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
497 	    0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &fdc->sc_dmamap)) {
498 		aprint_error_dev(self, "can't set up intio DMA map\n");
499 		return;
500 	}
501 
502 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc) != 0)
503 		panic("Could not establish interrupt (duplicated vector?).");
504 	intio_set_ivec(ia->ia_intr);
505 
506 	/* reset */
507 	intio_disable_intr(SICILIAN_INTR_FDD);
508 	intio_enable_intr(SICILIAN_INTR_FDC);
509 	fdcresult(fdc);
510 	fdcreset(fdc);
511 
512 	aprint_normal_dev(self, "uPD72065 FDC\n");
513 	out_fdc(iot, ioh, NE7CMD_SPECIFY);	/* specify command */
514 	out_fdc(iot, ioh, 0xd0);
515 	out_fdc(iot, ioh, 0x10);
516 
517 	/* physical limit: four drives per controller. */
518 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
519 		(void)config_found(self, (void *)&fa, fdprint, CFARGS_NONE);
520 	}
521 
522 	intio_enable_intr(SICILIAN_INTR_FDC);
523 }
524 
525 static void
fdcreset(struct fdc_softc * fdc)526 fdcreset(struct fdc_softc *fdc)
527 {
528 
529 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
530 }
531 
532 static int
fdcpoll(struct fdc_softc * fdc)533 fdcpoll(struct fdc_softc *fdc)
534 {
535 	int i = 25000;
536 
537 	while (--i > 0) {
538 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC) != 0) {
539 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
540 			fdcresult(fdc);
541 			break;
542 		}
543 		DELAY(100);
544 	}
545 	return i;
546 }
547 
548 static int
fdprobe(device_t parent,cfdata_t cf,void * aux)549 fdprobe(device_t parent, cfdata_t cf, void *aux)
550 {
551 	struct fdc_softc *fdc = device_private(parent);
552 	struct fd_type *type;
553 	struct fdc_attach_args *fa = aux;
554 	int drive = fa->fa_drive;
555 	bus_space_tag_t iot = fdc->sc_iot;
556 	bus_space_handle_t ioh = fdc->sc_ioh;
557 	int n = 0;
558 	int found = 0;
559 	int i;
560 
561 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
562 	    cf->cf_loc[FDCCF_UNIT] != drive)
563 		return 0;
564 
565 	type = &fd_types[0];	/* XXX 1.2MB */
566 
567 	/* toss any interrupt status */
568 	for (n = 0; n < 4; n++) {
569 		out_fdc(iot, ioh, NE7CMD_SENSEI);
570 		(void)fdcresult(fdc);
571 	}
572 	intio_disable_intr(SICILIAN_INTR_FDC);
573 
574 	/* select drive and turn on motor */
575 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
576 	fdc_force_ready(FDCRDY);
577 	fdcpoll(fdc);
578 
579  retry:
580 	out_fdc(iot, ioh, NE7CMD_RECAL);
581 	out_fdc(iot, ioh, drive);
582 
583 	i = 25000;
584 	while (--i > 0) {
585 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC) != 0) {
586 			out_fdc(iot, ioh, NE7CMD_SENSEI);
587 			n = fdcresult(fdc);
588 			break;
589 		}
590 		DELAY(100);
591 	}
592 
593 #ifdef FDDEBUG
594 	{
595 		int _i;
596 		DPRINTF(("fdprobe: status"));
597 		for (_i = 0; _i < n; _i++)
598 			DPRINTF((" %x", fdc->sc_status[_i]));
599 		DPRINTF(("\n"));
600 	}
601 #endif
602 
603 	if (n == 2) {
604 		if ((fdc->sc_status[0] & 0xf0) == 0x20)
605 			found = 1;
606 		else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
607 			goto retry;
608 	}
609 
610 	/* turn off motor */
611 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
612 	    fdctl, (type->rate << 4) | drive);
613 	fdc_force_ready(FDCSTBY);
614 	if (!found) {
615 		intio_enable_intr(SICILIAN_INTR_FDC);
616 		return 0;
617 	}
618 
619 	return 1;
620 }
621 
622 /*
623  * Controller is working, and drive responded.  Attach it.
624  */
625 static void
fdattach(device_t parent,device_t self,void * aux)626 fdattach(device_t parent, device_t self, void *aux)
627 {
628 	struct fdc_softc *fdc = device_private(parent);
629 	struct fd_softc *fd = device_private(self);
630 	struct fdc_attach_args *fa = aux;
631 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
632 	int drive = fa->fa_drive;
633 
634 #if 0
635 	callout_init(&fd->sc_motoron_ch, 0);
636 #endif
637 	callout_init(&fd->sc_motoroff_ch, 0);
638 
639 	fd->sc_dev = self;
640 	fd->sc_flags = 0;
641 
642 	if (type)
643 		aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
644 		    type->cyls, type->heads, type->sectrac);
645 	else
646 		aprint_normal(": density unknown\n");
647 
648 	bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
649 	fd->sc_cylin = -1;
650 	fd->sc_drive = drive;
651 	fd->sc_deftype = type;
652 	fdc->sc_fd[drive] = fd;
653 
654 	fd->sc_copybuf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
655 	if (fd->sc_copybuf == 0)
656 		aprint_error("%s: WARNING!! malloc() failed.\n", __func__);
657 	fd->sc_flags |= FD_ALIVE;
658 
659 	/*
660 	 * Initialize and attach the disk structure.
661 	 */
662 	disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
663 	disk_attach(&fd->sc_dk);
664 
665 	/*
666 	 * Establish a mountroot_hook anyway in case we booted
667 	 * with RB_ASKNAME and get selected as the boot device.
668 	 */
669 	mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
670 
671 	rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
672 	    RND_TYPE_DISK, RND_FLAG_DEFAULT);
673 }
674 
675 static struct fd_type *
fd_dev_to_type(struct fd_softc * fd,dev_t dev)676 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
677 {
678 	size_t type = FDTYPE(dev);
679 
680 	if (type >= __arraycount(fd_types))
681 		return NULL;
682 	return &fd_types[type];
683 }
684 
685 static void
fdstrategy(struct buf * bp)686 fdstrategy(struct buf *bp)
687 {
688 	struct fd_softc *fd;
689 	int unit;
690 	int sz;
691 	int s;
692 
693 	unit = FDUNIT(bp->b_dev);
694 	fd = device_lookup_private(&fd_cd, unit);
695 	if (fd == NULL) {
696 		bp->b_error = EINVAL;
697 		goto done;
698 	}
699 
700 	if (bp->b_blkno < 0 ||
701 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
702 	     (bp->b_flags & B_FORMAT) == 0)) {
703 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
704 		    "bcount=%d\n", unit,
705 		    bp->b_blkno, bp->b_bcount));
706 		bp->b_error = EINVAL;
707 		goto done;
708 	}
709 
710 	/* If it's a null transfer, return immediately. */
711 	if (bp->b_bcount == 0)
712 		goto done;
713 
714 	sz = howmany(bp->b_bcount, FDC_BSIZE);
715 
716 	if (bp->b_blkno + sz >
717 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
718 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
719 		     - bp->b_blkno;
720 		if (sz == 0) {
721 			/* If exactly at end of disk, return EOF. */
722 			bp->b_resid = bp->b_bcount;
723 			goto done;
724 		}
725 		if (sz < 0) {
726 			/* If past end of disk, return EINVAL. */
727 			bp->b_error = EINVAL;
728 			goto done;
729 		}
730 		/* Otherwise, truncate request. */
731 		bp->b_bcount = sz << DEV_BSHIFT;
732 	}
733 
734 	bp->b_rawblkno = bp->b_blkno;
735 	bp->b_cylinder = (bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)) /
736 	    (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
737 
738 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
739 	    bp->b_flags & B_READ ? "read" : "write",
740 	    bp->b_blkno, bp->b_bcount, bp->b_cylinder));
741 	/* Queue transfer on drive, activate drive and controller if idle. */
742 	s = splbio();
743 	bufq_put(fd->sc_q, bp);
744 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
745 	if (fd->sc_active == 0)
746 		fdstart(fd);
747 #ifdef DIAGNOSTIC
748 	else {
749 		struct fdc_softc *fdc;
750 
751 		fdc = device_private(device_parent(fd->sc_dev));
752 		if (fdc->sc_state == DEVIDLE) {
753 			printf("fdstrategy: controller inactive\n");
754 			fdcstart(fdc);
755 		}
756 	}
757 #endif
758 	splx(s);
759 	return;
760 
761  done:
762 	/* Toss transfer; we're done early. */
763 	biodone(bp);
764 }
765 
766 static void
fdstart(struct fd_softc * fd)767 fdstart(struct fd_softc *fd)
768 {
769 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
770 	int active = !TAILQ_EMPTY(&fdc->sc_drives);
771 
772 	/* Link into controller queue. */
773 	fd->sc_active = 1;
774 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
775 
776 	/* If controller not already active, start it. */
777 	if (!active)
778 		fdcstart(fdc);
779 }
780 
781 static void
fdfinish(struct fd_softc * fd,struct buf * bp)782 fdfinish(struct fd_softc *fd, struct buf *bp)
783 {
784 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
785 
786 	/*
787 	 * Move this drive to the end of the queue to give others a `fair'
788 	 * chance.  We only force a switch if N operations are completed while
789 	 * another drive is waiting to be serviced, since there is a long motor
790 	 * startup delay whenever we switch.
791 	 */
792 	(void)bufq_get(fd->sc_q);
793 	if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
794 		fd->sc_ops = 0;
795 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
796 		if (bufq_peek(fd->sc_q) != NULL)
797 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
798 		else
799 			fd->sc_active = 0;
800 	}
801 	bp->b_resid = fd->sc_bcount;
802 	fd->sc_skip = 0;
803 
804 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
805 
806 	biodone(bp);
807 	/* turn off motor 5s from now */
808 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
809 	fdc->sc_state = DEVIDLE;
810 }
811 
812 static int
fdread(dev_t dev,struct uio * uio,int flags)813 fdread(dev_t dev, struct uio *uio, int flags)
814 {
815 
816 	return physio(fdstrategy, NULL, dev, B_READ, minphys, uio);
817 }
818 
819 static int
fdwrite(dev_t dev,struct uio * uio,int flags)820 fdwrite(dev_t dev, struct uio *uio, int flags)
821 {
822 
823 	return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio);
824 }
825 
826 static void
fd_set_motor(struct fdc_softc * fdc,int reset)827 fd_set_motor(struct fdc_softc *fdc, int reset)
828 {
829 	struct fd_softc *fd;
830 	int n;
831 
832 	DPRINTF(("fd_set_motor:\n"));
833 	for (n = 0; n < 4; n++) {
834 		fd = fdc->sc_fd[n];
835 		if (fd != NULL && (fd->sc_flags & FD_MOTOR) != 0)
836 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
837 			    0x80 | (fd->sc_type->rate << 4)| n);
838 	}
839 }
840 
841 static void
fd_motor_off(void * arg)842 fd_motor_off(void *arg)
843 {
844 	struct fd_softc *fd = arg;
845 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
846 	int s;
847 
848 	DPRINTF(("fd_motor_off:\n"));
849 
850 	s = splbio();
851 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
852 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
853 	    (fd->sc_type->rate << 4) | fd->sc_drive);
854 #if 0
855 	fd_set_motor(fdc, 0); /* XXX */
856 #endif
857 	splx(s);
858 }
859 
860 #if 0 /* on x68k motor on triggers interrupts by state change of ready line. */
861 static void
862 fd_motor_on(void *arg)
863 {
864 	struct fd_softc *fd = arg;
865 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
866 	int s;
867 
868 	DPRINTF(("fd_motor_on:\n"));
869 
870 	s = splbio();
871 	fd->sc_flags &= ~FD_MOTOR_WAIT;
872 	if ((TAILQ_FIRST(&fdc->sc_drives) == fd) &&
873 	    (fdc->sc_state == MOTORWAIT))
874 		(void)fdcintr(fdc);
875 	splx(s);
876 }
877 #endif
878 
879 static int
fdcresult(struct fdc_softc * fdc)880 fdcresult(struct fdc_softc *fdc)
881 {
882 	bus_space_tag_t iot = fdc->sc_iot;
883 	bus_space_handle_t ioh = fdc->sc_ioh;
884 	uint8_t i;
885 	int j, n;
886 
887 	n = 0;
888 	for (j = 100000; j != 0; j--) {
889 		i = bus_space_read_1(iot, ioh, fdsts) &
890 		  (NE7_DIO | NE7_RQM | NE7_CB);
891 
892 		if (i == NE7_RQM)
893 			return n;
894 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
895 			if (n >= sizeof(fdc->sc_status)) {
896 				log(LOG_ERR, "fdcresult: overrun\n");
897 				return -1;
898 			}
899 			fdc->sc_status[n++] =
900 			    bus_space_read_1(iot, ioh, fddata);
901 		}
902 		delay(10);
903 	}
904 	log(LOG_ERR, "fdcresult: timeout\n");
905 	return -1;
906 }
907 
908 static int
out_fdc(bus_space_tag_t iot,bus_space_handle_t ioh,uint8_t x)909 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t x)
910 {
911 	int i = 100000;
912 
913 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
914 	if (i <= 0)
915 		return -1;
916 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
917 	if (i <= 0)
918 		return -1;
919 	bus_space_write_1(iot, ioh, fddata, x);
920 	return 0;
921 }
922 
923 static int
fdopen(dev_t dev,int flags,int mode,struct lwp * l)924 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
925 {
926 	int unit;
927 	struct fd_softc *fd;
928 	struct fd_type *type;
929 	struct fdc_softc *fdc;
930 
931 	unit = FDUNIT(dev);
932 	fd = device_lookup_private(&fd_cd, unit);
933 	if (fd == NULL)
934 		return ENXIO;
935 	type = fd_dev_to_type(fd, dev);
936 	if (type == NULL)
937 		return ENXIO;
938 
939 	if ((fd->sc_flags & FD_OPEN) != 0 &&
940 	    fd->sc_type != type)
941 		return EBUSY;
942 
943 	fdc = device_private(device_parent(fd->sc_dev));
944 	if ((fd->sc_flags & FD_OPEN) == 0) {
945 		/* Lock eject button */
946 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
947 		    0x40 | (1 << unit));
948 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
949 	}
950 
951 	fd->sc_type = type;
952 	fd->sc_cylin = -1;
953 
954 	switch (mode) {
955 	case S_IFCHR:
956 		fd->sc_flags |= FD_COPEN;
957 		break;
958 	case S_IFBLK:
959 		fd->sc_flags |= FD_BOPEN;
960 		break;
961 	}
962 
963 	fdgetdisklabel(fd, dev);
964 
965 	return 0;
966 }
967 
968 static int
fdclose(dev_t dev,int flags,int mode,struct lwp * l)969 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
970 {
971 	int unit = FDUNIT(dev);
972 	struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
973 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
974 
975 	DPRINTF(("fdclose %d\n", unit));
976 
977 	switch (mode) {
978 	case S_IFCHR:
979 		fd->sc_flags &= ~FD_COPEN;
980 		break;
981 	case S_IFBLK:
982 		fd->sc_flags &= ~FD_BOPEN;
983 		break;
984 	}
985 
986 	/* clear flags */
987 	fd->sc_opts &= ~(FDOPT_NORETRY | FDOPT_SILENT);
988 
989 	if ((fd->sc_flags & FD_OPEN) == 0) {
990 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
991 		    (1 << unit));
992 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
993 	}
994 	return 0;
995 }
996 
997 static void
fdcstart(struct fdc_softc * fdc)998 fdcstart(struct fdc_softc *fdc)
999 {
1000 
1001 #ifdef DIAGNOSTIC
1002 	/*
1003 	 * only got here if controller's drive queue was inactive; should
1004 	 * be in idle state
1005 	 */
1006 	if (fdc->sc_state != DEVIDLE) {
1007 		printf("fdcstart: not idle\n");
1008 		return;
1009 	}
1010 #endif
1011 	(void)fdcintr(fdc);
1012 }
1013 
1014 
1015 static void
fdcpstatus(int n,struct fdc_softc * fdc)1016 fdcpstatus(int n, struct fdc_softc *fdc)
1017 {
1018 	char bits[64];
1019 
1020 	switch (n) {
1021 	case 0:
1022 		printf("\n");
1023 		break;
1024 	case 2:
1025 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
1026 		printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
1027 		break;
1028 	case 7:
1029 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
1030 		printf(" (st0 %s", bits);
1031 		snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
1032 		printf(" st1 %s", bits);
1033 		snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
1034 		printf(" st2 %s", bits);
1035 		printf(" cyl %d head %d sec %d)\n",
1036 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1037 		break;
1038 #ifdef DIAGNOSTIC
1039 	default:
1040 		printf("\nfdcstatus: weird size");
1041 		break;
1042 #endif
1043 	}
1044 }
1045 
1046 static void
fdcstatus(device_t dv,int n,const char * s)1047 fdcstatus(device_t dv, int n, const char *s)
1048 {
1049 	struct fdc_softc *fdc = device_private(device_parent(dv));
1050 
1051 	if (n == 0) {
1052 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
1053 		(void)fdcresult(fdc);
1054 		n = 2;
1055 	}
1056 
1057 	printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state);
1058 	fdcpstatus(n, fdc);
1059 }
1060 
1061 static void
fdctimeout(void * arg)1062 fdctimeout(void *arg)
1063 {
1064 	struct fdc_softc *fdc = arg;
1065 	struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
1066 	int s;
1067 
1068 	s = splbio();
1069 	fdcstatus(fd->sc_dev, 0, "timeout");
1070 
1071 	if (bufq_peek(fd->sc_q) != NULL)
1072 		fdc->sc_state++;
1073 	else
1074 		fdc->sc_state = DEVIDLE;
1075 
1076 	(void)fdcintr(fdc);
1077 	splx(s);
1078 }
1079 
1080 #if 0
1081 static void
1082 fdcpseudointr(void *arg)
1083 {
1084 	int s;
1085 	struct fdc_softc *fdc = arg;
1086 
1087 	/* just ensure it has the right spl */
1088 	s = splbio();
1089 	(void)fdcintr(fdc);
1090 	splx(s);
1091 }
1092 #endif
1093 
1094 static int
fdcintr(void * arg)1095 fdcintr(void *arg)
1096 {
1097 	struct fdc_softc *fdc = arg;
1098 #define	st0	fdc->sc_status[0]
1099 #define	cyl	fdc->sc_status[1]
1100 	struct fd_softc *fd;
1101 	struct buf *bp;
1102 	bus_space_tag_t iot = fdc->sc_iot;
1103 	bus_space_handle_t ioh = fdc->sc_ioh;
1104 	int read, head, sec, pos, i, sectrac, nblks;
1105 	int tmp;
1106 	struct fd_type *type;
1107 	struct ne7_fd_formb *finfo = NULL;
1108 
1109  loop:
1110 	fd = TAILQ_FIRST(&fdc->sc_drives);
1111 	if (fd == NULL) {
1112 		DPRINTF(("fdcintr: set DEVIDLE\n"));
1113 		if (fdc->sc_state == DEVIDLE) {
1114 			if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)
1115 			    != 0) {
1116 				out_fdc(iot, ioh, NE7CMD_SENSEI);
1117 				if ((tmp = fdcresult(fdc)) != 2 ||
1118 				    (st0 & 0xf8) != 0x20) {
1119 					goto loop;
1120 				}
1121 			}
1122 		}
1123 		/* no drives waiting; end */
1124 		fdc->sc_state = DEVIDLE;
1125 		return 1;
1126 	}
1127 
1128 	/* Is there a transfer to this drive?  If not, deactivate drive. */
1129 	bp = bufq_peek(fd->sc_q);
1130 	if (bp == NULL) {
1131 		fd->sc_ops = 0;
1132 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1133 		fd->sc_active = 0;
1134 		goto loop;
1135 	}
1136 
1137 	if (bp->b_flags & B_FORMAT)
1138 		finfo = (struct ne7_fd_formb *)bp->b_data;
1139 
1140 	switch (fdc->sc_state) {
1141 	case DEVIDLE:
1142 		DPRINTF(("fdcintr: in DEVIDLE\n"));
1143 		fdc->sc_errors = 0;
1144 		fd->sc_skip = 0;
1145 		fd->sc_bcount = bp->b_bcount;
1146 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1147 		callout_stop(&fd->sc_motoroff_ch);
1148 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1149 			fdc->sc_state = MOTORWAIT;
1150 			return 1;
1151 		}
1152 		if ((fd->sc_flags & FD_MOTOR) == 0) {
1153 			/* Turn on the motor */
1154 			/* being careful about other drives. */
1155 			for (i = 0; i < 4; i++) {
1156 				struct fd_softc *ofd = fdc->sc_fd[i];
1157 				if (ofd != NULL &&
1158 				    (ofd->sc_flags & FD_MOTOR) != 0) {
1159 					callout_stop(&ofd->sc_motoroff_ch);
1160 					ofd->sc_flags &=
1161 					    ~(FD_MOTOR | FD_MOTOR_WAIT);
1162 					break;
1163 				}
1164 			}
1165 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1166 			fd_set_motor(fdc, 0);
1167 			fdc->sc_state = MOTORWAIT;
1168 #if 0	/* no need to callout on x68k; motor on will trigger interrupts */
1169 			/* allow .5s for motor to stabilize */
1170 			callout_reset(&fd->sc_motoron_ch, hz / 2,
1171 			    fd_motor_on, fd);
1172 #endif
1173 			return 1;
1174 		}
1175 		/* Make sure the right drive is selected. */
1176 		fd_set_motor(fdc, 0);
1177 
1178 		/* fall through */
1179 	case DOSEEK:
1180 	doseek:
1181 		DPRINTF(("fdcintr: in DOSEEK\n"));
1182 		if (fd->sc_cylin == bp->b_cylinder)
1183 			goto doio;
1184 
1185 		out_fdc(iot, ioh, NE7CMD_SPECIFY);	/* specify command */
1186 		out_fdc(iot, ioh, 0xd0);		/* XXX const */
1187 		out_fdc(iot, ioh, 0x10);
1188 
1189 		out_fdc(iot, ioh, NE7CMD_SEEK);		/* seek function */
1190 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
1191 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1192 
1193 		fd->sc_cylin = -1;
1194 		fdc->sc_state = SEEKWAIT;
1195 
1196 		iostat_seek(fd->sc_dk.dk_stats);
1197 		disk_busy(&fd->sc_dk);
1198 
1199 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1200 		return 1;
1201 
1202 	case DOIO:
1203 	doio:
1204 		DPRINTF(("fdcintr: DOIO: "));
1205 		type = fd->sc_type;
1206 		if (finfo != NULL)
1207 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1208 			    (char *)finfo;
1209 		sectrac = type->sectrac;
1210 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1211 		sec = pos / (1 << (type->secsize - 2));
1212 		if (finfo != NULL || type->secsize == 2) {
1213 			fd->sc_part = SEC_P11;
1214 			nblks = (sectrac - sec) << (type->secsize - 2);
1215 			nblks = uimin(nblks, fd->sc_bcount / FDC_BSIZE);
1216 			DPRINTF(("nblks(0)"));
1217 		} else if ((fd->sc_blkno % 2) == 0) {
1218 			if (fd->sc_bcount & 0x00000200) {
1219 				if (fd->sc_bcount == FDC_BSIZE) {
1220 					fd->sc_part = SEC_P10;
1221 					nblks = 1;
1222 					DPRINTF(("nblks(1)"));
1223 				} else {
1224 					fd->sc_part = SEC_P11;
1225 					nblks = (sectrac - sec) * 2;
1226 					nblks = uimin(nblks,
1227 					    fd->sc_bcount / FDC_BSIZE - 1);
1228 					DPRINTF(("nblks(2)"));
1229 				}
1230 			} else {
1231 				fd->sc_part = SEC_P11;
1232 				nblks = (sectrac - sec) << (type->secsize - 2);
1233 				nblks = uimin(nblks, fd->sc_bcount / FDC_BSIZE);
1234 				DPRINTF(("nblks(3)"));
1235 			}
1236 		} else {
1237 			fd->sc_part = SEC_P01;
1238 			nblks = 1;
1239 			DPRINTF(("nblks(4)"));
1240 		}
1241 		nblks = uimin(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1242 		DPRINTF((" %d\n", nblks));
1243 		fd->sc_nblks = nblks;
1244 		fd->sc_nbytes =
1245 		    (finfo != NULL) ? bp->b_bcount : nblks * FDC_BSIZE;
1246 		head = (fd->sc_blkno
1247 		    % (type->seccyl * (1 << (type->secsize - 2))))
1248 		    / (type->sectrac * (1 << (type->secsize - 2)));
1249 
1250 #ifdef DIAGNOSTIC
1251 		{
1252 			int block;
1253 			block = ((fd->sc_cylin * type->heads + head) *
1254 			    type->sectrac + sec) * (1 << (type->secsize - 2));
1255 			block += (fd->sc_part == SEC_P01) ? 1 : 0;
1256 			if (block != fd->sc_blkno) {
1257 				printf("C H R N: %d %d %d %d\n",
1258 				    fd->sc_cylin, head, sec, type->secsize);
1259 				printf("fdcintr: doio: block %d != blkno %"
1260 				    PRId64 "\n",
1261 				    block, fd->sc_blkno);
1262 #ifdef DDB
1263 				Debugger();
1264 #endif
1265 			}
1266 		}
1267 #endif
1268 		read = bp->b_flags & B_READ;
1269 		DPRINTF(("fdcintr: %s drive %d track %d "
1270 		    "head %d sec %d nblks %d, skip %d\n",
1271 		    read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1272 		    head, sec, nblks, fd->sc_skip));
1273 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1274 		    type->secsize));
1275 
1276 		if (finfo == NULL && fd->sc_part != SEC_P11)
1277 			goto docopy;
1278 
1279 		fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
1280 		    fd->sc_nbytes);
1281 		if (finfo != NULL) {
1282 			/* formatting */
1283 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1284 				fdc->sc_errors = 4;
1285 				fdcretry(fdc);
1286 				goto loop;
1287 			}
1288 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1289 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
1290 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1291 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1292 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1293 		} else {
1294 			if (read)
1295 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
1296 			else
1297 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1298 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1299 			out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1300 			out_fdc(iot, ioh, head);
1301 			out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1302 			out_fdc(iot, ioh, type->secsize); /* sector size */
1303 			out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1304 			out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1305 			out_fdc(iot, ioh, type->datalen); /* data length */
1306 		}
1307 		fdc->sc_state = IOCOMPLETE;
1308 
1309 		disk_busy(&fd->sc_dk);
1310 
1311 		/* allow 2 seconds for operation */
1312 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1313 		return 1;				/* will return later */
1314 
1315 	case DOCOPY:
1316 	docopy:
1317 		DPRINTF(("fdcintr: DOCOPY:\n"));
1318 		type = fd->sc_type;
1319 		head = (fd->sc_blkno
1320 		    % (type->seccyl * (1 << (type->secsize - 2))))
1321 		    / (type->sectrac * (1 << (type->secsize - 2)));
1322 		pos = fd->sc_blkno %
1323 		    (type->sectrac * (1 << (type->secsize - 2)));
1324 		sec = pos / (1 << (type->secsize - 2));
1325 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1326 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
1327 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1328 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1329 		out_fdc(iot, ioh, head);
1330 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1331 		out_fdc(iot, ioh, type->secsize);	/* sector size */
1332 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
1333 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
1334 		out_fdc(iot, ioh, type->datalen);	/* data length */
1335 		fdc->sc_state = COPYCOMPLETE;
1336 		/* allow 2 seconds for operation */
1337 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1338 		return 1;				/* will return later */
1339 
1340 	case DOIOHALF:
1341 	doiohalf:
1342 		DPRINTF((" DOIOHALF:\n"));
1343 
1344 		type = fd->sc_type;
1345 		sectrac = type->sectrac;
1346 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1347 		sec = pos / (1 << (type->secsize - 2));
1348 		head = (fd->sc_blkno
1349 		    % (type->seccyl * (1 << (type->secsize - 2))))
1350 		    / (type->sectrac * (1 << (type->secsize - 2)));
1351 #ifdef DIAGNOSTIC
1352 		{
1353 			int block;
1354 			block = ((fd->sc_cylin * type->heads + head) *
1355 			    type->sectrac + sec) * (1 << (type->secsize - 2));
1356 			block += (fd->sc_part == SEC_P01) ? 1 : 0;
1357 			if (block != fd->sc_blkno) {
1358 				printf("fdcintr: block %d != blkno %" PRId64
1359 				    "\n",
1360 				    block, fd->sc_blkno);
1361 #ifdef DDB
1362 				Debugger();
1363 #endif
1364 			}
1365 		}
1366 #endif
1367 		if ((read = bp->b_flags & B_READ)) {
1368 			memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
1369 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1370 			    FDC_BSIZE);
1371 			fdc->sc_state = IOCOMPLETE;
1372 			goto iocomplete2;
1373 		} else {
1374 			memcpy((char *)fd->sc_copybuf
1375 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1376 			    (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
1377 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1378 		}
1379 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
1380 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1381 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
1382 		out_fdc(iot, ioh, head);
1383 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
1384 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1385 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
1386 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
1387 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1388 		fdc->sc_state = IOCOMPLETE;
1389 		/* allow 2 seconds for operation */
1390 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1391 		return 1;				/* will return later */
1392 
1393 	case SEEKWAIT:
1394 		callout_stop(&fdc->sc_timo_ch);
1395 		fdc->sc_state = SEEKCOMPLETE;
1396 		/* allow 1/50 second for heads to settle */
1397 #if 0
1398 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1399 #endif
1400 		return 1;
1401 
1402 	case SEEKCOMPLETE:
1403 		/* Make sure seek really happened */
1404 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1405 		    bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1406 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1407 		tmp = fdcresult(fdc);
1408 		if ((st0 & 0xf8) == 0xc0) {
1409 			DPRINTF(("fdcintr: first seek!\n"));
1410 			fdc->sc_state = DORECAL;
1411 			goto loop;
1412 		} else if (tmp != 2 ||
1413 		    (st0 & 0xf8) != 0x20 ||
1414 		    cyl != bp->b_cylinder) {
1415 #ifdef FDDEBUG
1416 			fdcstatus(fd->sc_dev, 2, "seek failed");
1417 #endif
1418 			fdcretry(fdc);
1419 			goto loop;
1420 		}
1421 		fd->sc_cylin = bp->b_cylinder;
1422 		goto doio;
1423 
1424 	case IOTIMEDOUT:
1425 		fdc_dmaabort(fdc);
1426 	case SEEKTIMEDOUT:
1427 	case RECALTIMEDOUT:
1428 	case RESETTIMEDOUT:
1429 		fdcretry(fdc);
1430 		goto loop;
1431 
1432 	case IOCOMPLETE: /* IO DONE, post-analyze */
1433 		callout_stop(&fdc->sc_timo_ch);
1434 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1435 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1436 			fdc_dmaabort(fdc);
1437 			fdcstatus(fd->sc_dev, tmp, bp->b_flags & B_READ ?
1438 			    "read failed" : "write failed");
1439 			printf("blkno %" PRId64 " nblks %d\n",
1440 			    fd->sc_blkno, fd->sc_nblks);
1441 			fdcretry(fdc);
1442 			goto loop;
1443 		}
1444 	iocomplete2:
1445 		if (fdc->sc_errors) {
1446 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1447 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1448 			printf("\n");
1449 			fdc->sc_errors = 0;
1450 		}
1451 		fd->sc_blkno += fd->sc_nblks;
1452 		fd->sc_skip += fd->sc_nbytes;
1453 		fd->sc_bcount -= fd->sc_nbytes;
1454 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1455 		if (finfo == NULL && fd->sc_bcount > 0) {
1456 			bp->b_cylinder = fd->sc_blkno
1457 			    / (fd->sc_type->seccyl
1458 			    * (1 << (fd->sc_type->secsize - 2)));
1459 			goto doseek;
1460 		}
1461 		fdfinish(fd, bp);
1462 		goto loop;
1463 
1464 	case COPYCOMPLETE: /* IO DONE, post-analyze */
1465 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
1466 		callout_stop(&fdc->sc_timo_ch);
1467 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1468 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1469 			fdc_dmaabort(fdc);
1470 			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
1471 			    "read failed" : "write failed");
1472 			printf("blkno %" PRId64 " nblks %d\n",
1473 			    fd->sc_blkno, fd->sc_nblks);
1474 			fdcretry(fdc);
1475 			goto loop;
1476 		}
1477 		goto doiohalf;
1478 
1479 	case DORESET:
1480 		DPRINTF(("fdcintr: in DORESET\n"));
1481 		/* try a reset, keep motor on */
1482 		fd_set_motor(fdc, 1);
1483 		DELAY(100);
1484 		fd_set_motor(fdc, 0);
1485 		fdc->sc_state = RESETCOMPLETE;
1486 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1487 		return 1;			/* will return later */
1488 
1489 	case RESETCOMPLETE:
1490 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1491 		callout_stop(&fdc->sc_timo_ch);
1492 		/* clear the controller output buffer */
1493 		for (i = 0; i < 4; i++) {
1494 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1495 			(void)fdcresult(fdc);
1496 		}
1497 
1498 		/* fall through */
1499 	case DORECAL:
1500 		DPRINTF(("fdcintr: in DORECAL\n"));
1501 		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1502 		out_fdc(iot, ioh, fd->sc_drive);
1503 		fdc->sc_state = RECALWAIT;
1504 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1505 		return 1;			/* will return later */
1506 
1507 	case RECALWAIT:
1508 		DPRINTF(("fdcintr: in RECALWAIT\n"));
1509 		callout_stop(&fdc->sc_timo_ch);
1510 		fdc->sc_state = RECALCOMPLETE;
1511 		/* allow 1/30 second for heads to settle */
1512 #if 0
1513 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1514 #endif
1515 		return 1;			/* will return later */
1516 
1517 	case RECALCOMPLETE:
1518 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1519 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1520 		tmp = fdcresult(fdc);
1521 		if ((st0 & 0xf8) == 0xc0) {
1522 			DPRINTF(("fdcintr: first seek!\n"));
1523 			fdc->sc_state = DORECAL;
1524 			goto loop;
1525 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1526 #ifdef FDDEBUG
1527 			fdcstatus(fd->sc_dev, 2, "recalibrate failed");
1528 #endif
1529 			fdcretry(fdc);
1530 			goto loop;
1531 		}
1532 		fd->sc_cylin = 0;
1533 		goto doseek;
1534 
1535 	case MOTORWAIT:
1536 #if 0 /* on x68k motor on triggers interrupts by state change of ready line. */
1537 		if (fd->sc_flags & FD_MOTOR_WAIT)
1538 			return 1;		/* time's not up yet */
1539 #else
1540 		/* check drive ready by state change interrupt */
1541 		KASSERT(fd->sc_flags & FD_MOTOR_WAIT);
1542 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1543 		tmp = fdcresult(fdc);
1544 		if (tmp != 2 || (st0 & 0xc0) != 0xc0 /* ready changed */) {
1545 			printf("%s: unexpected interrupt during MOTORWAIT",
1546 			    device_xname(fd->sc_dev));
1547 			fdcpstatus(7, fdc);
1548 			return 1;
1549 		}
1550 		fd->sc_flags &= ~FD_MOTOR_WAIT;
1551 #endif
1552 		goto doseek;
1553 
1554 	default:
1555 		fdcstatus(fd->sc_dev, 0, "stray interrupt");
1556 		return 1;
1557 	}
1558 #ifdef DIAGNOSTIC
1559 	panic("fdcintr: impossible");
1560 #endif
1561 #undef	st0
1562 #undef	cyl
1563 }
1564 
1565 static void
fdcretry(struct fdc_softc * fdc)1566 fdcretry(struct fdc_softc *fdc)
1567 {
1568 	struct fd_softc *fd;
1569 	struct buf *bp;
1570 
1571 	DPRINTF(("fdcretry:\n"));
1572 	fd = TAILQ_FIRST(&fdc->sc_drives);
1573 	bp = bufq_peek(fd->sc_q);
1574 
1575 	if (fd->sc_opts & FDOPT_NORETRY)
1576 		goto fail;
1577 
1578 	switch (fdc->sc_errors) {
1579 	case 0:
1580 		/* try again */
1581 		fdc->sc_state = SEEKCOMPLETE;
1582 		break;
1583 
1584 	case 1:
1585 	case 2:
1586 	case 3:
1587 		/* didn't work; try recalibrating */
1588 		fdc->sc_state = DORECAL;
1589 		break;
1590 
1591 	case 4:
1592 		/* still no go; reset the bastard */
1593 		fdc->sc_state = DORESET;
1594 		break;
1595 
1596 	default:
1597 	fail:
1598 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1599 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
1600 			    fd->sc_skip, (struct disklabel *)NULL);
1601 			fdcpstatus(7, fdc);
1602 		}
1603 
1604 		bp->b_error = EIO;
1605 		fdfinish(fd, bp);
1606 	}
1607 	fdc->sc_errors++;
1608 }
1609 
1610 static int
fdioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)1611 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1612 {
1613 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1614 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1615 	struct fdformat_parms *form_parms;
1616 	struct fdformat_cmd *form_cmd;
1617 	struct ne7_fd_formb *fd_formb;
1618 	int part = DISKPART(dev);
1619 	struct disklabel buffer;
1620 	int error;
1621 	unsigned int scratch;
1622 	int il[FD_MAX_NSEC + 1];
1623 	int i, j;
1624 
1625 	error = disk_ioctl(&fd->sc_dk, dev, cmd, addr, flag, l);
1626 	if (error != EPASSTHROUGH)
1627 		return error;
1628 
1629 	DPRINTF(("fdioctl:"));
1630 	switch (cmd) {
1631 	case DIOCWLABEL:
1632 		DPRINTF(("DIOCWLABEL\n"));
1633 		if ((flag & FWRITE) == 0)
1634 			return EBADF;
1635 		/* XXX do something */
1636 		return 0;
1637 
1638 	case DIOCWDINFO:
1639 		DPRINTF(("DIOCWDINFO\n"));
1640 		if ((flag & FWRITE) == 0)
1641 			return EBADF;
1642 
1643 		error = setdisklabel(&buffer, (struct disklabel *)addr,
1644 		    0, NULL);
1645 		if (error)
1646 			return error;
1647 
1648 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1649 		return error;
1650 
1651 	case FDIOCGETFORMAT:
1652 		DPRINTF(("FDIOCGETFORMAT\n"));
1653 		form_parms = (struct fdformat_parms *)addr;
1654 		form_parms->fdformat_version = FDFORMAT_VERSION;
1655 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1656 		form_parms->ncyl = fd->sc_type->cyls;
1657 		form_parms->nspt = fd->sc_type->sectrac;
1658 		form_parms->ntrk = fd->sc_type->heads;
1659 		form_parms->stepspercyl = fd->sc_type->step;
1660 		form_parms->gaplen = fd->sc_type->gap2;
1661 		form_parms->fillbyte = fd->sc_type->fillbyte;
1662 		form_parms->interleave = fd->sc_type->interleave;
1663 		switch (fd->sc_type->rate) {
1664 		case FDC_500KBPS:
1665 			form_parms->xfer_rate = 500 * 1024;
1666 			break;
1667 		case FDC_300KBPS:
1668 			form_parms->xfer_rate = 300 * 1024;
1669 			break;
1670 		case FDC_250KBPS:
1671 			form_parms->xfer_rate = 250 * 1024;
1672 			break;
1673 		default:
1674 			return EINVAL;
1675 		}
1676 		return 0;
1677 
1678 	case FDIOCSETFORMAT:
1679 		DPRINTF(("FDIOCSETFORMAT\n"));
1680 		if((flag & FWRITE) == 0)
1681 			return EBADF;	/* must be opened for writing */
1682 		form_parms = (struct fdformat_parms *)addr;
1683 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
1684 			return EINVAL;	/* wrong version of formatting prog */
1685 
1686 		scratch = form_parms->nbps >> 7;
1687 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1688 		    scratch & ~(1 << (ffs(scratch) - 1)))
1689 			/* not a power-of-two multiple of 128 */
1690 			return EINVAL;
1691 
1692 		switch (form_parms->xfer_rate) {
1693 		case 500 * 1024:
1694 			fd->sc_type->rate = FDC_500KBPS;
1695 			break;
1696 		case 300 * 1024:
1697 			fd->sc_type->rate = FDC_300KBPS;
1698 			break;
1699 		case 250 * 1024:
1700 			fd->sc_type->rate = FDC_250KBPS;
1701 			break;
1702 		default:
1703 			return EINVAL;
1704 		}
1705 
1706 		if (form_parms->nspt > FD_MAX_NSEC ||
1707 		    form_parms->fillbyte > 0xff ||
1708 		    form_parms->interleave > 0xff)
1709 			return EINVAL;
1710 		fd->sc_type->sectrac = form_parms->nspt;
1711 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1712 			return EINVAL;
1713 		fd->sc_type->heads = form_parms->ntrk;
1714 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1715 		fd->sc_type->secsize = ffs(scratch)-1;
1716 		fd->sc_type->gap2 = form_parms->gaplen;
1717 		fd->sc_type->cyls = form_parms->ncyl;
1718 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1719 		    form_parms->nbps / DEV_BSIZE;
1720 		fd->sc_type->step = form_parms->stepspercyl;
1721 		fd->sc_type->fillbyte = form_parms->fillbyte;
1722 		fd->sc_type->interleave = form_parms->interleave;
1723 		return 0;
1724 
1725 	case FDIOCFORMAT_TRACK:
1726 		DPRINTF(("FDIOCFORMAT_TRACK\n"));
1727 		if ((flag & FWRITE) == 0)
1728 			return EBADF;	/* must be opened for writing */
1729 		form_cmd = (struct fdformat_cmd *)addr;
1730 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1731 			return EINVAL;	/* wrong version of formatting prog */
1732 
1733 		if (form_cmd->head >= fd->sc_type->heads ||
1734 		    form_cmd->cylinder >= fd->sc_type->cyls) {
1735 			return EINVAL;
1736 		}
1737 
1738 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
1739 		    M_TEMP, M_WAITOK);
1740 		fd_formb->head = form_cmd->head;
1741 		fd_formb->cyl = form_cmd->cylinder;
1742 		fd_formb->transfer_rate = fd->sc_type->rate;
1743 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1744 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1745 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1746 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1747 
1748 		memset(il, 0, sizeof il);
1749 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1750 			while (il[(j % fd_formb->fd_formb_nsecs) + 1])
1751 				j++;
1752 			il[(j % fd_formb->fd_formb_nsecs)+  1] = i;
1753 			j += fd->sc_type->interleave;
1754 		}
1755 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1756 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1757 			fd_formb->fd_formb_headno(i) = form_cmd->head;
1758 			fd_formb->fd_formb_secno(i) = il[i + 1];
1759 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1760 		}
1761 
1762 		error = fdformat(dev, fd_formb, l);
1763 		free(fd_formb, M_TEMP);
1764 		return error;
1765 
1766 	case FDIOCGETOPTS:		/* get drive options */
1767 		DPRINTF(("FDIOCGETOPTS\n"));
1768 		*(int *)addr = fd->sc_opts;
1769 		return 0;
1770 
1771 	case FDIOCSETOPTS:		/* set drive options */
1772 		DPRINTF(("FDIOCSETOPTS\n"));
1773 		fd->sc_opts = *(int *)addr;
1774 		return 0;
1775 
1776 	case DIOCLOCK:
1777 		/*
1778 		 * Nothing to do here, really.
1779 		 */
1780 		return 0; /* XXX */
1781 
1782 	case DIOCEJECT:
1783 		DPRINTF(("DIOCEJECT\n"));
1784 		if (*(int *)addr == 0) {
1785 			/*
1786 			 * Don't force eject: check that we are the only
1787 			 * partition open. If so, unlock it.
1788 			 */
1789 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1790 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1791 			    fd->sc_dk.dk_openmask) {
1792 				return EBUSY;
1793 			}
1794 		}
1795 		/* FALLTHROUGH */
1796 	case ODIOCEJECT:
1797 		DPRINTF(("ODIOCEJECT\n"));
1798 		fd_do_eject(fdc, FDUNIT(dev));
1799 		return 0;
1800 
1801 	default:
1802 		return ENOTTY;
1803 	}
1804 
1805 #ifdef DIAGNOSTIC
1806 	panic("fdioctl: impossible");
1807 #endif
1808 }
1809 
1810 static int
fdformat(dev_t dev,struct ne7_fd_formb * finfo,struct lwp * l)1811 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
1812 {
1813 	int rv = 0;
1814 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1815 	struct fd_type *type = fd->sc_type;
1816 	struct buf *bp;
1817 
1818 	/* set up a buffer header for fdstrategy() */
1819 	bp = getiobuf(NULL, false);
1820 	if (bp == NULL)
1821 		return ENOBUFS;
1822 
1823 	bp->b_cflags = BC_BUSY;
1824 	bp->b_flags = B_PHYS | B_FORMAT;
1825 	bp->b_proc = l->l_proc;
1826 	bp->b_dev = dev;
1827 
1828 	/*
1829 	 * calculate a fake blkno, so fdstrategy() would initiate a
1830 	 * seek to the requested cylinder
1831 	 */
1832 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1833 	    + finfo->head * type->sectrac) * (128 << type->secsize) / DEV_BSIZE;
1834 
1835 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1836 	bp->b_data = (void *)finfo;
1837 
1838 #ifdef FDDEBUG
1839 	printf("fdformat: blkno %" PRIx64 " count %x\n",
1840 	    bp->b_blkno, bp->b_bcount);
1841 #endif
1842 
1843 	/* now do the format */
1844 	fdstrategy(bp);
1845 
1846 	/* ...and wait for it to complete */
1847 	rv = biowait(bp);
1848 	putiobuf(bp);
1849 	return rv;
1850 }
1851 
1852 static void
fd_do_eject(struct fdc_softc * fdc,int unit)1853 fd_do_eject(struct fdc_softc *fdc, int unit)
1854 {
1855 
1856 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20 | (1 << unit));
1857 	DELAY(1); /* XXX */
1858 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1859 }
1860 
1861 /*
1862  * Build disk label. For now we only create a label from what we know
1863  * from 'sc'.
1864  */
1865 static int
fdgetdisklabel(struct fd_softc * sc,dev_t dev)1866 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
1867 {
1868 	struct disklabel *lp;
1869 	int part;
1870 
1871 	DPRINTF(("fdgetdisklabel()\n"));
1872 
1873 	part = DISKPART(dev);
1874 	lp = sc->sc_dk.dk_label;
1875 	memset(lp, 0, sizeof(struct disklabel));
1876 
1877 	lp->d_secsize     = 128 << sc->sc_type->secsize;
1878 	lp->d_ntracks     = sc->sc_type->heads;
1879 	lp->d_nsectors    = sc->sc_type->sectrac;
1880 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
1881 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
1882 	lp->d_secperunit  = sc->sc_type->size;
1883 
1884 	lp->d_type        = DKTYPE_FLOPPY;
1885 	lp->d_rpm         = 300;	/* XXX */
1886 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
1887 	lp->d_bbsize      = 0;
1888 	lp->d_sbsize      = 0;
1889 	lp->d_npartitions = part + 1;
1890 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
1891 	lp->d_trkseek     = STEP_DELAY; /* XXX */
1892 	lp->d_magic       = DISKMAGIC;
1893 	lp->d_magic2      = DISKMAGIC;
1894 	lp->d_checksum    = dkcksum(lp);
1895 	lp->d_partitions[part].p_size   = lp->d_secperunit;
1896 	lp->d_partitions[part].p_fstype = FS_UNUSED;
1897 	lp->d_partitions[part].p_fsize  = 1024;
1898 	lp->d_partitions[part].p_frag   = 8;
1899 
1900 	return 0;
1901 }
1902 
1903 /*
1904  * Mountroot hook: prompt the user to enter the root file system
1905  * floppy.
1906  */
1907 static void
fd_mountroot_hook(device_t dev)1908 fd_mountroot_hook(device_t dev)
1909 {
1910 	struct fd_softc *fd = device_private(dev);
1911 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1912 	int c;
1913 
1914 	/* XXX device_unit() abuse */
1915 	fd_do_eject(fdc, device_unit(dev));
1916 	printf("Insert filesystem floppy and press return.");
1917 	for (;;) {
1918 		c = cngetc();
1919 		if ((c == '\r') || (c == '\n')) {
1920 			printf("\n");
1921 			break;
1922 		}
1923 	}
1924 }
1925