fd.c revision 1.37.8.5 1 1.37.8.5 nathanw /* $NetBSD: fd.c,v 1.37.8.5 2002/09/17 21:18: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.2 nathanw struct cfattach fdc_ca = {
179 1.37.8.2 nathanw sizeof(struct fdc_softc), fdcprobe, fdcattach
180 1.37.8.2 nathanw };
181 1.37.8.2 nathanw
182 1.37.8.2 nathanw extern struct cfdriver fdc_cd;
183 1.37.8.2 nathanw
184 1.37.8.2 nathanw /*
185 1.37.8.2 nathanw * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
186 1.37.8.2 nathanw * we tell them apart.
187 1.37.8.2 nathanw */
188 1.37.8.2 nathanw struct fd_type {
189 1.37.8.2 nathanw int sectrac; /* sectors per track */
190 1.37.8.2 nathanw int heads; /* number of heads */
191 1.37.8.2 nathanw int seccyl; /* sectors per cylinder */
192 1.37.8.2 nathanw int secsize; /* size code for sectors */
193 1.37.8.2 nathanw int datalen; /* data len when secsize = 0 */
194 1.37.8.2 nathanw int steprate; /* step rate and head unload time */
195 1.37.8.2 nathanw int gap1; /* gap len between sectors */
196 1.37.8.2 nathanw int gap2; /* formatting gap */
197 1.37.8.2 nathanw int cyls; /* total num of cylinders */
198 1.37.8.2 nathanw int size; /* size of disk in sectors */
199 1.37.8.2 nathanw int step; /* steps per cylinder */
200 1.37.8.2 nathanw int rate; /* transfer speed code */
201 1.37.8.2 nathanw char *name;
202 1.37.8.2 nathanw };
203 1.37.8.2 nathanw
204 1.37.8.2 nathanw /* The order of entries in the following table is important -- BEWARE! */
205 1.37.8.2 nathanw struct fd_type fd_types[] = {
206 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 */
207 1.37.8.2 nathanw { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
208 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 */
209 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 */
210 1.37.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
211 1.37.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
212 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 */
213 1.37.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
214 1.37.8.2 nathanw };
215 1.37.8.2 nathanw
216 1.37.8.2 nathanw /* software state, per disk (with up to 4 disks per ctlr) */
217 1.37.8.2 nathanw struct fd_softc {
218 1.37.8.2 nathanw struct device sc_dev;
219 1.37.8.2 nathanw struct disk sc_dk;
220 1.37.8.2 nathanw
221 1.37.8.2 nathanw struct fd_type *sc_deftype; /* default type descriptor */
222 1.37.8.2 nathanw struct fd_type *sc_type; /* current type descriptor */
223 1.37.8.2 nathanw
224 1.37.8.2 nathanw struct callout sc_motoron_ch;
225 1.37.8.2 nathanw struct callout sc_motoroff_ch;
226 1.37.8.2 nathanw
227 1.37.8.2 nathanw daddr_t sc_blkno; /* starting block number */
228 1.37.8.2 nathanw int sc_bcount; /* byte count left */
229 1.37.8.2 nathanw int sc_opts; /* user-set options */
230 1.37.8.2 nathanw int sc_skip; /* bytes already transferred */
231 1.37.8.2 nathanw int sc_nblks; /* number of blocks currently transferring */
232 1.37.8.2 nathanw int sc_nbytes; /* number of bytes currently transferring */
233 1.37.8.2 nathanw
234 1.37.8.2 nathanw int sc_drive; /* physical unit number */
235 1.37.8.2 nathanw int sc_flags;
236 1.37.8.2 nathanw #define FD_BOPEN 0x01 /* it's open */
237 1.37.8.2 nathanw #define FD_COPEN 0x02 /* it's open */
238 1.37.8.2 nathanw #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
239 1.37.8.2 nathanw #define FD_MOTOR 0x04 /* motor should be on */
240 1.37.8.2 nathanw #define FD_MOTOR_WAIT 0x08 /* motor coming up */
241 1.37.8.2 nathanw #define FD_ALIVE 0x10 /* alive */
242 1.37.8.2 nathanw int sc_cylin; /* where we think the head is */
243 1.37.8.2 nathanw
244 1.37.8.2 nathanw TAILQ_ENTRY(fd_softc) sc_drivechain;
245 1.37.8.2 nathanw int sc_ops; /* I/O ops since last switch */
246 1.37.8.4 nathanw struct bufq_state sc_q; /* pending I/O requests */
247 1.37.8.2 nathanw int sc_active; /* number of active I/O operations */
248 1.37.8.2 nathanw u_char *sc_copybuf; /* for secsize >=3 */
249 1.37.8.2 nathanw u_char sc_part; /* for secsize >=3 */
250 1.37.8.2 nathanw #define SEC_P10 0x02 /* first part */
251 1.37.8.2 nathanw #define SEC_P01 0x01 /* second part */
252 1.37.8.2 nathanw #define SEC_P11 0x03 /* both part */
253 1.37.8.2 nathanw
254 1.37.8.2 nathanw #if NRND > 0
255 1.37.8.2 nathanw rndsource_element_t rnd_source;
256 1.37.8.2 nathanw #endif
257 1.37.8.2 nathanw };
258 1.37.8.2 nathanw
259 1.37.8.2 nathanw /* floppy driver configuration */
260 1.37.8.2 nathanw int fdprobe __P((struct device *, struct cfdata *, void *));
261 1.37.8.2 nathanw void fdattach __P((struct device *, struct device *, void *));
262 1.37.8.2 nathanw
263 1.37.8.2 nathanw struct cfattach fd_ca = {
264 1.37.8.2 nathanw sizeof(struct fd_softc), fdprobe, fdattach
265 1.37.8.2 nathanw };
266 1.37.8.2 nathanw
267 1.37.8.2 nathanw extern struct cfdriver fd_cd;
268 1.37.8.2 nathanw
269 1.37.8.5 nathanw dev_type_open(fdopen);
270 1.37.8.5 nathanw dev_type_close(fdclose);
271 1.37.8.5 nathanw dev_type_read(fdread);
272 1.37.8.5 nathanw dev_type_write(fdwrite);
273 1.37.8.5 nathanw dev_type_ioctl(fdioctl);
274 1.37.8.5 nathanw dev_type_strategy(fdstrategy);
275 1.37.8.5 nathanw
276 1.37.8.5 nathanw const struct bdevsw fd_bdevsw = {
277 1.37.8.5 nathanw fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
278 1.37.8.5 nathanw };
279 1.37.8.5 nathanw
280 1.37.8.5 nathanw const struct cdevsw fd_cdevsw = {
281 1.37.8.5 nathanw fdopen, fdclose, fdread, fdwrite, fdioctl,
282 1.37.8.5 nathanw nostop, notty, nopoll, nommap, D_DISK
283 1.37.8.5 nathanw };
284 1.37.8.5 nathanw
285 1.37.8.2 nathanw void fdstart __P((struct fd_softc *fd));
286 1.37.8.2 nathanw
287 1.37.8.2 nathanw struct dkdriver fddkdriver = { fdstrategy };
288 1.37.8.2 nathanw
289 1.37.8.2 nathanw void fd_set_motor __P((struct fdc_softc *fdc, int reset));
290 1.37.8.2 nathanw void fd_motor_off __P((void *arg));
291 1.37.8.2 nathanw void fd_motor_on __P((void *arg));
292 1.37.8.2 nathanw int fdcresult __P((struct fdc_softc *fdc));
293 1.37.8.2 nathanw int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
294 1.37.8.2 nathanw void fdcstart __P((struct fdc_softc *fdc));
295 1.37.8.2 nathanw void fdcstatus __P((struct device *dv, int n, char *s));
296 1.37.8.2 nathanw void fdctimeout __P((void *arg));
297 1.37.8.2 nathanw void fdcpseudointr __P((void *arg));
298 1.37.8.2 nathanw void fdcretry __P((struct fdc_softc *fdc));
299 1.37.8.2 nathanw void fdfinish __P((struct fd_softc *fd, struct buf *bp));
300 1.37.8.2 nathanw __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
301 1.37.8.2 nathanw static int fdcpoll __P((struct fdc_softc *));
302 1.37.8.2 nathanw static int fdgetdisklabel __P((struct fd_softc *, dev_t));
303 1.37.8.2 nathanw static void fd_do_eject __P((struct fdc_softc *, int));
304 1.37.8.2 nathanw
305 1.37.8.2 nathanw void fd_mountroot_hook __P((struct device *));
306 1.37.8.2 nathanw
307 1.37.8.2 nathanw /* dma transfer routines */
308 1.37.8.2 nathanw __inline static void fdc_dmastart __P((struct fdc_softc*, int,
309 1.37.8.2 nathanw caddr_t, vsize_t));
310 1.37.8.2 nathanw static int fdcdmaintr __P((void*));
311 1.37.8.2 nathanw static int fdcdmaerrintr __P((void*));
312 1.37.8.2 nathanw
313 1.37.8.2 nathanw __inline static void
314 1.37.8.2 nathanw fdc_dmastart(fdc, read, addr, count)
315 1.37.8.2 nathanw struct fdc_softc *fdc;
316 1.37.8.2 nathanw int read;
317 1.37.8.2 nathanw caddr_t addr;
318 1.37.8.2 nathanw vsize_t count;
319 1.37.8.2 nathanw {
320 1.37.8.2 nathanw int error;
321 1.37.8.2 nathanw
322 1.37.8.3 nathanw DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %ld\n",
323 1.37.8.2 nathanw read ? "read" : "write", (caddr_t) addr, count));
324 1.37.8.2 nathanw
325 1.37.8.2 nathanw error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
326 1.37.8.2 nathanw 0, BUS_DMA_NOWAIT);
327 1.37.8.2 nathanw if (error) {
328 1.37.8.2 nathanw panic ("fdc_dmastart: cannot load dmamap");
329 1.37.8.2 nathanw }
330 1.37.8.2 nathanw
331 1.37.8.2 nathanw bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
332 1.37.8.2 nathanw read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
333 1.37.8.2 nathanw
334 1.37.8.2 nathanw fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
335 1.37.8.2 nathanw fdc->sc_dmamap,
336 1.37.8.2 nathanw (read?
337 1.37.8.2 nathanw DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
338 1.37.8.2 nathanw (DMAC_SCR_MAC_COUNT_UP|
339 1.37.8.2 nathanw DMAC_SCR_DAC_NO_COUNT),
340 1.37.8.2 nathanw (u_int8_t*) (fdc->sc_addr +
341 1.37.8.2 nathanw fddata)); /* XXX */
342 1.37.8.2 nathanw
343 1.37.8.2 nathanw dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
344 1.37.8.2 nathanw }
345 1.37.8.2 nathanw
346 1.37.8.2 nathanw static int
347 1.37.8.2 nathanw fdcdmaintr(arg)
348 1.37.8.2 nathanw void *arg;
349 1.37.8.2 nathanw {
350 1.37.8.2 nathanw struct fdc_softc *fdc = arg;
351 1.37.8.2 nathanw
352 1.37.8.2 nathanw bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
353 1.37.8.2 nathanw
354 1.37.8.2 nathanw return 0;
355 1.37.8.2 nathanw }
356 1.37.8.2 nathanw
357 1.37.8.2 nathanw static int
358 1.37.8.2 nathanw fdcdmaerrintr(dummy)
359 1.37.8.2 nathanw void *dummy;
360 1.37.8.2 nathanw {
361 1.37.8.2 nathanw DPRINTF(("fdcdmaerrintr\n"));
362 1.37.8.2 nathanw
363 1.37.8.2 nathanw return 0;
364 1.37.8.2 nathanw }
365 1.37.8.2 nathanw
366 1.37.8.2 nathanw /* ARGSUSED */
367 1.37.8.2 nathanw int
368 1.37.8.2 nathanw fdcprobe(parent, cf, aux)
369 1.37.8.2 nathanw struct device *parent;
370 1.37.8.2 nathanw struct cfdata *cf;
371 1.37.8.2 nathanw void *aux;
372 1.37.8.2 nathanw {
373 1.37.8.2 nathanw struct intio_attach_args *ia = aux;
374 1.37.8.2 nathanw
375 1.37.8.2 nathanw if (strcmp(ia->ia_name, "fdc") != 0)
376 1.37.8.2 nathanw return 0;
377 1.37.8.2 nathanw
378 1.37.8.2 nathanw if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
379 1.37.8.2 nathanw ia->ia_addr = FDC_ADDR;
380 1.37.8.2 nathanw if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
381 1.37.8.2 nathanw ia->ia_intr = FDC_INTR;
382 1.37.8.2 nathanw if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
383 1.37.8.2 nathanw ia->ia_dma = FDC_DMA;
384 1.37.8.2 nathanw if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
385 1.37.8.2 nathanw ia->ia_dmaintr = FDC_DMAINTR;
386 1.37.8.2 nathanw
387 1.37.8.2 nathanw if ((ia->ia_intr & 0x03) != 0)
388 1.37.8.2 nathanw return 0;
389 1.37.8.2 nathanw
390 1.37.8.2 nathanw ia->ia_size = 0x2000;
391 1.37.8.2 nathanw if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
392 1.37.8.2 nathanw return 0;
393 1.37.8.2 nathanw
394 1.37.8.2 nathanw /* builtin device; always there */
395 1.37.8.2 nathanw return 1;
396 1.37.8.2 nathanw }
397 1.37.8.2 nathanw
398 1.37.8.2 nathanw /*
399 1.37.8.2 nathanw * Arguments passed between fdcattach and fdprobe.
400 1.37.8.2 nathanw */
401 1.37.8.2 nathanw struct fdc_attach_args {
402 1.37.8.2 nathanw int fa_drive;
403 1.37.8.2 nathanw struct fd_type *fa_deftype;
404 1.37.8.2 nathanw };
405 1.37.8.2 nathanw
406 1.37.8.2 nathanw /*
407 1.37.8.2 nathanw * Print the location of a disk drive (called just before attaching the
408 1.37.8.2 nathanw * the drive). If `fdc' is not NULL, the drive was found but was not
409 1.37.8.2 nathanw * in the system config file; print the drive name as well.
410 1.37.8.2 nathanw * Return QUIET (config_find ignores this if the device was configured) to
411 1.37.8.2 nathanw * avoid printing `fdN not configured' messages.
412 1.37.8.2 nathanw */
413 1.37.8.2 nathanw int
414 1.37.8.2 nathanw fdprint(aux, fdc)
415 1.37.8.2 nathanw void *aux;
416 1.37.8.2 nathanw const char *fdc;
417 1.37.8.2 nathanw {
418 1.37.8.2 nathanw register struct fdc_attach_args *fa = aux;
419 1.37.8.2 nathanw
420 1.37.8.2 nathanw if (!fdc)
421 1.37.8.2 nathanw printf(" drive %d", fa->fa_drive);
422 1.37.8.2 nathanw return QUIET;
423 1.37.8.2 nathanw }
424 1.37.8.2 nathanw
425 1.37.8.2 nathanw void
426 1.37.8.2 nathanw fdcattach(parent, self, aux)
427 1.37.8.2 nathanw struct device *parent, *self;
428 1.37.8.2 nathanw void *aux;
429 1.37.8.2 nathanw {
430 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)self;
431 1.37.8.2 nathanw bus_space_tag_t iot;
432 1.37.8.2 nathanw bus_space_handle_t ioh;
433 1.37.8.2 nathanw struct intio_attach_args *ia = aux;
434 1.37.8.2 nathanw struct fdc_attach_args fa;
435 1.37.8.2 nathanw
436 1.37.8.2 nathanw iot = ia->ia_bst;
437 1.37.8.2 nathanw
438 1.37.8.2 nathanw printf("\n");
439 1.37.8.2 nathanw
440 1.37.8.2 nathanw callout_init(&fdc->sc_timo_ch);
441 1.37.8.2 nathanw callout_init(&fdc->sc_intr_ch);
442 1.37.8.2 nathanw
443 1.37.8.2 nathanw /* Re-map the I/O space. */
444 1.37.8.2 nathanw bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
445 1.37.8.2 nathanw
446 1.37.8.2 nathanw fdc->sc_iot = iot;
447 1.37.8.2 nathanw fdc->sc_ioh = ioh;
448 1.37.8.2 nathanw fdc->sc_addr = (void*) ia->ia_addr;
449 1.37.8.2 nathanw
450 1.37.8.2 nathanw fdc->sc_dmat = ia->ia_dmat;
451 1.37.8.2 nathanw fdc->sc_state = DEVIDLE;
452 1.37.8.2 nathanw TAILQ_INIT(&fdc->sc_drives);
453 1.37.8.2 nathanw
454 1.37.8.2 nathanw /* Initialize DMAC channel */
455 1.37.8.2 nathanw fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
456 1.37.8.2 nathanw ia->ia_dmaintr, fdcdmaintr, fdc,
457 1.37.8.2 nathanw ia->ia_dmaintr+1, fdcdmaerrintr,
458 1.37.8.2 nathanw fdc);
459 1.37.8.2 nathanw if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
460 1.37.8.2 nathanw 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
461 1.37.8.2 nathanw &fdc->sc_dmamap)) {
462 1.37.8.2 nathanw printf("%s: can't set up intio DMA map\n",
463 1.37.8.2 nathanw fdc->sc_dev.dv_xname);
464 1.37.8.2 nathanw return;
465 1.37.8.2 nathanw }
466 1.37.8.2 nathanw
467 1.37.8.2 nathanw if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
468 1.37.8.2 nathanw panic ("Could not establish interrupt (duplicated vector?).");
469 1.37.8.2 nathanw intio_set_ivec(ia->ia_intr);
470 1.37.8.2 nathanw
471 1.37.8.2 nathanw /* reset */
472 1.37.8.2 nathanw intio_disable_intr(SICILIAN_INTR_FDD);
473 1.37.8.2 nathanw intio_enable_intr(SICILIAN_INTR_FDC);
474 1.37.8.2 nathanw fdcresult(fdc);
475 1.37.8.2 nathanw fdcreset(fdc);
476 1.37.8.2 nathanw
477 1.37.8.2 nathanw printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
478 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
479 1.37.8.2 nathanw out_fdc(iot, ioh, 0xd0);
480 1.37.8.2 nathanw out_fdc(iot, ioh, 0x10);
481 1.37.8.2 nathanw
482 1.37.8.2 nathanw /* physical limit: four drives per controller. */
483 1.37.8.2 nathanw for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
484 1.37.8.2 nathanw (void)config_found(self, (void *)&fa, fdprint);
485 1.37.8.2 nathanw }
486 1.37.8.2 nathanw
487 1.37.8.2 nathanw intio_enable_intr(SICILIAN_INTR_FDC);
488 1.37.8.2 nathanw }
489 1.37.8.2 nathanw
490 1.37.8.2 nathanw void
491 1.37.8.2 nathanw fdcreset(fdc)
492 1.37.8.2 nathanw struct fdc_softc *fdc;
493 1.37.8.2 nathanw {
494 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
495 1.37.8.2 nathanw }
496 1.37.8.2 nathanw
497 1.37.8.2 nathanw static int
498 1.37.8.2 nathanw fdcpoll(fdc)
499 1.37.8.2 nathanw struct fdc_softc *fdc;
500 1.37.8.2 nathanw {
501 1.37.8.2 nathanw int i = 25000, n;
502 1.37.8.2 nathanw while (--i > 0) {
503 1.37.8.2 nathanw if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
504 1.37.8.2 nathanw out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
505 1.37.8.2 nathanw n = fdcresult(fdc);
506 1.37.8.2 nathanw break;
507 1.37.8.2 nathanw }
508 1.37.8.2 nathanw DELAY(100);
509 1.37.8.2 nathanw }
510 1.37.8.2 nathanw return i;
511 1.37.8.2 nathanw }
512 1.37.8.2 nathanw
513 1.37.8.2 nathanw int
514 1.37.8.2 nathanw fdprobe(parent, cf, aux)
515 1.37.8.2 nathanw struct device *parent;
516 1.37.8.2 nathanw struct cfdata *cf;
517 1.37.8.2 nathanw void *aux;
518 1.37.8.2 nathanw {
519 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)parent;
520 1.37.8.2 nathanw struct fd_type *type;
521 1.37.8.2 nathanw struct fdc_attach_args *fa = aux;
522 1.37.8.2 nathanw int drive = fa->fa_drive;
523 1.37.8.2 nathanw bus_space_tag_t iot = fdc->sc_iot;
524 1.37.8.2 nathanw bus_space_handle_t ioh = fdc->sc_ioh;
525 1.37.8.2 nathanw int n;
526 1.37.8.2 nathanw int found = 0;
527 1.37.8.2 nathanw int i;
528 1.37.8.2 nathanw
529 1.37.8.2 nathanw if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
530 1.37.8.2 nathanw cf->cf_loc[FDCCF_UNIT] != drive)
531 1.37.8.2 nathanw return 0;
532 1.37.8.2 nathanw
533 1.37.8.2 nathanw type = &fd_types[0]; /* XXX 1.2MB */
534 1.37.8.2 nathanw
535 1.37.8.2 nathanw intio_disable_intr(SICILIAN_INTR_FDC);
536 1.37.8.2 nathanw
537 1.37.8.2 nathanw /* select drive and turn on motor */
538 1.37.8.2 nathanw bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
539 1.37.8.2 nathanw fdc_force_ready(FDCRDY);
540 1.37.8.2 nathanw fdcpoll(fdc);
541 1.37.8.2 nathanw
542 1.37.8.2 nathanw retry:
543 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_RECAL);
544 1.37.8.2 nathanw out_fdc(iot, ioh, drive);
545 1.37.8.2 nathanw
546 1.37.8.2 nathanw i = 25000;
547 1.37.8.2 nathanw while (--i > 0) {
548 1.37.8.2 nathanw if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
549 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
550 1.37.8.2 nathanw n = fdcresult(fdc);
551 1.37.8.2 nathanw break;
552 1.37.8.2 nathanw }
553 1.37.8.2 nathanw DELAY(100);
554 1.37.8.2 nathanw }
555 1.37.8.2 nathanw
556 1.37.8.2 nathanw #ifdef FDDEBUG
557 1.37.8.2 nathanw {
558 1.37.8.2 nathanw int i;
559 1.37.8.2 nathanw DPRINTF(("fdprobe: status"));
560 1.37.8.2 nathanw for (i = 0; i < n; i++)
561 1.37.8.2 nathanw DPRINTF((" %x", fdc->sc_status[i]));
562 1.37.8.2 nathanw DPRINTF(("\n"));
563 1.37.8.2 nathanw }
564 1.37.8.2 nathanw #endif
565 1.37.8.2 nathanw
566 1.37.8.2 nathanw if (n == 2) {
567 1.37.8.2 nathanw if ((fdc->sc_status[0] & 0xf0) == 0x20) {
568 1.37.8.2 nathanw found = 1;
569 1.37.8.2 nathanw } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
570 1.37.8.2 nathanw goto retry;
571 1.37.8.2 nathanw }
572 1.37.8.2 nathanw }
573 1.37.8.2 nathanw
574 1.37.8.2 nathanw /* turn off motor */
575 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
576 1.37.8.2 nathanw fdctl, (type->rate << 4)| drive);
577 1.37.8.2 nathanw fdc_force_ready(FDCSTBY);
578 1.37.8.2 nathanw if (!found) {
579 1.37.8.2 nathanw intio_enable_intr(SICILIAN_INTR_FDC);
580 1.37.8.2 nathanw return 0;
581 1.37.8.2 nathanw }
582 1.37.8.2 nathanw
583 1.37.8.2 nathanw return 1;
584 1.37.8.2 nathanw }
585 1.37.8.2 nathanw
586 1.37.8.2 nathanw /*
587 1.37.8.2 nathanw * Controller is working, and drive responded. Attach it.
588 1.37.8.2 nathanw */
589 1.37.8.2 nathanw void
590 1.37.8.2 nathanw fdattach(parent, self, aux)
591 1.37.8.2 nathanw struct device *parent, *self;
592 1.37.8.2 nathanw void *aux;
593 1.37.8.2 nathanw {
594 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)parent;
595 1.37.8.2 nathanw struct fd_softc *fd = (void *)self;
596 1.37.8.2 nathanw struct fdc_attach_args *fa = aux;
597 1.37.8.2 nathanw struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
598 1.37.8.2 nathanw int drive = fa->fa_drive;
599 1.37.8.2 nathanw
600 1.37.8.2 nathanw callout_init(&fd->sc_motoron_ch);
601 1.37.8.2 nathanw callout_init(&fd->sc_motoroff_ch);
602 1.37.8.2 nathanw
603 1.37.8.2 nathanw fd->sc_flags = 0;
604 1.37.8.2 nathanw
605 1.37.8.2 nathanw if (type)
606 1.37.8.2 nathanw printf(": %s, %d cyl, %d head, %d sec\n", type->name,
607 1.37.8.2 nathanw type->cyls, type->heads, type->sectrac);
608 1.37.8.2 nathanw else
609 1.37.8.2 nathanw printf(": density unknown\n");
610 1.37.8.2 nathanw
611 1.37.8.4 nathanw bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
612 1.37.8.2 nathanw fd->sc_cylin = -1;
613 1.37.8.2 nathanw fd->sc_drive = drive;
614 1.37.8.2 nathanw fd->sc_deftype = type;
615 1.37.8.2 nathanw fdc->sc_fd[drive] = fd;
616 1.37.8.2 nathanw
617 1.37.8.2 nathanw fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
618 1.37.8.2 nathanw if (fd->sc_copybuf == 0)
619 1.37.8.2 nathanw printf("fdprobe: WARNING!! malloc() failed.\n");
620 1.37.8.2 nathanw fd->sc_flags |= FD_ALIVE;
621 1.37.8.2 nathanw
622 1.37.8.2 nathanw /*
623 1.37.8.2 nathanw * Initialize and attach the disk structure.
624 1.37.8.2 nathanw */
625 1.37.8.2 nathanw fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
626 1.37.8.2 nathanw fd->sc_dk.dk_driver = &fddkdriver;
627 1.37.8.2 nathanw disk_attach(&fd->sc_dk);
628 1.37.8.2 nathanw
629 1.37.8.2 nathanw /*
630 1.37.8.2 nathanw * Establish a mountroot_hook anyway in case we booted
631 1.37.8.2 nathanw * with RB_ASKNAME and get selected as the boot device.
632 1.37.8.2 nathanw */
633 1.37.8.2 nathanw mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
634 1.37.8.2 nathanw
635 1.37.8.2 nathanw #if NRND > 0
636 1.37.8.2 nathanw rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
637 1.37.8.2 nathanw RND_TYPE_DISK, 0);
638 1.37.8.2 nathanw #endif
639 1.37.8.2 nathanw }
640 1.37.8.2 nathanw
641 1.37.8.2 nathanw __inline struct fd_type *
642 1.37.8.2 nathanw fd_dev_to_type(fd, dev)
643 1.37.8.2 nathanw struct fd_softc *fd;
644 1.37.8.2 nathanw dev_t dev;
645 1.37.8.2 nathanw {
646 1.37.8.2 nathanw int type = FDTYPE(dev);
647 1.37.8.2 nathanw
648 1.37.8.2 nathanw if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
649 1.37.8.2 nathanw return NULL;
650 1.37.8.2 nathanw return &fd_types[type];
651 1.37.8.2 nathanw }
652 1.37.8.2 nathanw
653 1.37.8.2 nathanw void
654 1.37.8.2 nathanw fdstrategy(bp)
655 1.37.8.2 nathanw register struct buf *bp; /* IO operation to perform */
656 1.37.8.2 nathanw {
657 1.37.8.2 nathanw struct fd_softc *fd;
658 1.37.8.2 nathanw int unit = FDUNIT(bp->b_dev);
659 1.37.8.2 nathanw int sz;
660 1.37.8.2 nathanw int s;
661 1.37.8.2 nathanw
662 1.37.8.2 nathanw if (unit >= fd_cd.cd_ndevs ||
663 1.37.8.2 nathanw (fd = fd_cd.cd_devs[unit]) == 0 ||
664 1.37.8.2 nathanw bp->b_blkno < 0 ||
665 1.37.8.2 nathanw (bp->b_bcount % FDC_BSIZE) != 0) {
666 1.37.8.3 nathanw DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%ld\n", unit,
667 1.37.8.2 nathanw bp->b_blkno, bp->b_bcount));
668 1.37.8.2 nathanw bp->b_error = EINVAL;
669 1.37.8.2 nathanw goto bad;
670 1.37.8.2 nathanw }
671 1.37.8.2 nathanw
672 1.37.8.2 nathanw /* If it's a null transfer, return immediately. */
673 1.37.8.2 nathanw if (bp->b_bcount == 0)
674 1.37.8.2 nathanw goto done;
675 1.37.8.2 nathanw
676 1.37.8.2 nathanw sz = howmany(bp->b_bcount, FDC_BSIZE);
677 1.37.8.2 nathanw
678 1.37.8.2 nathanw if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
679 1.37.8.2 nathanw sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - 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.2 nathanw ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1134 1.37.8.2 nathanw break;
1135 1.37.8.2 nathanw }
1136 1.37.8.2 nathanw }
1137 1.37.8.2 nathanw fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1138 1.37.8.2 nathanw fd_set_motor(fdc, 0);
1139 1.37.8.2 nathanw fdc->sc_state = MOTORWAIT;
1140 1.37.8.2 nathanw /* allow .5s for motor to stabilize */
1141 1.37.8.2 nathanw callout_reset(&fd->sc_motoron_ch, hz / 2,
1142 1.37.8.2 nathanw fd_motor_on, fd);
1143 1.37.8.2 nathanw return 1;
1144 1.37.8.2 nathanw }
1145 1.37.8.2 nathanw /* Make sure the right drive is selected. */
1146 1.37.8.2 nathanw fd_set_motor(fdc, 0);
1147 1.37.8.2 nathanw
1148 1.37.8.2 nathanw /* fall through */
1149 1.37.8.2 nathanw case DOSEEK:
1150 1.37.8.2 nathanw doseek:
1151 1.37.8.2 nathanw DPRINTF(("fdcintr: in DOSEEK\n"));
1152 1.37.8.2 nathanw if (fd->sc_cylin == bp->b_cylinder)
1153 1.37.8.2 nathanw goto doio;
1154 1.37.8.2 nathanw
1155 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1156 1.37.8.2 nathanw out_fdc(iot, ioh, 0xd0); /* XXX const */
1157 1.37.8.2 nathanw out_fdc(iot, ioh, 0x10);
1158 1.37.8.2 nathanw
1159 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1160 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1161 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1162 1.37.8.2 nathanw
1163 1.37.8.2 nathanw fd->sc_cylin = -1;
1164 1.37.8.2 nathanw fdc->sc_state = SEEKWAIT;
1165 1.37.8.2 nathanw
1166 1.37.8.2 nathanw fd->sc_dk.dk_seek++;
1167 1.37.8.2 nathanw disk_busy(&fd->sc_dk);
1168 1.37.8.2 nathanw
1169 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1170 1.37.8.2 nathanw return 1;
1171 1.37.8.2 nathanw
1172 1.37.8.2 nathanw case DOIO:
1173 1.37.8.2 nathanw doio:
1174 1.37.8.2 nathanw DPRINTF(("fdcintr: DOIO: "));
1175 1.37.8.2 nathanw type = fd->sc_type;
1176 1.37.8.2 nathanw sectrac = type->sectrac;
1177 1.37.8.2 nathanw pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1178 1.37.8.2 nathanw sec = pos / (1 << (type->secsize - 2));
1179 1.37.8.2 nathanw if (type->secsize == 2) {
1180 1.37.8.2 nathanw fd->sc_part = SEC_P11;
1181 1.37.8.2 nathanw nblks = (sectrac - sec) << (type->secsize - 2);
1182 1.37.8.2 nathanw nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1183 1.37.8.2 nathanw DPRINTF(("nblks(0)"));
1184 1.37.8.2 nathanw } else if ((fd->sc_blkno % 2) == 0) {
1185 1.37.8.2 nathanw if (fd->sc_bcount & 0x00000200) {
1186 1.37.8.2 nathanw if (fd->sc_bcount == FDC_BSIZE) {
1187 1.37.8.2 nathanw fd->sc_part = SEC_P10;
1188 1.37.8.2 nathanw nblks = 1;
1189 1.37.8.2 nathanw DPRINTF(("nblks(1)"));
1190 1.37.8.2 nathanw } else {
1191 1.37.8.2 nathanw fd->sc_part = SEC_P11;
1192 1.37.8.2 nathanw nblks = (sectrac - sec) * 2;
1193 1.37.8.2 nathanw nblks = min(nblks, fd->sc_bcount
1194 1.37.8.2 nathanw / FDC_BSIZE - 1);
1195 1.37.8.2 nathanw DPRINTF(("nblks(2)"));
1196 1.37.8.2 nathanw }
1197 1.37.8.2 nathanw } else {
1198 1.37.8.2 nathanw fd->sc_part = SEC_P11;
1199 1.37.8.2 nathanw nblks = (sectrac - sec)
1200 1.37.8.2 nathanw << (type->secsize - 2);
1201 1.37.8.2 nathanw nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1202 1.37.8.2 nathanw DPRINTF(("nblks(3)"));
1203 1.37.8.2 nathanw }
1204 1.37.8.2 nathanw } else {
1205 1.37.8.2 nathanw fd->sc_part = SEC_P01;
1206 1.37.8.2 nathanw nblks = 1;
1207 1.37.8.2 nathanw DPRINTF(("nblks(4)"));
1208 1.37.8.2 nathanw }
1209 1.37.8.2 nathanw nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1210 1.37.8.2 nathanw DPRINTF((" %d\n", nblks));
1211 1.37.8.2 nathanw fd->sc_nblks = nblks;
1212 1.37.8.2 nathanw fd->sc_nbytes = nblks * FDC_BSIZE;
1213 1.37.8.2 nathanw head = (fd->sc_blkno
1214 1.37.8.2 nathanw % (type->seccyl * (1 << (type->secsize - 2))))
1215 1.37.8.2 nathanw / (type->sectrac * (1 << (type->secsize - 2)));
1216 1.37.8.2 nathanw
1217 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1218 1.37.8.2 nathanw {int block;
1219 1.37.8.2 nathanw block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1220 1.37.8.2 nathanw + sec) * (1 << (type->secsize - 2));
1221 1.37.8.2 nathanw block += (fd->sc_part == SEC_P01) ? 1 : 0;
1222 1.37.8.2 nathanw if (block != fd->sc_blkno) {
1223 1.37.8.2 nathanw printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1224 1.37.8.2 nathanw printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1225 1.37.8.2 nathanw #ifdef DDB
1226 1.37.8.2 nathanw Debugger();
1227 1.37.8.2 nathanw #endif
1228 1.37.8.2 nathanw }}
1229 1.37.8.2 nathanw #endif
1230 1.37.8.2 nathanw read = bp->b_flags & B_READ;
1231 1.37.8.2 nathanw DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1232 1.37.8.2 nathanw read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1233 1.37.8.2 nathanw head, sec, nblks, fd->sc_skip));
1234 1.37.8.2 nathanw DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1235 1.37.8.2 nathanw type->secsize));
1236 1.37.8.2 nathanw
1237 1.37.8.2 nathanw if (fd->sc_part != SEC_P11)
1238 1.37.8.2 nathanw goto docopy;
1239 1.37.8.2 nathanw
1240 1.37.8.2 nathanw fdc_dmastart(fdc,
1241 1.37.8.2 nathanw read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1242 1.37.8.2 nathanw if (read)
1243 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1244 1.37.8.2 nathanw else
1245 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1246 1.37.8.2 nathanw out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1247 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1248 1.37.8.2 nathanw out_fdc(iot, ioh, head);
1249 1.37.8.2 nathanw out_fdc(iot, ioh, sec + 1); /* sector +1 */
1250 1.37.8.2 nathanw out_fdc(iot, ioh, type->secsize); /* sector size */
1251 1.37.8.2 nathanw out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1252 1.37.8.2 nathanw out_fdc(iot, ioh, type->gap1); /* gap1 size */
1253 1.37.8.2 nathanw out_fdc(iot, ioh, type->datalen); /* data length */
1254 1.37.8.2 nathanw fdc->sc_state = IOCOMPLETE;
1255 1.37.8.2 nathanw
1256 1.37.8.2 nathanw disk_busy(&fd->sc_dk);
1257 1.37.8.2 nathanw
1258 1.37.8.2 nathanw /* allow 2 seconds for operation */
1259 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1260 1.37.8.2 nathanw return 1; /* will return later */
1261 1.37.8.2 nathanw
1262 1.37.8.2 nathanw case DOCOPY:
1263 1.37.8.2 nathanw docopy:
1264 1.37.8.2 nathanw DPRINTF(("fdcintr: DOCOPY:\n"));
1265 1.37.8.2 nathanw fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1266 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1267 1.37.8.2 nathanw out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1268 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1269 1.37.8.2 nathanw out_fdc(iot, ioh, head);
1270 1.37.8.2 nathanw out_fdc(iot, ioh, sec + 1); /* sector +1 */
1271 1.37.8.2 nathanw out_fdc(iot, ioh, type->secsize); /* sector size */
1272 1.37.8.2 nathanw out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1273 1.37.8.2 nathanw out_fdc(iot, ioh, type->gap1); /* gap1 size */
1274 1.37.8.2 nathanw out_fdc(iot, ioh, type->datalen); /* data length */
1275 1.37.8.2 nathanw fdc->sc_state = COPYCOMPLETE;
1276 1.37.8.2 nathanw /* allow 2 seconds for operation */
1277 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1278 1.37.8.2 nathanw return 1; /* will return later */
1279 1.37.8.2 nathanw
1280 1.37.8.2 nathanw case DOIOHALF:
1281 1.37.8.2 nathanw doiohalf:
1282 1.37.8.2 nathanw DPRINTF((" DOIOHALF:\n"));
1283 1.37.8.2 nathanw
1284 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1285 1.37.8.2 nathanw type = fd->sc_type;
1286 1.37.8.2 nathanw sectrac = type->sectrac;
1287 1.37.8.2 nathanw pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1288 1.37.8.2 nathanw sec = pos / (1 << (type->secsize - 2));
1289 1.37.8.2 nathanw head = (fd->sc_blkno
1290 1.37.8.2 nathanw % (type->seccyl * (1 << (type->secsize - 2))))
1291 1.37.8.2 nathanw / (type->sectrac * (1 << (type->secsize - 2)));
1292 1.37.8.2 nathanw {int block;
1293 1.37.8.2 nathanw block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1294 1.37.8.2 nathanw * (1 << (type->secsize - 2));
1295 1.37.8.2 nathanw block += (fd->sc_part == SEC_P01) ? 1 : 0;
1296 1.37.8.2 nathanw if (block != fd->sc_blkno) {
1297 1.37.8.2 nathanw printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1298 1.37.8.2 nathanw #ifdef DDB
1299 1.37.8.2 nathanw Debugger();
1300 1.37.8.2 nathanw #endif
1301 1.37.8.2 nathanw }}
1302 1.37.8.2 nathanw #endif
1303 1.37.8.2 nathanw if ((read = bp->b_flags & B_READ)) {
1304 1.37.8.2 nathanw memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf
1305 1.37.8.2 nathanw + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1306 1.37.8.2 nathanw FDC_BSIZE);
1307 1.37.8.2 nathanw fdc->sc_state = IOCOMPLETE;
1308 1.37.8.2 nathanw goto iocomplete2;
1309 1.37.8.2 nathanw } else {
1310 1.37.8.2 nathanw memcpy(fd->sc_copybuf
1311 1.37.8.2 nathanw + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1312 1.37.8.2 nathanw bp->b_data + fd->sc_skip, FDC_BSIZE);
1313 1.37.8.2 nathanw fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1314 1.37.8.2 nathanw }
1315 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1316 1.37.8.2 nathanw out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1317 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1318 1.37.8.2 nathanw out_fdc(iot, ioh, head);
1319 1.37.8.2 nathanw out_fdc(iot, ioh, sec + 1); /* sector +1 */
1320 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1321 1.37.8.2 nathanw out_fdc(iot, ioh, sectrac); /* sectors/track */
1322 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1323 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1324 1.37.8.2 nathanw fdc->sc_state = IOCOMPLETE;
1325 1.37.8.2 nathanw /* allow 2 seconds for operation */
1326 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1327 1.37.8.2 nathanw return 1; /* will return later */
1328 1.37.8.2 nathanw
1329 1.37.8.2 nathanw case SEEKWAIT:
1330 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1331 1.37.8.2 nathanw fdc->sc_state = SEEKCOMPLETE;
1332 1.37.8.2 nathanw /* allow 1/50 second for heads to settle */
1333 1.37.8.2 nathanw #if 0
1334 1.37.8.2 nathanw callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1335 1.37.8.2 nathanw #endif
1336 1.37.8.2 nathanw return 1;
1337 1.37.8.2 nathanw
1338 1.37.8.2 nathanw case SEEKCOMPLETE:
1339 1.37.8.2 nathanw /* Make sure seek really happened */
1340 1.37.8.2 nathanw DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1341 1.37.8.2 nathanw bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1342 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
1343 1.37.8.2 nathanw tmp = fdcresult(fdc);
1344 1.37.8.2 nathanw if ((st0 & 0xf8) == 0xc0) {
1345 1.37.8.2 nathanw DPRINTF(("fdcintr: first seek!\n"));
1346 1.37.8.2 nathanw fdc->sc_state = DORECAL;
1347 1.37.8.2 nathanw goto loop;
1348 1.37.8.2 nathanw } else if (tmp != 2 ||
1349 1.37.8.2 nathanw (st0 & 0xf8) != 0x20 ||
1350 1.37.8.2 nathanw cyl != bp->b_cylinder) {
1351 1.37.8.2 nathanw #ifdef FDDEBUG
1352 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 2, "seek failed");
1353 1.37.8.2 nathanw #endif
1354 1.37.8.2 nathanw fdcretry(fdc);
1355 1.37.8.2 nathanw goto loop;
1356 1.37.8.2 nathanw }
1357 1.37.8.2 nathanw fd->sc_cylin = bp->b_cylinder;
1358 1.37.8.2 nathanw goto doio;
1359 1.37.8.2 nathanw
1360 1.37.8.2 nathanw case IOTIMEDOUT:
1361 1.37.8.2 nathanw #if 0
1362 1.37.8.2 nathanw isa_dmaabort(fdc->sc_drq);
1363 1.37.8.2 nathanw #endif
1364 1.37.8.2 nathanw case SEEKTIMEDOUT:
1365 1.37.8.2 nathanw case RECALTIMEDOUT:
1366 1.37.8.2 nathanw case RESETTIMEDOUT:
1367 1.37.8.2 nathanw fdcretry(fdc);
1368 1.37.8.2 nathanw goto loop;
1369 1.37.8.2 nathanw
1370 1.37.8.2 nathanw case IOCOMPLETE: /* IO DONE, post-analyze */
1371 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1372 1.37.8.2 nathanw DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1373 1.37.8.2 nathanw if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1374 1.37.8.2 nathanw printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1375 1.37.8.2 nathanw #if 0
1376 1.37.8.2 nathanw isa_dmaabort(fdc->sc_drq);
1377 1.37.8.2 nathanw #endif
1378 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1379 1.37.8.2 nathanw "read failed" : "write failed");
1380 1.37.8.2 nathanw printf("blkno %d nblks %d\n",
1381 1.37.8.2 nathanw fd->sc_blkno, fd->sc_nblks);
1382 1.37.8.2 nathanw fdcretry(fdc);
1383 1.37.8.2 nathanw goto loop;
1384 1.37.8.2 nathanw }
1385 1.37.8.2 nathanw #if 0
1386 1.37.8.2 nathanw isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1387 1.37.8.2 nathanw nblks * FDC_BSIZE, fdc->sc_drq);
1388 1.37.8.2 nathanw #endif
1389 1.37.8.2 nathanw iocomplete2:
1390 1.37.8.2 nathanw if (fdc->sc_errors) {
1391 1.37.8.2 nathanw diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1392 1.37.8.2 nathanw fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1393 1.37.8.2 nathanw printf("\n");
1394 1.37.8.2 nathanw fdc->sc_errors = 0;
1395 1.37.8.2 nathanw }
1396 1.37.8.2 nathanw fd->sc_blkno += fd->sc_nblks;
1397 1.37.8.2 nathanw fd->sc_skip += fd->sc_nbytes;
1398 1.37.8.2 nathanw fd->sc_bcount -= fd->sc_nbytes;
1399 1.37.8.2 nathanw DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1400 1.37.8.2 nathanw if (fd->sc_bcount > 0) {
1401 1.37.8.2 nathanw bp->b_cylinder = fd->sc_blkno
1402 1.37.8.2 nathanw / (fd->sc_type->seccyl
1403 1.37.8.2 nathanw * (1 << (fd->sc_type->secsize - 2)));
1404 1.37.8.2 nathanw goto doseek;
1405 1.37.8.2 nathanw }
1406 1.37.8.2 nathanw fdfinish(fd, bp);
1407 1.37.8.2 nathanw goto loop;
1408 1.37.8.2 nathanw
1409 1.37.8.2 nathanw case COPYCOMPLETE: /* IO DONE, post-analyze */
1410 1.37.8.2 nathanw DPRINTF(("fdcintr: COPYCOMPLETE:"));
1411 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1412 1.37.8.2 nathanw if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1413 1.37.8.2 nathanw printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1414 1.37.8.2 nathanw #if 0
1415 1.37.8.2 nathanw isa_dmaabort(fdc->sc_drq);
1416 1.37.8.2 nathanw #endif
1417 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1418 1.37.8.2 nathanw "read failed" : "write failed");
1419 1.37.8.2 nathanw printf("blkno %d nblks %d\n",
1420 1.37.8.2 nathanw fd->sc_blkno, fd->sc_nblks);
1421 1.37.8.2 nathanw fdcretry(fdc);
1422 1.37.8.2 nathanw goto loop;
1423 1.37.8.2 nathanw }
1424 1.37.8.2 nathanw goto doiohalf;
1425 1.37.8.2 nathanw
1426 1.37.8.2 nathanw case DORESET:
1427 1.37.8.2 nathanw DPRINTF(("fdcintr: in DORESET\n"));
1428 1.37.8.2 nathanw /* try a reset, keep motor on */
1429 1.37.8.2 nathanw fd_set_motor(fdc, 1);
1430 1.37.8.2 nathanw DELAY(100);
1431 1.37.8.2 nathanw fd_set_motor(fdc, 0);
1432 1.37.8.2 nathanw fdc->sc_state = RESETCOMPLETE;
1433 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1434 1.37.8.2 nathanw return 1; /* will return later */
1435 1.37.8.2 nathanw
1436 1.37.8.2 nathanw case RESETCOMPLETE:
1437 1.37.8.2 nathanw DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1438 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1439 1.37.8.2 nathanw /* clear the controller output buffer */
1440 1.37.8.2 nathanw for (i = 0; i < 4; i++) {
1441 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
1442 1.37.8.2 nathanw (void) fdcresult(fdc);
1443 1.37.8.2 nathanw }
1444 1.37.8.2 nathanw
1445 1.37.8.2 nathanw /* fall through */
1446 1.37.8.2 nathanw case DORECAL:
1447 1.37.8.2 nathanw DPRINTF(("fdcintr: in DORECAL\n"));
1448 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1449 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_drive);
1450 1.37.8.2 nathanw fdc->sc_state = RECALWAIT;
1451 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1452 1.37.8.2 nathanw return 1; /* will return later */
1453 1.37.8.2 nathanw
1454 1.37.8.2 nathanw case RECALWAIT:
1455 1.37.8.2 nathanw DPRINTF(("fdcintr: in RECALWAIT\n"));
1456 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1457 1.37.8.2 nathanw fdc->sc_state = RECALCOMPLETE;
1458 1.37.8.2 nathanw /* allow 1/30 second for heads to settle */
1459 1.37.8.2 nathanw #if 0
1460 1.37.8.2 nathanw callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1461 1.37.8.2 nathanw #endif
1462 1.37.8.2 nathanw return 1; /* will return later */
1463 1.37.8.2 nathanw
1464 1.37.8.2 nathanw case RECALCOMPLETE:
1465 1.37.8.2 nathanw DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1466 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
1467 1.37.8.2 nathanw tmp = fdcresult(fdc);
1468 1.37.8.2 nathanw if ((st0 & 0xf8) == 0xc0) {
1469 1.37.8.2 nathanw DPRINTF(("fdcintr: first seek!\n"));
1470 1.37.8.2 nathanw fdc->sc_state = DORECAL;
1471 1.37.8.2 nathanw goto loop;
1472 1.37.8.2 nathanw } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1473 1.37.8.2 nathanw #ifdef FDDEBUG
1474 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1475 1.37.8.2 nathanw #endif
1476 1.37.8.2 nathanw fdcretry(fdc);
1477 1.37.8.2 nathanw goto loop;
1478 1.37.8.2 nathanw }
1479 1.37.8.2 nathanw fd->sc_cylin = 0;
1480 1.37.8.2 nathanw goto doseek;
1481 1.37.8.2 nathanw
1482 1.37.8.2 nathanw case MOTORWAIT:
1483 1.37.8.2 nathanw if (fd->sc_flags & FD_MOTOR_WAIT)
1484 1.37.8.2 nathanw return 1; /* time's not up yet */
1485 1.37.8.2 nathanw goto doseek;
1486 1.37.8.2 nathanw
1487 1.37.8.2 nathanw default:
1488 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1489 1.37.8.2 nathanw return 1;
1490 1.37.8.2 nathanw }
1491 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1492 1.37.8.2 nathanw panic("fdcintr: impossible");
1493 1.37.8.2 nathanw #endif
1494 1.37.8.2 nathanw #undef st0
1495 1.37.8.2 nathanw #undef cyl
1496 1.37.8.2 nathanw }
1497 1.37.8.2 nathanw
1498 1.37.8.2 nathanw void
1499 1.37.8.2 nathanw fdcretry(fdc)
1500 1.37.8.2 nathanw struct fdc_softc *fdc;
1501 1.37.8.2 nathanw {
1502 1.37.8.2 nathanw struct fd_softc *fd;
1503 1.37.8.2 nathanw struct buf *bp;
1504 1.37.8.2 nathanw char bits[64];
1505 1.37.8.2 nathanw
1506 1.37.8.2 nathanw DPRINTF(("fdcretry:\n"));
1507 1.37.8.2 nathanw fd = fdc->sc_drives.tqh_first;
1508 1.37.8.4 nathanw bp = BUFQ_PEEK(&fd->sc_q);
1509 1.37.8.2 nathanw
1510 1.37.8.2 nathanw switch (fdc->sc_errors) {
1511 1.37.8.2 nathanw case 0:
1512 1.37.8.2 nathanw /* try again */
1513 1.37.8.2 nathanw fdc->sc_state = SEEKCOMPLETE;
1514 1.37.8.2 nathanw break;
1515 1.37.8.2 nathanw
1516 1.37.8.2 nathanw case 1: case 2: case 3:
1517 1.37.8.2 nathanw /* didn't work; try recalibrating */
1518 1.37.8.2 nathanw fdc->sc_state = DORECAL;
1519 1.37.8.2 nathanw break;
1520 1.37.8.2 nathanw
1521 1.37.8.2 nathanw case 4:
1522 1.37.8.2 nathanw /* still no go; reset the bastard */
1523 1.37.8.2 nathanw fdc->sc_state = DORESET;
1524 1.37.8.2 nathanw break;
1525 1.37.8.2 nathanw
1526 1.37.8.2 nathanw default:
1527 1.37.8.2 nathanw diskerr(bp, "fd", "hard error", LOG_PRINTF,
1528 1.37.8.2 nathanw fd->sc_skip, (struct disklabel *)NULL);
1529 1.37.8.2 nathanw printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1530 1.37.8.2 nathanw NE7_ST0BITS, bits,
1531 1.37.8.2 nathanw sizeof(bits)));
1532 1.37.8.2 nathanw printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1533 1.37.8.2 nathanw NE7_ST1BITS, bits,
1534 1.37.8.2 nathanw sizeof(bits)));
1535 1.37.8.2 nathanw printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1536 1.37.8.2 nathanw NE7_ST2BITS, bits,
1537 1.37.8.2 nathanw sizeof(bits)));
1538 1.37.8.2 nathanw printf(" cyl %d head %d sec %d)\n",
1539 1.37.8.2 nathanw fdc->sc_status[3],
1540 1.37.8.2 nathanw fdc->sc_status[4],
1541 1.37.8.2 nathanw fdc->sc_status[5]);
1542 1.37.8.2 nathanw
1543 1.37.8.2 nathanw bp->b_flags |= B_ERROR;
1544 1.37.8.2 nathanw bp->b_error = EIO;
1545 1.37.8.2 nathanw fdfinish(fd, bp);
1546 1.37.8.2 nathanw }
1547 1.37.8.2 nathanw fdc->sc_errors++;
1548 1.37.8.2 nathanw }
1549 1.37.8.2 nathanw
1550 1.37.8.2 nathanw int
1551 1.37.8.2 nathanw fdioctl(dev, cmd, addr, flag, p)
1552 1.37.8.2 nathanw dev_t dev;
1553 1.37.8.2 nathanw u_long cmd;
1554 1.37.8.2 nathanw caddr_t addr;
1555 1.37.8.2 nathanw int flag;
1556 1.37.8.2 nathanw struct proc *p;
1557 1.37.8.2 nathanw {
1558 1.37.8.2 nathanw struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1559 1.37.8.2 nathanw struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1560 1.37.8.2 nathanw int unit = FDUNIT(dev);
1561 1.37.8.2 nathanw int part = DISKPART(dev);
1562 1.37.8.2 nathanw struct disklabel buffer;
1563 1.37.8.2 nathanw int error;
1564 1.37.8.2 nathanw
1565 1.37.8.2 nathanw DPRINTF(("fdioctl:\n"));
1566 1.37.8.2 nathanw switch (cmd) {
1567 1.37.8.2 nathanw case DIOCGDINFO:
1568 1.37.8.2 nathanw #if 1
1569 1.37.8.2 nathanw *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1570 1.37.8.2 nathanw return(0);
1571 1.37.8.2 nathanw #else
1572 1.37.8.2 nathanw memset(&buffer, 0, sizeof(buffer));
1573 1.37.8.2 nathanw
1574 1.37.8.2 nathanw buffer.d_secpercyl = fd->sc_type->seccyl;
1575 1.37.8.2 nathanw buffer.d_type = DTYPE_FLOPPY;
1576 1.37.8.2 nathanw buffer.d_secsize = 128 << fd->sc_type->secsize;
1577 1.37.8.2 nathanw
1578 1.37.8.2 nathanw if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1579 1.37.8.2 nathanw return EINVAL;
1580 1.37.8.2 nathanw
1581 1.37.8.2 nathanw *(struct disklabel *)addr = buffer;
1582 1.37.8.2 nathanw return 0;
1583 1.37.8.2 nathanw #endif
1584 1.37.8.2 nathanw
1585 1.37.8.2 nathanw case DIOCGPART:
1586 1.37.8.2 nathanw ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1587 1.37.8.2 nathanw ((struct partinfo *)addr)->part =
1588 1.37.8.2 nathanw &fd->sc_dk.dk_label->d_partitions[part];
1589 1.37.8.2 nathanw return(0);
1590 1.37.8.2 nathanw
1591 1.37.8.2 nathanw case DIOCWLABEL:
1592 1.37.8.2 nathanw if ((flag & FWRITE) == 0)
1593 1.37.8.2 nathanw return EBADF;
1594 1.37.8.2 nathanw /* XXX do something */
1595 1.37.8.2 nathanw return 0;
1596 1.37.8.2 nathanw
1597 1.37.8.2 nathanw case DIOCWDINFO:
1598 1.37.8.2 nathanw if ((flag & FWRITE) == 0)
1599 1.37.8.2 nathanw return EBADF;
1600 1.37.8.2 nathanw
1601 1.37.8.2 nathanw error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1602 1.37.8.2 nathanw if (error)
1603 1.37.8.2 nathanw return error;
1604 1.37.8.2 nathanw
1605 1.37.8.2 nathanw error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1606 1.37.8.2 nathanw return error;
1607 1.37.8.2 nathanw
1608 1.37.8.2 nathanw case DIOCLOCK:
1609 1.37.8.2 nathanw /*
1610 1.37.8.2 nathanw * Nothing to do here, really.
1611 1.37.8.2 nathanw */
1612 1.37.8.2 nathanw return 0; /* XXX */
1613 1.37.8.2 nathanw
1614 1.37.8.2 nathanw case DIOCEJECT:
1615 1.37.8.2 nathanw if (*(int *)addr == 0) {
1616 1.37.8.2 nathanw /*
1617 1.37.8.2 nathanw * Don't force eject: check that we are the only
1618 1.37.8.2 nathanw * partition open. If so, unlock it.
1619 1.37.8.2 nathanw */
1620 1.37.8.2 nathanw if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1621 1.37.8.2 nathanw fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1622 1.37.8.2 nathanw fd->sc_dk.dk_openmask) {
1623 1.37.8.2 nathanw return (EBUSY);
1624 1.37.8.2 nathanw }
1625 1.37.8.2 nathanw }
1626 1.37.8.2 nathanw /* FALLTHROUGH */
1627 1.37.8.2 nathanw case ODIOCEJECT:
1628 1.37.8.2 nathanw fd_do_eject(fdc, unit);
1629 1.37.8.2 nathanw return 0;
1630 1.37.8.2 nathanw
1631 1.37.8.2 nathanw default:
1632 1.37.8.2 nathanw return ENOTTY;
1633 1.37.8.2 nathanw }
1634 1.37.8.2 nathanw
1635 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1636 1.37.8.2 nathanw panic("fdioctl: impossible");
1637 1.37.8.2 nathanw #endif
1638 1.37.8.2 nathanw }
1639 1.37.8.2 nathanw
1640 1.37.8.2 nathanw void
1641 1.37.8.2 nathanw fd_do_eject(fdc, unit)
1642 1.37.8.2 nathanw struct fdc_softc *fdc;
1643 1.37.8.2 nathanw int unit;
1644 1.37.8.2 nathanw {
1645 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1646 1.37.8.2 nathanw 0x20 | ( 1 << unit));
1647 1.37.8.2 nathanw DELAY(1); /* XXX */
1648 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1649 1.37.8.2 nathanw }
1650 1.37.8.2 nathanw
1651 1.37.8.2 nathanw /*
1652 1.37.8.2 nathanw * Build disk label. For now we only create a label from what we know
1653 1.37.8.2 nathanw * from 'sc'.
1654 1.37.8.2 nathanw */
1655 1.37.8.2 nathanw static int
1656 1.37.8.2 nathanw fdgetdisklabel(sc, dev)
1657 1.37.8.2 nathanw struct fd_softc *sc;
1658 1.37.8.2 nathanw dev_t dev;
1659 1.37.8.2 nathanw {
1660 1.37.8.2 nathanw struct disklabel *lp;
1661 1.37.8.2 nathanw int part;
1662 1.37.8.2 nathanw
1663 1.37.8.2 nathanw DPRINTF(("fdgetdisklabel()\n"));
1664 1.37.8.2 nathanw
1665 1.37.8.2 nathanw part = DISKPART(dev);
1666 1.37.8.2 nathanw lp = sc->sc_dk.dk_label;
1667 1.37.8.2 nathanw memset(lp, 0, sizeof(struct disklabel));
1668 1.37.8.2 nathanw
1669 1.37.8.2 nathanw lp->d_secsize = 128 << sc->sc_type->secsize;
1670 1.37.8.2 nathanw lp->d_ntracks = sc->sc_type->heads;
1671 1.37.8.2 nathanw lp->d_nsectors = sc->sc_type->sectrac;
1672 1.37.8.2 nathanw lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1673 1.37.8.2 nathanw lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1674 1.37.8.2 nathanw lp->d_secperunit = sc->sc_type->size;
1675 1.37.8.2 nathanw
1676 1.37.8.2 nathanw lp->d_type = DTYPE_FLOPPY;
1677 1.37.8.2 nathanw lp->d_rpm = 300; /* XXX */
1678 1.37.8.2 nathanw lp->d_interleave = 1; /* FIXME: is this OK? */
1679 1.37.8.2 nathanw lp->d_bbsize = 0;
1680 1.37.8.2 nathanw lp->d_sbsize = 0;
1681 1.37.8.2 nathanw lp->d_npartitions = part + 1;
1682 1.37.8.2 nathanw #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1683 1.37.8.2 nathanw lp->d_trkseek = STEP_DELAY; /* XXX */
1684 1.37.8.2 nathanw lp->d_magic = DISKMAGIC;
1685 1.37.8.2 nathanw lp->d_magic2 = DISKMAGIC;
1686 1.37.8.2 nathanw lp->d_checksum = dkcksum(lp);
1687 1.37.8.2 nathanw lp->d_partitions[part].p_size = lp->d_secperunit;
1688 1.37.8.2 nathanw lp->d_partitions[part].p_fstype = FS_UNUSED;
1689 1.37.8.2 nathanw lp->d_partitions[part].p_fsize = 1024;
1690 1.37.8.2 nathanw lp->d_partitions[part].p_frag = 8;
1691 1.37.8.2 nathanw
1692 1.37.8.2 nathanw return(0);
1693 1.37.8.2 nathanw }
1694 1.37.8.2 nathanw
1695 1.37.8.2 nathanw #include <dev/cons.h>
1696 1.37.8.2 nathanw
1697 1.37.8.2 nathanw /*
1698 1.37.8.2 nathanw * Mountroot hook: prompt the user to enter the root file system
1699 1.37.8.2 nathanw * floppy.
1700 1.37.8.2 nathanw */
1701 1.37.8.2 nathanw void
1702 1.37.8.2 nathanw fd_mountroot_hook(dev)
1703 1.37.8.2 nathanw struct device *dev;
1704 1.37.8.2 nathanw {
1705 1.37.8.2 nathanw struct fd_softc *fd = (void*) dev;
1706 1.37.8.2 nathanw struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1707 1.37.8.2 nathanw int c;
1708 1.37.8.2 nathanw
1709 1.37.8.2 nathanw fd_do_eject(fdc, dev->dv_unit);
1710 1.37.8.2 nathanw printf("Insert filesystem floppy and press return.");
1711 1.37.8.2 nathanw for (;;) {
1712 1.37.8.2 nathanw c = cngetc();
1713 1.37.8.2 nathanw if ((c == '\r') || (c == '\n')) {
1714 1.37.8.2 nathanw printf("\n");
1715 1.37.8.2 nathanw break;
1716 1.37.8.2 nathanw }
1717 1.37.8.2 nathanw }
1718 1.37.8.2 nathanw }
1719