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