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