fd.c revision 1.37.8.4 1 1.37.8.4 nathanw /* $NetBSD: fd.c,v 1.37.8.4 2002/08/13 02:19:09 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 bdev_decl(fd);
171 1.37.8.2 nathanw cdev_decl(fd);
172 1.37.8.2 nathanw
173 1.37.8.2 nathanw int fdcintr __P((void*));
174 1.37.8.2 nathanw void fdcreset __P((struct fdc_softc *));
175 1.37.8.2 nathanw
176 1.37.8.2 nathanw /* controller driver configuration */
177 1.37.8.2 nathanw int fdcprobe __P((struct device *, struct cfdata *, void *));
178 1.37.8.2 nathanw void fdcattach __P((struct device *, struct device *, void *));
179 1.37.8.2 nathanw int fdprint __P((void *, const char *));
180 1.37.8.2 nathanw
181 1.37.8.2 nathanw struct cfattach fdc_ca = {
182 1.37.8.2 nathanw sizeof(struct fdc_softc), fdcprobe, fdcattach
183 1.37.8.2 nathanw };
184 1.37.8.2 nathanw
185 1.37.8.2 nathanw extern struct cfdriver fdc_cd;
186 1.37.8.2 nathanw
187 1.37.8.2 nathanw /*
188 1.37.8.2 nathanw * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
189 1.37.8.2 nathanw * we tell them apart.
190 1.37.8.2 nathanw */
191 1.37.8.2 nathanw struct fd_type {
192 1.37.8.2 nathanw int sectrac; /* sectors per track */
193 1.37.8.2 nathanw int heads; /* number of heads */
194 1.37.8.2 nathanw int seccyl; /* sectors per cylinder */
195 1.37.8.2 nathanw int secsize; /* size code for sectors */
196 1.37.8.2 nathanw int datalen; /* data len when secsize = 0 */
197 1.37.8.2 nathanw int steprate; /* step rate and head unload time */
198 1.37.8.2 nathanw int gap1; /* gap len between sectors */
199 1.37.8.2 nathanw int gap2; /* formatting gap */
200 1.37.8.2 nathanw int cyls; /* total num of cylinders */
201 1.37.8.2 nathanw int size; /* size of disk in sectors */
202 1.37.8.2 nathanw int step; /* steps per cylinder */
203 1.37.8.2 nathanw int rate; /* transfer speed code */
204 1.37.8.2 nathanw char *name;
205 1.37.8.2 nathanw };
206 1.37.8.2 nathanw
207 1.37.8.2 nathanw /* The order of entries in the following table is important -- BEWARE! */
208 1.37.8.2 nathanw struct fd_type fd_types[] = {
209 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 */
210 1.37.8.2 nathanw { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
211 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 */
212 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 */
213 1.37.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
214 1.37.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
215 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 */
216 1.37.8.2 nathanw { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
217 1.37.8.2 nathanw };
218 1.37.8.2 nathanw
219 1.37.8.2 nathanw /* software state, per disk (with up to 4 disks per ctlr) */
220 1.37.8.2 nathanw struct fd_softc {
221 1.37.8.2 nathanw struct device sc_dev;
222 1.37.8.2 nathanw struct disk sc_dk;
223 1.37.8.2 nathanw
224 1.37.8.2 nathanw struct fd_type *sc_deftype; /* default type descriptor */
225 1.37.8.2 nathanw struct fd_type *sc_type; /* current type descriptor */
226 1.37.8.2 nathanw
227 1.37.8.2 nathanw struct callout sc_motoron_ch;
228 1.37.8.2 nathanw struct callout sc_motoroff_ch;
229 1.37.8.2 nathanw
230 1.37.8.2 nathanw daddr_t sc_blkno; /* starting block number */
231 1.37.8.2 nathanw int sc_bcount; /* byte count left */
232 1.37.8.2 nathanw int sc_opts; /* user-set options */
233 1.37.8.2 nathanw int sc_skip; /* bytes already transferred */
234 1.37.8.2 nathanw int sc_nblks; /* number of blocks currently transferring */
235 1.37.8.2 nathanw int sc_nbytes; /* number of bytes currently transferring */
236 1.37.8.2 nathanw
237 1.37.8.2 nathanw int sc_drive; /* physical unit number */
238 1.37.8.2 nathanw int sc_flags;
239 1.37.8.2 nathanw #define FD_BOPEN 0x01 /* it's open */
240 1.37.8.2 nathanw #define FD_COPEN 0x02 /* it's open */
241 1.37.8.2 nathanw #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
242 1.37.8.2 nathanw #define FD_MOTOR 0x04 /* motor should be on */
243 1.37.8.2 nathanw #define FD_MOTOR_WAIT 0x08 /* motor coming up */
244 1.37.8.2 nathanw #define FD_ALIVE 0x10 /* alive */
245 1.37.8.2 nathanw int sc_cylin; /* where we think the head is */
246 1.37.8.2 nathanw
247 1.37.8.2 nathanw TAILQ_ENTRY(fd_softc) sc_drivechain;
248 1.37.8.2 nathanw int sc_ops; /* I/O ops since last switch */
249 1.37.8.4 nathanw struct bufq_state sc_q; /* pending I/O requests */
250 1.37.8.2 nathanw int sc_active; /* number of active I/O operations */
251 1.37.8.2 nathanw u_char *sc_copybuf; /* for secsize >=3 */
252 1.37.8.2 nathanw u_char sc_part; /* for secsize >=3 */
253 1.37.8.2 nathanw #define SEC_P10 0x02 /* first part */
254 1.37.8.2 nathanw #define SEC_P01 0x01 /* second part */
255 1.37.8.2 nathanw #define SEC_P11 0x03 /* both part */
256 1.37.8.2 nathanw
257 1.37.8.2 nathanw #if NRND > 0
258 1.37.8.2 nathanw rndsource_element_t rnd_source;
259 1.37.8.2 nathanw #endif
260 1.37.8.2 nathanw };
261 1.37.8.2 nathanw
262 1.37.8.2 nathanw /* floppy driver configuration */
263 1.37.8.2 nathanw int fdprobe __P((struct device *, struct cfdata *, void *));
264 1.37.8.2 nathanw void fdattach __P((struct device *, struct device *, void *));
265 1.37.8.2 nathanw
266 1.37.8.2 nathanw struct cfattach fd_ca = {
267 1.37.8.2 nathanw sizeof(struct fd_softc), fdprobe, fdattach
268 1.37.8.2 nathanw };
269 1.37.8.2 nathanw
270 1.37.8.2 nathanw extern struct cfdriver fd_cd;
271 1.37.8.2 nathanw
272 1.37.8.2 nathanw void fdstrategy __P((struct buf *));
273 1.37.8.2 nathanw void fdstart __P((struct fd_softc *fd));
274 1.37.8.2 nathanw
275 1.37.8.2 nathanw struct dkdriver fddkdriver = { fdstrategy };
276 1.37.8.2 nathanw
277 1.37.8.2 nathanw void fd_set_motor __P((struct fdc_softc *fdc, int reset));
278 1.37.8.2 nathanw void fd_motor_off __P((void *arg));
279 1.37.8.2 nathanw void fd_motor_on __P((void *arg));
280 1.37.8.2 nathanw int fdcresult __P((struct fdc_softc *fdc));
281 1.37.8.2 nathanw int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
282 1.37.8.2 nathanw void fdcstart __P((struct fdc_softc *fdc));
283 1.37.8.2 nathanw void fdcstatus __P((struct device *dv, int n, char *s));
284 1.37.8.2 nathanw void fdctimeout __P((void *arg));
285 1.37.8.2 nathanw void fdcpseudointr __P((void *arg));
286 1.37.8.2 nathanw void fdcretry __P((struct fdc_softc *fdc));
287 1.37.8.2 nathanw void fdfinish __P((struct fd_softc *fd, struct buf *bp));
288 1.37.8.2 nathanw __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
289 1.37.8.2 nathanw static int fdcpoll __P((struct fdc_softc *));
290 1.37.8.2 nathanw static int fdgetdisklabel __P((struct fd_softc *, dev_t));
291 1.37.8.2 nathanw static void fd_do_eject __P((struct fdc_softc *, int));
292 1.37.8.2 nathanw
293 1.37.8.2 nathanw void fd_mountroot_hook __P((struct device *));
294 1.37.8.2 nathanw
295 1.37.8.2 nathanw /* dma transfer routines */
296 1.37.8.2 nathanw __inline static void fdc_dmastart __P((struct fdc_softc*, int,
297 1.37.8.2 nathanw caddr_t, vsize_t));
298 1.37.8.2 nathanw static int fdcdmaintr __P((void*));
299 1.37.8.2 nathanw static int fdcdmaerrintr __P((void*));
300 1.37.8.2 nathanw
301 1.37.8.2 nathanw __inline static void
302 1.37.8.2 nathanw fdc_dmastart(fdc, read, addr, count)
303 1.37.8.2 nathanw struct fdc_softc *fdc;
304 1.37.8.2 nathanw int read;
305 1.37.8.2 nathanw caddr_t addr;
306 1.37.8.2 nathanw vsize_t count;
307 1.37.8.2 nathanw {
308 1.37.8.2 nathanw int error;
309 1.37.8.2 nathanw
310 1.37.8.3 nathanw DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %ld\n",
311 1.37.8.2 nathanw read ? "read" : "write", (caddr_t) addr, count));
312 1.37.8.2 nathanw
313 1.37.8.2 nathanw error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
314 1.37.8.2 nathanw 0, BUS_DMA_NOWAIT);
315 1.37.8.2 nathanw if (error) {
316 1.37.8.2 nathanw panic ("fdc_dmastart: cannot load dmamap");
317 1.37.8.2 nathanw }
318 1.37.8.2 nathanw
319 1.37.8.2 nathanw bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
320 1.37.8.2 nathanw read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
321 1.37.8.2 nathanw
322 1.37.8.2 nathanw fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
323 1.37.8.2 nathanw fdc->sc_dmamap,
324 1.37.8.2 nathanw (read?
325 1.37.8.2 nathanw DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
326 1.37.8.2 nathanw (DMAC_SCR_MAC_COUNT_UP|
327 1.37.8.2 nathanw DMAC_SCR_DAC_NO_COUNT),
328 1.37.8.2 nathanw (u_int8_t*) (fdc->sc_addr +
329 1.37.8.2 nathanw fddata)); /* XXX */
330 1.37.8.2 nathanw
331 1.37.8.2 nathanw dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
332 1.37.8.2 nathanw }
333 1.37.8.2 nathanw
334 1.37.8.2 nathanw static int
335 1.37.8.2 nathanw fdcdmaintr(arg)
336 1.37.8.2 nathanw void *arg;
337 1.37.8.2 nathanw {
338 1.37.8.2 nathanw struct fdc_softc *fdc = arg;
339 1.37.8.2 nathanw
340 1.37.8.2 nathanw bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
341 1.37.8.2 nathanw
342 1.37.8.2 nathanw return 0;
343 1.37.8.2 nathanw }
344 1.37.8.2 nathanw
345 1.37.8.2 nathanw static int
346 1.37.8.2 nathanw fdcdmaerrintr(dummy)
347 1.37.8.2 nathanw void *dummy;
348 1.37.8.2 nathanw {
349 1.37.8.2 nathanw DPRINTF(("fdcdmaerrintr\n"));
350 1.37.8.2 nathanw
351 1.37.8.2 nathanw return 0;
352 1.37.8.2 nathanw }
353 1.37.8.2 nathanw
354 1.37.8.2 nathanw /* ARGSUSED */
355 1.37.8.2 nathanw int
356 1.37.8.2 nathanw fdcprobe(parent, cf, aux)
357 1.37.8.2 nathanw struct device *parent;
358 1.37.8.2 nathanw struct cfdata *cf;
359 1.37.8.2 nathanw void *aux;
360 1.37.8.2 nathanw {
361 1.37.8.2 nathanw struct intio_attach_args *ia = aux;
362 1.37.8.2 nathanw
363 1.37.8.2 nathanw if (strcmp(ia->ia_name, "fdc") != 0)
364 1.37.8.2 nathanw return 0;
365 1.37.8.2 nathanw
366 1.37.8.2 nathanw if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
367 1.37.8.2 nathanw ia->ia_addr = FDC_ADDR;
368 1.37.8.2 nathanw if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
369 1.37.8.2 nathanw ia->ia_intr = FDC_INTR;
370 1.37.8.2 nathanw if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
371 1.37.8.2 nathanw ia->ia_dma = FDC_DMA;
372 1.37.8.2 nathanw if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
373 1.37.8.2 nathanw ia->ia_dmaintr = FDC_DMAINTR;
374 1.37.8.2 nathanw
375 1.37.8.2 nathanw if ((ia->ia_intr & 0x03) != 0)
376 1.37.8.2 nathanw return 0;
377 1.37.8.2 nathanw
378 1.37.8.2 nathanw ia->ia_size = 0x2000;
379 1.37.8.2 nathanw if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
380 1.37.8.2 nathanw return 0;
381 1.37.8.2 nathanw
382 1.37.8.2 nathanw /* builtin device; always there */
383 1.37.8.2 nathanw return 1;
384 1.37.8.2 nathanw }
385 1.37.8.2 nathanw
386 1.37.8.2 nathanw /*
387 1.37.8.2 nathanw * Arguments passed between fdcattach and fdprobe.
388 1.37.8.2 nathanw */
389 1.37.8.2 nathanw struct fdc_attach_args {
390 1.37.8.2 nathanw int fa_drive;
391 1.37.8.2 nathanw struct fd_type *fa_deftype;
392 1.37.8.2 nathanw };
393 1.37.8.2 nathanw
394 1.37.8.2 nathanw /*
395 1.37.8.2 nathanw * Print the location of a disk drive (called just before attaching the
396 1.37.8.2 nathanw * the drive). If `fdc' is not NULL, the drive was found but was not
397 1.37.8.2 nathanw * in the system config file; print the drive name as well.
398 1.37.8.2 nathanw * Return QUIET (config_find ignores this if the device was configured) to
399 1.37.8.2 nathanw * avoid printing `fdN not configured' messages.
400 1.37.8.2 nathanw */
401 1.37.8.2 nathanw int
402 1.37.8.2 nathanw fdprint(aux, fdc)
403 1.37.8.2 nathanw void *aux;
404 1.37.8.2 nathanw const char *fdc;
405 1.37.8.2 nathanw {
406 1.37.8.2 nathanw register struct fdc_attach_args *fa = aux;
407 1.37.8.2 nathanw
408 1.37.8.2 nathanw if (!fdc)
409 1.37.8.2 nathanw printf(" drive %d", fa->fa_drive);
410 1.37.8.2 nathanw return QUIET;
411 1.37.8.2 nathanw }
412 1.37.8.2 nathanw
413 1.37.8.2 nathanw void
414 1.37.8.2 nathanw fdcattach(parent, self, aux)
415 1.37.8.2 nathanw struct device *parent, *self;
416 1.37.8.2 nathanw void *aux;
417 1.37.8.2 nathanw {
418 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)self;
419 1.37.8.2 nathanw bus_space_tag_t iot;
420 1.37.8.2 nathanw bus_space_handle_t ioh;
421 1.37.8.2 nathanw struct intio_attach_args *ia = aux;
422 1.37.8.2 nathanw struct fdc_attach_args fa;
423 1.37.8.2 nathanw
424 1.37.8.2 nathanw iot = ia->ia_bst;
425 1.37.8.2 nathanw
426 1.37.8.2 nathanw printf("\n");
427 1.37.8.2 nathanw
428 1.37.8.2 nathanw callout_init(&fdc->sc_timo_ch);
429 1.37.8.2 nathanw callout_init(&fdc->sc_intr_ch);
430 1.37.8.2 nathanw
431 1.37.8.2 nathanw /* Re-map the I/O space. */
432 1.37.8.2 nathanw bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
433 1.37.8.2 nathanw
434 1.37.8.2 nathanw fdc->sc_iot = iot;
435 1.37.8.2 nathanw fdc->sc_ioh = ioh;
436 1.37.8.2 nathanw fdc->sc_addr = (void*) ia->ia_addr;
437 1.37.8.2 nathanw
438 1.37.8.2 nathanw fdc->sc_dmat = ia->ia_dmat;
439 1.37.8.2 nathanw fdc->sc_state = DEVIDLE;
440 1.37.8.2 nathanw TAILQ_INIT(&fdc->sc_drives);
441 1.37.8.2 nathanw
442 1.37.8.2 nathanw /* Initialize DMAC channel */
443 1.37.8.2 nathanw fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
444 1.37.8.2 nathanw ia->ia_dmaintr, fdcdmaintr, fdc,
445 1.37.8.2 nathanw ia->ia_dmaintr+1, fdcdmaerrintr,
446 1.37.8.2 nathanw fdc);
447 1.37.8.2 nathanw if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
448 1.37.8.2 nathanw 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
449 1.37.8.2 nathanw &fdc->sc_dmamap)) {
450 1.37.8.2 nathanw printf("%s: can't set up intio DMA map\n",
451 1.37.8.2 nathanw fdc->sc_dev.dv_xname);
452 1.37.8.2 nathanw return;
453 1.37.8.2 nathanw }
454 1.37.8.2 nathanw
455 1.37.8.2 nathanw if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
456 1.37.8.2 nathanw panic ("Could not establish interrupt (duplicated vector?).");
457 1.37.8.2 nathanw intio_set_ivec(ia->ia_intr);
458 1.37.8.2 nathanw
459 1.37.8.2 nathanw /* reset */
460 1.37.8.2 nathanw intio_disable_intr(SICILIAN_INTR_FDD);
461 1.37.8.2 nathanw intio_enable_intr(SICILIAN_INTR_FDC);
462 1.37.8.2 nathanw fdcresult(fdc);
463 1.37.8.2 nathanw fdcreset(fdc);
464 1.37.8.2 nathanw
465 1.37.8.2 nathanw printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
466 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
467 1.37.8.2 nathanw out_fdc(iot, ioh, 0xd0);
468 1.37.8.2 nathanw out_fdc(iot, ioh, 0x10);
469 1.37.8.2 nathanw
470 1.37.8.2 nathanw /* physical limit: four drives per controller. */
471 1.37.8.2 nathanw for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
472 1.37.8.2 nathanw (void)config_found(self, (void *)&fa, fdprint);
473 1.37.8.2 nathanw }
474 1.37.8.2 nathanw
475 1.37.8.2 nathanw intio_enable_intr(SICILIAN_INTR_FDC);
476 1.37.8.2 nathanw }
477 1.37.8.2 nathanw
478 1.37.8.2 nathanw void
479 1.37.8.2 nathanw fdcreset(fdc)
480 1.37.8.2 nathanw struct fdc_softc *fdc;
481 1.37.8.2 nathanw {
482 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
483 1.37.8.2 nathanw }
484 1.37.8.2 nathanw
485 1.37.8.2 nathanw static int
486 1.37.8.2 nathanw fdcpoll(fdc)
487 1.37.8.2 nathanw struct fdc_softc *fdc;
488 1.37.8.2 nathanw {
489 1.37.8.2 nathanw int i = 25000, n;
490 1.37.8.2 nathanw while (--i > 0) {
491 1.37.8.2 nathanw if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
492 1.37.8.2 nathanw out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
493 1.37.8.2 nathanw n = fdcresult(fdc);
494 1.37.8.2 nathanw break;
495 1.37.8.2 nathanw }
496 1.37.8.2 nathanw DELAY(100);
497 1.37.8.2 nathanw }
498 1.37.8.2 nathanw return i;
499 1.37.8.2 nathanw }
500 1.37.8.2 nathanw
501 1.37.8.2 nathanw int
502 1.37.8.2 nathanw fdprobe(parent, cf, aux)
503 1.37.8.2 nathanw struct device *parent;
504 1.37.8.2 nathanw struct cfdata *cf;
505 1.37.8.2 nathanw void *aux;
506 1.37.8.2 nathanw {
507 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)parent;
508 1.37.8.2 nathanw struct fd_type *type;
509 1.37.8.2 nathanw struct fdc_attach_args *fa = aux;
510 1.37.8.2 nathanw int drive = fa->fa_drive;
511 1.37.8.2 nathanw bus_space_tag_t iot = fdc->sc_iot;
512 1.37.8.2 nathanw bus_space_handle_t ioh = fdc->sc_ioh;
513 1.37.8.2 nathanw int n;
514 1.37.8.2 nathanw int found = 0;
515 1.37.8.2 nathanw int i;
516 1.37.8.2 nathanw
517 1.37.8.2 nathanw if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
518 1.37.8.2 nathanw cf->cf_loc[FDCCF_UNIT] != drive)
519 1.37.8.2 nathanw return 0;
520 1.37.8.2 nathanw
521 1.37.8.2 nathanw type = &fd_types[0]; /* XXX 1.2MB */
522 1.37.8.2 nathanw
523 1.37.8.2 nathanw intio_disable_intr(SICILIAN_INTR_FDC);
524 1.37.8.2 nathanw
525 1.37.8.2 nathanw /* select drive and turn on motor */
526 1.37.8.2 nathanw bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
527 1.37.8.2 nathanw fdc_force_ready(FDCRDY);
528 1.37.8.2 nathanw fdcpoll(fdc);
529 1.37.8.2 nathanw
530 1.37.8.2 nathanw retry:
531 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_RECAL);
532 1.37.8.2 nathanw out_fdc(iot, ioh, drive);
533 1.37.8.2 nathanw
534 1.37.8.2 nathanw i = 25000;
535 1.37.8.2 nathanw while (--i > 0) {
536 1.37.8.2 nathanw if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
537 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
538 1.37.8.2 nathanw n = fdcresult(fdc);
539 1.37.8.2 nathanw break;
540 1.37.8.2 nathanw }
541 1.37.8.2 nathanw DELAY(100);
542 1.37.8.2 nathanw }
543 1.37.8.2 nathanw
544 1.37.8.2 nathanw #ifdef FDDEBUG
545 1.37.8.2 nathanw {
546 1.37.8.2 nathanw int i;
547 1.37.8.2 nathanw DPRINTF(("fdprobe: status"));
548 1.37.8.2 nathanw for (i = 0; i < n; i++)
549 1.37.8.2 nathanw DPRINTF((" %x", fdc->sc_status[i]));
550 1.37.8.2 nathanw DPRINTF(("\n"));
551 1.37.8.2 nathanw }
552 1.37.8.2 nathanw #endif
553 1.37.8.2 nathanw
554 1.37.8.2 nathanw if (n == 2) {
555 1.37.8.2 nathanw if ((fdc->sc_status[0] & 0xf0) == 0x20) {
556 1.37.8.2 nathanw found = 1;
557 1.37.8.2 nathanw } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
558 1.37.8.2 nathanw goto retry;
559 1.37.8.2 nathanw }
560 1.37.8.2 nathanw }
561 1.37.8.2 nathanw
562 1.37.8.2 nathanw /* turn off motor */
563 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
564 1.37.8.2 nathanw fdctl, (type->rate << 4)| drive);
565 1.37.8.2 nathanw fdc_force_ready(FDCSTBY);
566 1.37.8.2 nathanw if (!found) {
567 1.37.8.2 nathanw intio_enable_intr(SICILIAN_INTR_FDC);
568 1.37.8.2 nathanw return 0;
569 1.37.8.2 nathanw }
570 1.37.8.2 nathanw
571 1.37.8.2 nathanw return 1;
572 1.37.8.2 nathanw }
573 1.37.8.2 nathanw
574 1.37.8.2 nathanw /*
575 1.37.8.2 nathanw * Controller is working, and drive responded. Attach it.
576 1.37.8.2 nathanw */
577 1.37.8.2 nathanw void
578 1.37.8.2 nathanw fdattach(parent, self, aux)
579 1.37.8.2 nathanw struct device *parent, *self;
580 1.37.8.2 nathanw void *aux;
581 1.37.8.2 nathanw {
582 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)parent;
583 1.37.8.2 nathanw struct fd_softc *fd = (void *)self;
584 1.37.8.2 nathanw struct fdc_attach_args *fa = aux;
585 1.37.8.2 nathanw struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
586 1.37.8.2 nathanw int drive = fa->fa_drive;
587 1.37.8.2 nathanw
588 1.37.8.2 nathanw callout_init(&fd->sc_motoron_ch);
589 1.37.8.2 nathanw callout_init(&fd->sc_motoroff_ch);
590 1.37.8.2 nathanw
591 1.37.8.2 nathanw fd->sc_flags = 0;
592 1.37.8.2 nathanw
593 1.37.8.2 nathanw if (type)
594 1.37.8.2 nathanw printf(": %s, %d cyl, %d head, %d sec\n", type->name,
595 1.37.8.2 nathanw type->cyls, type->heads, type->sectrac);
596 1.37.8.2 nathanw else
597 1.37.8.2 nathanw printf(": density unknown\n");
598 1.37.8.2 nathanw
599 1.37.8.4 nathanw bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
600 1.37.8.2 nathanw fd->sc_cylin = -1;
601 1.37.8.2 nathanw fd->sc_drive = drive;
602 1.37.8.2 nathanw fd->sc_deftype = type;
603 1.37.8.2 nathanw fdc->sc_fd[drive] = fd;
604 1.37.8.2 nathanw
605 1.37.8.2 nathanw fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
606 1.37.8.2 nathanw if (fd->sc_copybuf == 0)
607 1.37.8.2 nathanw printf("fdprobe: WARNING!! malloc() failed.\n");
608 1.37.8.2 nathanw fd->sc_flags |= FD_ALIVE;
609 1.37.8.2 nathanw
610 1.37.8.2 nathanw /*
611 1.37.8.2 nathanw * Initialize and attach the disk structure.
612 1.37.8.2 nathanw */
613 1.37.8.2 nathanw fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
614 1.37.8.2 nathanw fd->sc_dk.dk_driver = &fddkdriver;
615 1.37.8.2 nathanw disk_attach(&fd->sc_dk);
616 1.37.8.2 nathanw
617 1.37.8.2 nathanw /*
618 1.37.8.2 nathanw * Establish a mountroot_hook anyway in case we booted
619 1.37.8.2 nathanw * with RB_ASKNAME and get selected as the boot device.
620 1.37.8.2 nathanw */
621 1.37.8.2 nathanw mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
622 1.37.8.2 nathanw
623 1.37.8.2 nathanw #if NRND > 0
624 1.37.8.2 nathanw rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
625 1.37.8.2 nathanw RND_TYPE_DISK, 0);
626 1.37.8.2 nathanw #endif
627 1.37.8.2 nathanw }
628 1.37.8.2 nathanw
629 1.37.8.2 nathanw __inline struct fd_type *
630 1.37.8.2 nathanw fd_dev_to_type(fd, dev)
631 1.37.8.2 nathanw struct fd_softc *fd;
632 1.37.8.2 nathanw dev_t dev;
633 1.37.8.2 nathanw {
634 1.37.8.2 nathanw int type = FDTYPE(dev);
635 1.37.8.2 nathanw
636 1.37.8.2 nathanw if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
637 1.37.8.2 nathanw return NULL;
638 1.37.8.2 nathanw return &fd_types[type];
639 1.37.8.2 nathanw }
640 1.37.8.2 nathanw
641 1.37.8.2 nathanw void
642 1.37.8.2 nathanw fdstrategy(bp)
643 1.37.8.2 nathanw register struct buf *bp; /* IO operation to perform */
644 1.37.8.2 nathanw {
645 1.37.8.2 nathanw struct fd_softc *fd;
646 1.37.8.2 nathanw int unit = FDUNIT(bp->b_dev);
647 1.37.8.2 nathanw int sz;
648 1.37.8.2 nathanw int s;
649 1.37.8.2 nathanw
650 1.37.8.2 nathanw if (unit >= fd_cd.cd_ndevs ||
651 1.37.8.2 nathanw (fd = fd_cd.cd_devs[unit]) == 0 ||
652 1.37.8.2 nathanw bp->b_blkno < 0 ||
653 1.37.8.2 nathanw (bp->b_bcount % FDC_BSIZE) != 0) {
654 1.37.8.3 nathanw DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%ld\n", unit,
655 1.37.8.2 nathanw bp->b_blkno, bp->b_bcount));
656 1.37.8.2 nathanw bp->b_error = EINVAL;
657 1.37.8.2 nathanw goto bad;
658 1.37.8.2 nathanw }
659 1.37.8.2 nathanw
660 1.37.8.2 nathanw /* If it's a null transfer, return immediately. */
661 1.37.8.2 nathanw if (bp->b_bcount == 0)
662 1.37.8.2 nathanw goto done;
663 1.37.8.2 nathanw
664 1.37.8.2 nathanw sz = howmany(bp->b_bcount, FDC_BSIZE);
665 1.37.8.2 nathanw
666 1.37.8.2 nathanw if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
667 1.37.8.2 nathanw sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
668 1.37.8.2 nathanw if (sz == 0) {
669 1.37.8.2 nathanw /* If exactly at end of disk, return EOF. */
670 1.37.8.2 nathanw bp->b_resid = bp->b_bcount;
671 1.37.8.2 nathanw goto done;
672 1.37.8.2 nathanw }
673 1.37.8.2 nathanw if (sz < 0) {
674 1.37.8.2 nathanw /* If past end of disk, return EINVAL. */
675 1.37.8.2 nathanw bp->b_error = EINVAL;
676 1.37.8.2 nathanw goto bad;
677 1.37.8.2 nathanw }
678 1.37.8.2 nathanw /* Otherwise, truncate request. */
679 1.37.8.2 nathanw bp->b_bcount = sz << DEV_BSHIFT;
680 1.37.8.2 nathanw }
681 1.37.8.2 nathanw
682 1.37.8.2 nathanw bp->b_rawblkno = bp->b_blkno;
683 1.37.8.2 nathanw bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
684 1.37.8.2 nathanw / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
685 1.37.8.2 nathanw
686 1.37.8.2 nathanw DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
687 1.37.8.2 nathanw bp->b_flags & B_READ ? "read" : "write",
688 1.37.8.2 nathanw bp->b_blkno, bp->b_bcount, bp->b_cylinder));
689 1.37.8.2 nathanw /* Queue transfer on drive, activate drive and controller if idle. */
690 1.37.8.2 nathanw s = splbio();
691 1.37.8.4 nathanw BUFQ_PUT(&fd->sc_q, bp);
692 1.37.8.2 nathanw callout_stop(&fd->sc_motoroff_ch); /* a good idea */
693 1.37.8.2 nathanw if (fd->sc_active == 0)
694 1.37.8.2 nathanw fdstart(fd);
695 1.37.8.2 nathanw #ifdef DIAGNOSTIC
696 1.37.8.2 nathanw else {
697 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
698 1.37.8.2 nathanw if (fdc->sc_state == DEVIDLE) {
699 1.37.8.2 nathanw printf("fdstrategy: controller inactive\n");
700 1.37.8.2 nathanw fdcstart(fdc);
701 1.37.8.2 nathanw }
702 1.37.8.2 nathanw }
703 1.37.8.2 nathanw #endif
704 1.37.8.2 nathanw splx(s);
705 1.37.8.2 nathanw return;
706 1.37.8.2 nathanw
707 1.37.8.2 nathanw bad:
708 1.37.8.2 nathanw bp->b_flags |= B_ERROR;
709 1.37.8.2 nathanw done:
710 1.37.8.2 nathanw /* Toss transfer; we're done early. */
711 1.37.8.2 nathanw biodone(bp);
712 1.37.8.2 nathanw }
713 1.37.8.2 nathanw
714 1.37.8.2 nathanw void
715 1.37.8.2 nathanw fdstart(fd)
716 1.37.8.2 nathanw struct fd_softc *fd;
717 1.37.8.2 nathanw {
718 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
719 1.37.8.2 nathanw int active = fdc->sc_drives.tqh_first != 0;
720 1.37.8.2 nathanw
721 1.37.8.2 nathanw /* Link into controller queue. */
722 1.37.8.2 nathanw fd->sc_active = 1;
723 1.37.8.2 nathanw TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
724 1.37.8.2 nathanw
725 1.37.8.2 nathanw /* If controller not already active, start it. */
726 1.37.8.2 nathanw if (!active)
727 1.37.8.2 nathanw fdcstart(fdc);
728 1.37.8.2 nathanw }
729 1.37.8.2 nathanw
730 1.37.8.2 nathanw void
731 1.37.8.2 nathanw fdfinish(fd, bp)
732 1.37.8.2 nathanw struct fd_softc *fd;
733 1.37.8.2 nathanw struct buf *bp;
734 1.37.8.2 nathanw {
735 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
736 1.37.8.2 nathanw
737 1.37.8.2 nathanw /*
738 1.37.8.2 nathanw * Move this drive to the end of the queue to give others a `fair'
739 1.37.8.2 nathanw * chance. We only force a switch if N operations are completed while
740 1.37.8.2 nathanw * another drive is waiting to be serviced, since there is a long motor
741 1.37.8.2 nathanw * startup delay whenever we switch.
742 1.37.8.2 nathanw */
743 1.37.8.4 nathanw (void)BUFQ_GET(&fd->sc_q);
744 1.37.8.2 nathanw if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
745 1.37.8.2 nathanw fd->sc_ops = 0;
746 1.37.8.2 nathanw TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
747 1.37.8.4 nathanw if (BUFQ_PEEK(&fd->sc_q) != NULL) {
748 1.37.8.2 nathanw TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
749 1.37.8.2 nathanw } else
750 1.37.8.2 nathanw fd->sc_active = 0;
751 1.37.8.2 nathanw }
752 1.37.8.2 nathanw bp->b_resid = fd->sc_bcount;
753 1.37.8.2 nathanw fd->sc_skip = 0;
754 1.37.8.2 nathanw
755 1.37.8.2 nathanw #if NRND > 0
756 1.37.8.2 nathanw rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
757 1.37.8.2 nathanw #endif
758 1.37.8.2 nathanw
759 1.37.8.2 nathanw biodone(bp);
760 1.37.8.2 nathanw /* turn off motor 5s from now */
761 1.37.8.2 nathanw callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
762 1.37.8.2 nathanw fdc->sc_state = DEVIDLE;
763 1.37.8.2 nathanw }
764 1.37.8.2 nathanw
765 1.37.8.2 nathanw int
766 1.37.8.2 nathanw fdread(dev, uio, flags)
767 1.37.8.2 nathanw dev_t dev;
768 1.37.8.2 nathanw struct uio *uio;
769 1.37.8.2 nathanw int flags;
770 1.37.8.2 nathanw {
771 1.37.8.2 nathanw
772 1.37.8.2 nathanw return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
773 1.37.8.2 nathanw }
774 1.37.8.2 nathanw
775 1.37.8.2 nathanw int
776 1.37.8.2 nathanw fdwrite(dev, uio, flags)
777 1.37.8.2 nathanw dev_t dev;
778 1.37.8.2 nathanw struct uio *uio;
779 1.37.8.2 nathanw int flags;
780 1.37.8.2 nathanw {
781 1.37.8.2 nathanw
782 1.37.8.2 nathanw return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
783 1.37.8.2 nathanw }
784 1.37.8.2 nathanw
785 1.37.8.2 nathanw void
786 1.37.8.2 nathanw fd_set_motor(fdc, reset)
787 1.37.8.2 nathanw struct fdc_softc *fdc;
788 1.37.8.2 nathanw int reset;
789 1.37.8.2 nathanw {
790 1.37.8.2 nathanw struct fd_softc *fd;
791 1.37.8.2 nathanw int n;
792 1.37.8.2 nathanw
793 1.37.8.2 nathanw DPRINTF(("fd_set_motor:\n"));
794 1.37.8.2 nathanw for (n = 0; n < 4; n++)
795 1.37.8.2 nathanw if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
796 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
797 1.37.8.2 nathanw 0x80 | (fd->sc_type->rate << 4)| n);
798 1.37.8.2 nathanw }
799 1.37.8.2 nathanw }
800 1.37.8.2 nathanw
801 1.37.8.2 nathanw void
802 1.37.8.2 nathanw fd_motor_off(arg)
803 1.37.8.2 nathanw void *arg;
804 1.37.8.2 nathanw {
805 1.37.8.2 nathanw struct fd_softc *fd = arg;
806 1.37.8.2 nathanw struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
807 1.37.8.2 nathanw int s;
808 1.37.8.2 nathanw
809 1.37.8.2 nathanw DPRINTF(("fd_motor_off:\n"));
810 1.37.8.2 nathanw
811 1.37.8.2 nathanw s = splbio();
812 1.37.8.2 nathanw fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
813 1.37.8.2 nathanw bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
814 1.37.8.2 nathanw (fd->sc_type->rate << 4) | fd->sc_drive);
815 1.37.8.2 nathanw #if 0
816 1.37.8.2 nathanw fd_set_motor(fdc, 0); /* XXX */
817 1.37.8.2 nathanw #endif
818 1.37.8.2 nathanw splx(s);
819 1.37.8.2 nathanw }
820 1.37.8.2 nathanw
821 1.37.8.2 nathanw void
822 1.37.8.2 nathanw fd_motor_on(arg)
823 1.37.8.2 nathanw void *arg;
824 1.37.8.2 nathanw {
825 1.37.8.2 nathanw struct fd_softc *fd = arg;
826 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
827 1.37.8.2 nathanw int s;
828 1.37.8.2 nathanw
829 1.37.8.2 nathanw DPRINTF(("fd_motor_on:\n"));
830 1.37.8.2 nathanw
831 1.37.8.2 nathanw s = splbio();
832 1.37.8.2 nathanw fd->sc_flags &= ~FD_MOTOR_WAIT;
833 1.37.8.2 nathanw if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
834 1.37.8.2 nathanw (void) fdcintr(fdc);
835 1.37.8.2 nathanw splx(s);
836 1.37.8.2 nathanw }
837 1.37.8.2 nathanw
838 1.37.8.2 nathanw int
839 1.37.8.2 nathanw fdcresult(fdc)
840 1.37.8.2 nathanw struct fdc_softc *fdc;
841 1.37.8.2 nathanw {
842 1.37.8.2 nathanw bus_space_tag_t iot = fdc->sc_iot;
843 1.37.8.2 nathanw bus_space_handle_t ioh = fdc->sc_ioh;
844 1.37.8.2 nathanw u_char i;
845 1.37.8.2 nathanw int j = 100000,
846 1.37.8.2 nathanw n = 0;
847 1.37.8.2 nathanw
848 1.37.8.2 nathanw for (; j; j--) {
849 1.37.8.2 nathanw i = bus_space_read_1(iot, ioh, fdsts) &
850 1.37.8.2 nathanw (NE7_DIO | NE7_RQM | NE7_CB);
851 1.37.8.2 nathanw
852 1.37.8.2 nathanw if (i == NE7_RQM)
853 1.37.8.2 nathanw return n;
854 1.37.8.2 nathanw if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
855 1.37.8.2 nathanw if (n >= sizeof(fdc->sc_status)) {
856 1.37.8.2 nathanw log(LOG_ERR, "fdcresult: overrun\n");
857 1.37.8.2 nathanw return -1;
858 1.37.8.2 nathanw }
859 1.37.8.2 nathanw fdc->sc_status[n++] =
860 1.37.8.2 nathanw bus_space_read_1(iot, ioh, fddata);
861 1.37.8.2 nathanw }
862 1.37.8.2 nathanw delay(10);
863 1.37.8.2 nathanw }
864 1.37.8.2 nathanw log(LOG_ERR, "fdcresult: timeout\n");
865 1.37.8.2 nathanw return -1;
866 1.37.8.2 nathanw }
867 1.37.8.2 nathanw
868 1.37.8.2 nathanw int
869 1.37.8.2 nathanw out_fdc(iot, ioh, x)
870 1.37.8.2 nathanw bus_space_tag_t iot;
871 1.37.8.2 nathanw bus_space_handle_t ioh;
872 1.37.8.2 nathanw u_char x;
873 1.37.8.2 nathanw {
874 1.37.8.2 nathanw int i = 100000;
875 1.37.8.2 nathanw
876 1.37.8.2 nathanw while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
877 1.37.8.2 nathanw if (i <= 0)
878 1.37.8.2 nathanw return -1;
879 1.37.8.2 nathanw while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
880 1.37.8.2 nathanw if (i <= 0)
881 1.37.8.2 nathanw return -1;
882 1.37.8.2 nathanw bus_space_write_1(iot, ioh, fddata, x);
883 1.37.8.2 nathanw return 0;
884 1.37.8.2 nathanw }
885 1.37.8.2 nathanw
886 1.37.8.2 nathanw int
887 1.37.8.2 nathanw fdopen(dev, flags, mode, p)
888 1.37.8.2 nathanw dev_t dev;
889 1.37.8.2 nathanw int flags, mode;
890 1.37.8.2 nathanw struct proc *p;
891 1.37.8.2 nathanw {
892 1.37.8.2 nathanw int unit;
893 1.37.8.2 nathanw struct fd_softc *fd;
894 1.37.8.2 nathanw struct fd_type *type;
895 1.37.8.2 nathanw struct fdc_softc *fdc;
896 1.37.8.2 nathanw
897 1.37.8.2 nathanw unit = FDUNIT(dev);
898 1.37.8.2 nathanw if (unit >= fd_cd.cd_ndevs)
899 1.37.8.2 nathanw return ENXIO;
900 1.37.8.2 nathanw fd = fd_cd.cd_devs[unit];
901 1.37.8.2 nathanw if (fd == 0)
902 1.37.8.2 nathanw return ENXIO;
903 1.37.8.2 nathanw type = fd_dev_to_type(fd, dev);
904 1.37.8.2 nathanw if (type == NULL)
905 1.37.8.2 nathanw return ENXIO;
906 1.37.8.2 nathanw
907 1.37.8.2 nathanw if ((fd->sc_flags & FD_OPEN) != 0 &&
908 1.37.8.2 nathanw fd->sc_type != type)
909 1.37.8.2 nathanw return EBUSY;
910 1.37.8.2 nathanw
911 1.37.8.2 nathanw fdc = (void *)fd->sc_dev.dv_parent;
912 1.37.8.2 nathanw if ((fd->sc_flags & FD_OPEN) == 0) {
913 1.37.8.2 nathanw /* Lock eject button */
914 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
915 1.37.8.2 nathanw 0x40 | ( 1 << unit));
916 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
917 1.37.8.2 nathanw }
918 1.37.8.2 nathanw
919 1.37.8.2 nathanw fd->sc_type = type;
920 1.37.8.2 nathanw fd->sc_cylin = -1;
921 1.37.8.2 nathanw
922 1.37.8.2 nathanw switch (mode) {
923 1.37.8.2 nathanw case S_IFCHR:
924 1.37.8.2 nathanw fd->sc_flags |= FD_COPEN;
925 1.37.8.2 nathanw break;
926 1.37.8.2 nathanw case S_IFBLK:
927 1.37.8.2 nathanw fd->sc_flags |= FD_BOPEN;
928 1.37.8.2 nathanw break;
929 1.37.8.2 nathanw }
930 1.37.8.2 nathanw
931 1.37.8.2 nathanw fdgetdisklabel(fd, dev);
932 1.37.8.2 nathanw
933 1.37.8.2 nathanw return 0;
934 1.37.8.2 nathanw }
935 1.37.8.2 nathanw
936 1.37.8.2 nathanw int
937 1.37.8.2 nathanw fdclose(dev, flags, mode, p)
938 1.37.8.2 nathanw dev_t dev;
939 1.37.8.2 nathanw int flags, mode;
940 1.37.8.2 nathanw struct proc *p;
941 1.37.8.2 nathanw {
942 1.37.8.2 nathanw int unit = FDUNIT(dev);
943 1.37.8.2 nathanw struct fd_softc *fd = fd_cd.cd_devs[unit];
944 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
945 1.37.8.2 nathanw
946 1.37.8.2 nathanw DPRINTF(("fdclose %d\n", unit));
947 1.37.8.2 nathanw
948 1.37.8.2 nathanw switch (mode) {
949 1.37.8.2 nathanw case S_IFCHR:
950 1.37.8.2 nathanw fd->sc_flags &= ~FD_COPEN;
951 1.37.8.2 nathanw break;
952 1.37.8.2 nathanw case S_IFBLK:
953 1.37.8.2 nathanw fd->sc_flags &= ~FD_BOPEN;
954 1.37.8.2 nathanw break;
955 1.37.8.2 nathanw }
956 1.37.8.2 nathanw
957 1.37.8.2 nathanw if ((fd->sc_flags & FD_OPEN) == 0) {
958 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
959 1.37.8.2 nathanw ( 1 << unit));
960 1.37.8.2 nathanw bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
961 1.37.8.2 nathanw }
962 1.37.8.2 nathanw return 0;
963 1.37.8.2 nathanw }
964 1.37.8.2 nathanw
965 1.37.8.2 nathanw void
966 1.37.8.2 nathanw fdcstart(fdc)
967 1.37.8.2 nathanw struct fdc_softc *fdc;
968 1.37.8.2 nathanw {
969 1.37.8.2 nathanw
970 1.37.8.2 nathanw #ifdef DIAGNOSTIC
971 1.37.8.2 nathanw /* only got here if controller's drive queue was inactive; should
972 1.37.8.2 nathanw be in idle state */
973 1.37.8.2 nathanw if (fdc->sc_state != DEVIDLE) {
974 1.37.8.2 nathanw printf("fdcstart: not idle\n");
975 1.37.8.2 nathanw return;
976 1.37.8.2 nathanw }
977 1.37.8.2 nathanw #endif
978 1.37.8.2 nathanw (void) fdcintr(fdc);
979 1.37.8.2 nathanw }
980 1.37.8.2 nathanw
981 1.37.8.2 nathanw void
982 1.37.8.2 nathanw fdcstatus(dv, n, s)
983 1.37.8.2 nathanw struct device *dv;
984 1.37.8.2 nathanw int n;
985 1.37.8.2 nathanw char *s;
986 1.37.8.2 nathanw {
987 1.37.8.2 nathanw struct fdc_softc *fdc = (void *)dv->dv_parent;
988 1.37.8.2 nathanw char bits[64];
989 1.37.8.2 nathanw
990 1.37.8.2 nathanw if (n == 0) {
991 1.37.8.2 nathanw out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
992 1.37.8.2 nathanw (void) fdcresult(fdc);
993 1.37.8.2 nathanw n = 2;
994 1.37.8.2 nathanw }
995 1.37.8.2 nathanw
996 1.37.8.2 nathanw printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
997 1.37.8.2 nathanw
998 1.37.8.2 nathanw switch (n) {
999 1.37.8.2 nathanw case 0:
1000 1.37.8.2 nathanw printf("\n");
1001 1.37.8.2 nathanw break;
1002 1.37.8.2 nathanw case 2:
1003 1.37.8.2 nathanw printf(" (st0 %s cyl %d)\n",
1004 1.37.8.2 nathanw bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
1005 1.37.8.2 nathanw bits, sizeof(bits)), fdc->sc_status[1]);
1006 1.37.8.2 nathanw break;
1007 1.37.8.2 nathanw case 7:
1008 1.37.8.2 nathanw printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1009 1.37.8.2 nathanw NE7_ST0BITS, bits, sizeof(bits)));
1010 1.37.8.2 nathanw printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1011 1.37.8.2 nathanw NE7_ST1BITS, bits, sizeof(bits)));
1012 1.37.8.2 nathanw printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1013 1.37.8.2 nathanw NE7_ST2BITS, bits, sizeof(bits)));
1014 1.37.8.2 nathanw printf(" cyl %d head %d sec %d)\n",
1015 1.37.8.2 nathanw fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1016 1.37.8.2 nathanw break;
1017 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1018 1.37.8.2 nathanw default:
1019 1.37.8.2 nathanw printf(" fdcstatus: weird size: %d\n", n);
1020 1.37.8.2 nathanw break;
1021 1.37.8.2 nathanw #endif
1022 1.37.8.2 nathanw }
1023 1.37.8.2 nathanw }
1024 1.37.8.2 nathanw
1025 1.37.8.2 nathanw void
1026 1.37.8.2 nathanw fdctimeout(arg)
1027 1.37.8.2 nathanw void *arg;
1028 1.37.8.2 nathanw {
1029 1.37.8.2 nathanw struct fdc_softc *fdc = arg;
1030 1.37.8.2 nathanw struct fd_softc *fd = fdc->sc_drives.tqh_first;
1031 1.37.8.2 nathanw int s;
1032 1.37.8.2 nathanw
1033 1.37.8.2 nathanw s = splbio();
1034 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 0, "timeout");
1035 1.37.8.2 nathanw
1036 1.37.8.4 nathanw if (BUFQ_PEEK(&fd->sc_q) != NULL)
1037 1.37.8.2 nathanw fdc->sc_state++;
1038 1.37.8.2 nathanw else
1039 1.37.8.2 nathanw fdc->sc_state = DEVIDLE;
1040 1.37.8.2 nathanw
1041 1.37.8.2 nathanw (void) fdcintr(fdc);
1042 1.37.8.2 nathanw splx(s);
1043 1.37.8.2 nathanw }
1044 1.37.8.2 nathanw
1045 1.37.8.2 nathanw #if 0
1046 1.37.8.2 nathanw void
1047 1.37.8.2 nathanw fdcpseudointr(arg)
1048 1.37.8.2 nathanw void *arg;
1049 1.37.8.2 nathanw {
1050 1.37.8.2 nathanw int s;
1051 1.37.8.2 nathanw struct fdc_softc *fdc = arg;
1052 1.37.8.2 nathanw
1053 1.37.8.2 nathanw /* just ensure it has the right spl */
1054 1.37.8.2 nathanw s = splbio();
1055 1.37.8.2 nathanw (void) fdcintr(fdc);
1056 1.37.8.2 nathanw splx(s);
1057 1.37.8.2 nathanw }
1058 1.37.8.2 nathanw #endif
1059 1.37.8.2 nathanw
1060 1.37.8.2 nathanw int
1061 1.37.8.2 nathanw fdcintr(arg)
1062 1.37.8.2 nathanw void *arg;
1063 1.37.8.2 nathanw {
1064 1.37.8.2 nathanw struct fdc_softc *fdc = arg;
1065 1.37.8.2 nathanw #define st0 fdc->sc_status[0]
1066 1.37.8.2 nathanw #define cyl fdc->sc_status[1]
1067 1.37.8.2 nathanw struct fd_softc *fd;
1068 1.37.8.2 nathanw struct buf *bp;
1069 1.37.8.2 nathanw bus_space_tag_t iot = fdc->sc_iot;
1070 1.37.8.2 nathanw bus_space_handle_t ioh = fdc->sc_ioh;
1071 1.37.8.2 nathanw int read, head, sec, pos, i, sectrac, nblks;
1072 1.37.8.2 nathanw int tmp;
1073 1.37.8.2 nathanw struct fd_type *type;
1074 1.37.8.2 nathanw
1075 1.37.8.2 nathanw loop:
1076 1.37.8.2 nathanw fd = fdc->sc_drives.tqh_first;
1077 1.37.8.2 nathanw if (fd == NULL) {
1078 1.37.8.2 nathanw DPRINTF(("fdcintr: set DEVIDLE\n"));
1079 1.37.8.2 nathanw if (fdc->sc_state == DEVIDLE) {
1080 1.37.8.2 nathanw if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1081 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
1082 1.37.8.2 nathanw if ((tmp = fdcresult(fdc)) != 2 ||
1083 1.37.8.2 nathanw (st0 & 0xf8) != 0x20) {
1084 1.37.8.2 nathanw goto loop;
1085 1.37.8.2 nathanw }
1086 1.37.8.2 nathanw }
1087 1.37.8.2 nathanw }
1088 1.37.8.2 nathanw /* no drives waiting; end */
1089 1.37.8.2 nathanw fdc->sc_state = DEVIDLE;
1090 1.37.8.2 nathanw return 1;
1091 1.37.8.2 nathanw }
1092 1.37.8.2 nathanw
1093 1.37.8.2 nathanw /* Is there a transfer to this drive? If not, deactivate drive. */
1094 1.37.8.4 nathanw bp = BUFQ_PEEK(&fd->sc_q);
1095 1.37.8.2 nathanw if (bp == NULL) {
1096 1.37.8.2 nathanw fd->sc_ops = 0;
1097 1.37.8.2 nathanw TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1098 1.37.8.2 nathanw fd->sc_active = 0;
1099 1.37.8.2 nathanw goto loop;
1100 1.37.8.2 nathanw }
1101 1.37.8.2 nathanw
1102 1.37.8.2 nathanw switch (fdc->sc_state) {
1103 1.37.8.2 nathanw case DEVIDLE:
1104 1.37.8.2 nathanw DPRINTF(("fdcintr: in DEVIDLE\n"));
1105 1.37.8.2 nathanw fdc->sc_errors = 0;
1106 1.37.8.2 nathanw fd->sc_skip = 0;
1107 1.37.8.2 nathanw fd->sc_bcount = bp->b_bcount;
1108 1.37.8.2 nathanw fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1109 1.37.8.2 nathanw callout_stop(&fd->sc_motoroff_ch);
1110 1.37.8.2 nathanw if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1111 1.37.8.2 nathanw fdc->sc_state = MOTORWAIT;
1112 1.37.8.2 nathanw return 1;
1113 1.37.8.2 nathanw }
1114 1.37.8.2 nathanw if ((fd->sc_flags & FD_MOTOR) == 0) {
1115 1.37.8.2 nathanw /* Turn on the motor */
1116 1.37.8.2 nathanw /* being careful about other drives. */
1117 1.37.8.2 nathanw for (i = 0; i < 4; i++) {
1118 1.37.8.2 nathanw struct fd_softc *ofd = fdc->sc_fd[i];
1119 1.37.8.2 nathanw if (ofd && ofd->sc_flags & FD_MOTOR) {
1120 1.37.8.2 nathanw callout_stop(&ofd->sc_motoroff_ch);
1121 1.37.8.2 nathanw ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1122 1.37.8.2 nathanw break;
1123 1.37.8.2 nathanw }
1124 1.37.8.2 nathanw }
1125 1.37.8.2 nathanw fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1126 1.37.8.2 nathanw fd_set_motor(fdc, 0);
1127 1.37.8.2 nathanw fdc->sc_state = MOTORWAIT;
1128 1.37.8.2 nathanw /* allow .5s for motor to stabilize */
1129 1.37.8.2 nathanw callout_reset(&fd->sc_motoron_ch, hz / 2,
1130 1.37.8.2 nathanw fd_motor_on, fd);
1131 1.37.8.2 nathanw return 1;
1132 1.37.8.2 nathanw }
1133 1.37.8.2 nathanw /* Make sure the right drive is selected. */
1134 1.37.8.2 nathanw fd_set_motor(fdc, 0);
1135 1.37.8.2 nathanw
1136 1.37.8.2 nathanw /* fall through */
1137 1.37.8.2 nathanw case DOSEEK:
1138 1.37.8.2 nathanw doseek:
1139 1.37.8.2 nathanw DPRINTF(("fdcintr: in DOSEEK\n"));
1140 1.37.8.2 nathanw if (fd->sc_cylin == bp->b_cylinder)
1141 1.37.8.2 nathanw goto doio;
1142 1.37.8.2 nathanw
1143 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1144 1.37.8.2 nathanw out_fdc(iot, ioh, 0xd0); /* XXX const */
1145 1.37.8.2 nathanw out_fdc(iot, ioh, 0x10);
1146 1.37.8.2 nathanw
1147 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1148 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1149 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1150 1.37.8.2 nathanw
1151 1.37.8.2 nathanw fd->sc_cylin = -1;
1152 1.37.8.2 nathanw fdc->sc_state = SEEKWAIT;
1153 1.37.8.2 nathanw
1154 1.37.8.2 nathanw fd->sc_dk.dk_seek++;
1155 1.37.8.2 nathanw disk_busy(&fd->sc_dk);
1156 1.37.8.2 nathanw
1157 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1158 1.37.8.2 nathanw return 1;
1159 1.37.8.2 nathanw
1160 1.37.8.2 nathanw case DOIO:
1161 1.37.8.2 nathanw doio:
1162 1.37.8.2 nathanw DPRINTF(("fdcintr: DOIO: "));
1163 1.37.8.2 nathanw type = fd->sc_type;
1164 1.37.8.2 nathanw sectrac = type->sectrac;
1165 1.37.8.2 nathanw pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1166 1.37.8.2 nathanw sec = pos / (1 << (type->secsize - 2));
1167 1.37.8.2 nathanw if (type->secsize == 2) {
1168 1.37.8.2 nathanw fd->sc_part = SEC_P11;
1169 1.37.8.2 nathanw nblks = (sectrac - sec) << (type->secsize - 2);
1170 1.37.8.2 nathanw nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1171 1.37.8.2 nathanw DPRINTF(("nblks(0)"));
1172 1.37.8.2 nathanw } else if ((fd->sc_blkno % 2) == 0) {
1173 1.37.8.2 nathanw if (fd->sc_bcount & 0x00000200) {
1174 1.37.8.2 nathanw if (fd->sc_bcount == FDC_BSIZE) {
1175 1.37.8.2 nathanw fd->sc_part = SEC_P10;
1176 1.37.8.2 nathanw nblks = 1;
1177 1.37.8.2 nathanw DPRINTF(("nblks(1)"));
1178 1.37.8.2 nathanw } else {
1179 1.37.8.2 nathanw fd->sc_part = SEC_P11;
1180 1.37.8.2 nathanw nblks = (sectrac - sec) * 2;
1181 1.37.8.2 nathanw nblks = min(nblks, fd->sc_bcount
1182 1.37.8.2 nathanw / FDC_BSIZE - 1);
1183 1.37.8.2 nathanw DPRINTF(("nblks(2)"));
1184 1.37.8.2 nathanw }
1185 1.37.8.2 nathanw } else {
1186 1.37.8.2 nathanw fd->sc_part = SEC_P11;
1187 1.37.8.2 nathanw nblks = (sectrac - sec)
1188 1.37.8.2 nathanw << (type->secsize - 2);
1189 1.37.8.2 nathanw nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1190 1.37.8.2 nathanw DPRINTF(("nblks(3)"));
1191 1.37.8.2 nathanw }
1192 1.37.8.2 nathanw } else {
1193 1.37.8.2 nathanw fd->sc_part = SEC_P01;
1194 1.37.8.2 nathanw nblks = 1;
1195 1.37.8.2 nathanw DPRINTF(("nblks(4)"));
1196 1.37.8.2 nathanw }
1197 1.37.8.2 nathanw nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1198 1.37.8.2 nathanw DPRINTF((" %d\n", nblks));
1199 1.37.8.2 nathanw fd->sc_nblks = nblks;
1200 1.37.8.2 nathanw fd->sc_nbytes = nblks * FDC_BSIZE;
1201 1.37.8.2 nathanw head = (fd->sc_blkno
1202 1.37.8.2 nathanw % (type->seccyl * (1 << (type->secsize - 2))))
1203 1.37.8.2 nathanw / (type->sectrac * (1 << (type->secsize - 2)));
1204 1.37.8.2 nathanw
1205 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1206 1.37.8.2 nathanw {int block;
1207 1.37.8.2 nathanw block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1208 1.37.8.2 nathanw + sec) * (1 << (type->secsize - 2));
1209 1.37.8.2 nathanw block += (fd->sc_part == SEC_P01) ? 1 : 0;
1210 1.37.8.2 nathanw if (block != fd->sc_blkno) {
1211 1.37.8.2 nathanw printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1212 1.37.8.2 nathanw printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1213 1.37.8.2 nathanw #ifdef DDB
1214 1.37.8.2 nathanw Debugger();
1215 1.37.8.2 nathanw #endif
1216 1.37.8.2 nathanw }}
1217 1.37.8.2 nathanw #endif
1218 1.37.8.2 nathanw read = bp->b_flags & B_READ;
1219 1.37.8.2 nathanw DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1220 1.37.8.2 nathanw read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1221 1.37.8.2 nathanw head, sec, nblks, fd->sc_skip));
1222 1.37.8.2 nathanw DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1223 1.37.8.2 nathanw type->secsize));
1224 1.37.8.2 nathanw
1225 1.37.8.2 nathanw if (fd->sc_part != SEC_P11)
1226 1.37.8.2 nathanw goto docopy;
1227 1.37.8.2 nathanw
1228 1.37.8.2 nathanw fdc_dmastart(fdc,
1229 1.37.8.2 nathanw read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1230 1.37.8.2 nathanw if (read)
1231 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1232 1.37.8.2 nathanw else
1233 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1234 1.37.8.2 nathanw out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1235 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1236 1.37.8.2 nathanw out_fdc(iot, ioh, head);
1237 1.37.8.2 nathanw out_fdc(iot, ioh, sec + 1); /* sector +1 */
1238 1.37.8.2 nathanw out_fdc(iot, ioh, type->secsize); /* sector size */
1239 1.37.8.2 nathanw out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1240 1.37.8.2 nathanw out_fdc(iot, ioh, type->gap1); /* gap1 size */
1241 1.37.8.2 nathanw out_fdc(iot, ioh, type->datalen); /* data length */
1242 1.37.8.2 nathanw fdc->sc_state = IOCOMPLETE;
1243 1.37.8.2 nathanw
1244 1.37.8.2 nathanw disk_busy(&fd->sc_dk);
1245 1.37.8.2 nathanw
1246 1.37.8.2 nathanw /* allow 2 seconds for operation */
1247 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1248 1.37.8.2 nathanw return 1; /* will return later */
1249 1.37.8.2 nathanw
1250 1.37.8.2 nathanw case DOCOPY:
1251 1.37.8.2 nathanw docopy:
1252 1.37.8.2 nathanw DPRINTF(("fdcintr: DOCOPY:\n"));
1253 1.37.8.2 nathanw fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1254 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1255 1.37.8.2 nathanw out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1256 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1257 1.37.8.2 nathanw out_fdc(iot, ioh, head);
1258 1.37.8.2 nathanw out_fdc(iot, ioh, sec + 1); /* sector +1 */
1259 1.37.8.2 nathanw out_fdc(iot, ioh, type->secsize); /* sector size */
1260 1.37.8.2 nathanw out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1261 1.37.8.2 nathanw out_fdc(iot, ioh, type->gap1); /* gap1 size */
1262 1.37.8.2 nathanw out_fdc(iot, ioh, type->datalen); /* data length */
1263 1.37.8.2 nathanw fdc->sc_state = COPYCOMPLETE;
1264 1.37.8.2 nathanw /* allow 2 seconds for operation */
1265 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1266 1.37.8.2 nathanw return 1; /* will return later */
1267 1.37.8.2 nathanw
1268 1.37.8.2 nathanw case DOIOHALF:
1269 1.37.8.2 nathanw doiohalf:
1270 1.37.8.2 nathanw DPRINTF((" DOIOHALF:\n"));
1271 1.37.8.2 nathanw
1272 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1273 1.37.8.2 nathanw type = fd->sc_type;
1274 1.37.8.2 nathanw sectrac = type->sectrac;
1275 1.37.8.2 nathanw pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1276 1.37.8.2 nathanw sec = pos / (1 << (type->secsize - 2));
1277 1.37.8.2 nathanw head = (fd->sc_blkno
1278 1.37.8.2 nathanw % (type->seccyl * (1 << (type->secsize - 2))))
1279 1.37.8.2 nathanw / (type->sectrac * (1 << (type->secsize - 2)));
1280 1.37.8.2 nathanw {int block;
1281 1.37.8.2 nathanw block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1282 1.37.8.2 nathanw * (1 << (type->secsize - 2));
1283 1.37.8.2 nathanw block += (fd->sc_part == SEC_P01) ? 1 : 0;
1284 1.37.8.2 nathanw if (block != fd->sc_blkno) {
1285 1.37.8.2 nathanw printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1286 1.37.8.2 nathanw #ifdef DDB
1287 1.37.8.2 nathanw Debugger();
1288 1.37.8.2 nathanw #endif
1289 1.37.8.2 nathanw }}
1290 1.37.8.2 nathanw #endif
1291 1.37.8.2 nathanw if ((read = bp->b_flags & B_READ)) {
1292 1.37.8.2 nathanw memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf
1293 1.37.8.2 nathanw + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1294 1.37.8.2 nathanw FDC_BSIZE);
1295 1.37.8.2 nathanw fdc->sc_state = IOCOMPLETE;
1296 1.37.8.2 nathanw goto iocomplete2;
1297 1.37.8.2 nathanw } else {
1298 1.37.8.2 nathanw memcpy(fd->sc_copybuf
1299 1.37.8.2 nathanw + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1300 1.37.8.2 nathanw bp->b_data + fd->sc_skip, FDC_BSIZE);
1301 1.37.8.2 nathanw fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1302 1.37.8.2 nathanw }
1303 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1304 1.37.8.2 nathanw out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1305 1.37.8.2 nathanw out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1306 1.37.8.2 nathanw out_fdc(iot, ioh, head);
1307 1.37.8.2 nathanw out_fdc(iot, ioh, sec + 1); /* sector +1 */
1308 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1309 1.37.8.2 nathanw out_fdc(iot, ioh, sectrac); /* sectors/track */
1310 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1311 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1312 1.37.8.2 nathanw fdc->sc_state = IOCOMPLETE;
1313 1.37.8.2 nathanw /* allow 2 seconds for operation */
1314 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1315 1.37.8.2 nathanw return 1; /* will return later */
1316 1.37.8.2 nathanw
1317 1.37.8.2 nathanw case SEEKWAIT:
1318 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1319 1.37.8.2 nathanw fdc->sc_state = SEEKCOMPLETE;
1320 1.37.8.2 nathanw /* allow 1/50 second for heads to settle */
1321 1.37.8.2 nathanw #if 0
1322 1.37.8.2 nathanw callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1323 1.37.8.2 nathanw #endif
1324 1.37.8.2 nathanw return 1;
1325 1.37.8.2 nathanw
1326 1.37.8.2 nathanw case SEEKCOMPLETE:
1327 1.37.8.2 nathanw /* Make sure seek really happened */
1328 1.37.8.2 nathanw DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1329 1.37.8.2 nathanw bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1330 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
1331 1.37.8.2 nathanw tmp = fdcresult(fdc);
1332 1.37.8.2 nathanw if ((st0 & 0xf8) == 0xc0) {
1333 1.37.8.2 nathanw DPRINTF(("fdcintr: first seek!\n"));
1334 1.37.8.2 nathanw fdc->sc_state = DORECAL;
1335 1.37.8.2 nathanw goto loop;
1336 1.37.8.2 nathanw } else if (tmp != 2 ||
1337 1.37.8.2 nathanw (st0 & 0xf8) != 0x20 ||
1338 1.37.8.2 nathanw cyl != bp->b_cylinder) {
1339 1.37.8.2 nathanw #ifdef FDDEBUG
1340 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 2, "seek failed");
1341 1.37.8.2 nathanw #endif
1342 1.37.8.2 nathanw fdcretry(fdc);
1343 1.37.8.2 nathanw goto loop;
1344 1.37.8.2 nathanw }
1345 1.37.8.2 nathanw fd->sc_cylin = bp->b_cylinder;
1346 1.37.8.2 nathanw goto doio;
1347 1.37.8.2 nathanw
1348 1.37.8.2 nathanw case IOTIMEDOUT:
1349 1.37.8.2 nathanw #if 0
1350 1.37.8.2 nathanw isa_dmaabort(fdc->sc_drq);
1351 1.37.8.2 nathanw #endif
1352 1.37.8.2 nathanw case SEEKTIMEDOUT:
1353 1.37.8.2 nathanw case RECALTIMEDOUT:
1354 1.37.8.2 nathanw case RESETTIMEDOUT:
1355 1.37.8.2 nathanw fdcretry(fdc);
1356 1.37.8.2 nathanw goto loop;
1357 1.37.8.2 nathanw
1358 1.37.8.2 nathanw case IOCOMPLETE: /* IO DONE, post-analyze */
1359 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1360 1.37.8.2 nathanw DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1361 1.37.8.2 nathanw if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1362 1.37.8.2 nathanw printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1363 1.37.8.2 nathanw #if 0
1364 1.37.8.2 nathanw isa_dmaabort(fdc->sc_drq);
1365 1.37.8.2 nathanw #endif
1366 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1367 1.37.8.2 nathanw "read failed" : "write failed");
1368 1.37.8.2 nathanw printf("blkno %d nblks %d\n",
1369 1.37.8.2 nathanw fd->sc_blkno, fd->sc_nblks);
1370 1.37.8.2 nathanw fdcretry(fdc);
1371 1.37.8.2 nathanw goto loop;
1372 1.37.8.2 nathanw }
1373 1.37.8.2 nathanw #if 0
1374 1.37.8.2 nathanw isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1375 1.37.8.2 nathanw nblks * FDC_BSIZE, fdc->sc_drq);
1376 1.37.8.2 nathanw #endif
1377 1.37.8.2 nathanw iocomplete2:
1378 1.37.8.2 nathanw if (fdc->sc_errors) {
1379 1.37.8.2 nathanw diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1380 1.37.8.2 nathanw fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1381 1.37.8.2 nathanw printf("\n");
1382 1.37.8.2 nathanw fdc->sc_errors = 0;
1383 1.37.8.2 nathanw }
1384 1.37.8.2 nathanw fd->sc_blkno += fd->sc_nblks;
1385 1.37.8.2 nathanw fd->sc_skip += fd->sc_nbytes;
1386 1.37.8.2 nathanw fd->sc_bcount -= fd->sc_nbytes;
1387 1.37.8.2 nathanw DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1388 1.37.8.2 nathanw if (fd->sc_bcount > 0) {
1389 1.37.8.2 nathanw bp->b_cylinder = fd->sc_blkno
1390 1.37.8.2 nathanw / (fd->sc_type->seccyl
1391 1.37.8.2 nathanw * (1 << (fd->sc_type->secsize - 2)));
1392 1.37.8.2 nathanw goto doseek;
1393 1.37.8.2 nathanw }
1394 1.37.8.2 nathanw fdfinish(fd, bp);
1395 1.37.8.2 nathanw goto loop;
1396 1.37.8.2 nathanw
1397 1.37.8.2 nathanw case COPYCOMPLETE: /* IO DONE, post-analyze */
1398 1.37.8.2 nathanw DPRINTF(("fdcintr: COPYCOMPLETE:"));
1399 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1400 1.37.8.2 nathanw if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1401 1.37.8.2 nathanw printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1402 1.37.8.2 nathanw #if 0
1403 1.37.8.2 nathanw isa_dmaabort(fdc->sc_drq);
1404 1.37.8.2 nathanw #endif
1405 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1406 1.37.8.2 nathanw "read failed" : "write failed");
1407 1.37.8.2 nathanw printf("blkno %d nblks %d\n",
1408 1.37.8.2 nathanw fd->sc_blkno, fd->sc_nblks);
1409 1.37.8.2 nathanw fdcretry(fdc);
1410 1.37.8.2 nathanw goto loop;
1411 1.37.8.2 nathanw }
1412 1.37.8.2 nathanw goto doiohalf;
1413 1.37.8.2 nathanw
1414 1.37.8.2 nathanw case DORESET:
1415 1.37.8.2 nathanw DPRINTF(("fdcintr: in DORESET\n"));
1416 1.37.8.2 nathanw /* try a reset, keep motor on */
1417 1.37.8.2 nathanw fd_set_motor(fdc, 1);
1418 1.37.8.2 nathanw DELAY(100);
1419 1.37.8.2 nathanw fd_set_motor(fdc, 0);
1420 1.37.8.2 nathanw fdc->sc_state = RESETCOMPLETE;
1421 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1422 1.37.8.2 nathanw return 1; /* will return later */
1423 1.37.8.2 nathanw
1424 1.37.8.2 nathanw case RESETCOMPLETE:
1425 1.37.8.2 nathanw DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1426 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1427 1.37.8.2 nathanw /* clear the controller output buffer */
1428 1.37.8.2 nathanw for (i = 0; i < 4; i++) {
1429 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
1430 1.37.8.2 nathanw (void) fdcresult(fdc);
1431 1.37.8.2 nathanw }
1432 1.37.8.2 nathanw
1433 1.37.8.2 nathanw /* fall through */
1434 1.37.8.2 nathanw case DORECAL:
1435 1.37.8.2 nathanw DPRINTF(("fdcintr: in DORECAL\n"));
1436 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1437 1.37.8.2 nathanw out_fdc(iot, ioh, fd->sc_drive);
1438 1.37.8.2 nathanw fdc->sc_state = RECALWAIT;
1439 1.37.8.2 nathanw callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1440 1.37.8.2 nathanw return 1; /* will return later */
1441 1.37.8.2 nathanw
1442 1.37.8.2 nathanw case RECALWAIT:
1443 1.37.8.2 nathanw DPRINTF(("fdcintr: in RECALWAIT\n"));
1444 1.37.8.2 nathanw callout_stop(&fdc->sc_timo_ch);
1445 1.37.8.2 nathanw fdc->sc_state = RECALCOMPLETE;
1446 1.37.8.2 nathanw /* allow 1/30 second for heads to settle */
1447 1.37.8.2 nathanw #if 0
1448 1.37.8.2 nathanw callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1449 1.37.8.2 nathanw #endif
1450 1.37.8.2 nathanw return 1; /* will return later */
1451 1.37.8.2 nathanw
1452 1.37.8.2 nathanw case RECALCOMPLETE:
1453 1.37.8.2 nathanw DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1454 1.37.8.2 nathanw out_fdc(iot, ioh, NE7CMD_SENSEI);
1455 1.37.8.2 nathanw tmp = fdcresult(fdc);
1456 1.37.8.2 nathanw if ((st0 & 0xf8) == 0xc0) {
1457 1.37.8.2 nathanw DPRINTF(("fdcintr: first seek!\n"));
1458 1.37.8.2 nathanw fdc->sc_state = DORECAL;
1459 1.37.8.2 nathanw goto loop;
1460 1.37.8.2 nathanw } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1461 1.37.8.2 nathanw #ifdef FDDEBUG
1462 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1463 1.37.8.2 nathanw #endif
1464 1.37.8.2 nathanw fdcretry(fdc);
1465 1.37.8.2 nathanw goto loop;
1466 1.37.8.2 nathanw }
1467 1.37.8.2 nathanw fd->sc_cylin = 0;
1468 1.37.8.2 nathanw goto doseek;
1469 1.37.8.2 nathanw
1470 1.37.8.2 nathanw case MOTORWAIT:
1471 1.37.8.2 nathanw if (fd->sc_flags & FD_MOTOR_WAIT)
1472 1.37.8.2 nathanw return 1; /* time's not up yet */
1473 1.37.8.2 nathanw goto doseek;
1474 1.37.8.2 nathanw
1475 1.37.8.2 nathanw default:
1476 1.37.8.2 nathanw fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1477 1.37.8.2 nathanw return 1;
1478 1.37.8.2 nathanw }
1479 1.37.8.2 nathanw #ifdef DIAGNOSTIC
1480 1.37.8.2 nathanw panic("fdcintr: impossible");
1481 1.37.8.2 nathanw #endif
1482 1.37.8.2 nathanw #undef st0
1483 1.37.8.2 nathanw #undef cyl
1484 1.37.8.2 nathanw }
1485 1.37.8.2 nathanw
1486 1.37.8.2 nathanw void
1487 1.37.8.2 nathanw fdcretry(fdc)
1488 1.37.8.2 nathanw struct fdc_softc *fdc;
1489 1.37.8.2 nathanw {
1490 1.37.8.2 nathanw struct fd_softc *fd;
1491 1.37.8.2 nathanw struct buf *bp;
1492 1.37.8.2 nathanw char bits[64];
1493 1.37.8.2 nathanw
1494 1.37.8.2 nathanw DPRINTF(("fdcretry:\n"));
1495 1.37.8.2 nathanw fd = fdc->sc_drives.tqh_first;
1496 1.37.8.4 nathanw bp = BUFQ_PEEK(&fd->sc_q);
1497 1.37.8.2 nathanw
1498 1.37.8.2 nathanw switch (fdc->sc_errors) {
1499 1.37.8.2 nathanw case 0:
1500 1.37.8.2 nathanw /* try again */
1501 1.37.8.2 nathanw fdc->sc_state = SEEKCOMPLETE;
1502 1.37.8.2 nathanw break;
1503 1.37.8.2 nathanw
1504 1.37.8.2 nathanw case 1: case 2: case 3:
1505 1.37.8.2 nathanw /* didn't work; try recalibrating */
1506 1.37.8.2 nathanw fdc->sc_state = DORECAL;
1507 1.37.8.2 nathanw break;
1508 1.37.8.2 nathanw
1509 1.37.8.2 nathanw case 4:
1510 1.37.8.2 nathanw /* still no go; reset the bastard */
1511 1.37.8.2 nathanw fdc->sc_state = DORESET;
1512 1.37.8.2 nathanw break;
1513 1.37.8.2 nathanw
1514 1.37.8.2 nathanw default:
1515 1.37.8.2 nathanw diskerr(bp, "fd", "hard error", LOG_PRINTF,
1516 1.37.8.2 nathanw fd->sc_skip, (struct disklabel *)NULL);
1517 1.37.8.2 nathanw printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1518 1.37.8.2 nathanw NE7_ST0BITS, bits,
1519 1.37.8.2 nathanw sizeof(bits)));
1520 1.37.8.2 nathanw printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1521 1.37.8.2 nathanw NE7_ST1BITS, bits,
1522 1.37.8.2 nathanw sizeof(bits)));
1523 1.37.8.2 nathanw printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1524 1.37.8.2 nathanw NE7_ST2BITS, bits,
1525 1.37.8.2 nathanw sizeof(bits)));
1526 1.37.8.2 nathanw printf(" cyl %d head %d sec %d)\n",
1527 1.37.8.2 nathanw fdc->sc_status[3],
1528 1.37.8.2 nathanw fdc->sc_status[4],
1529 1.37.8.2 nathanw fdc->sc_status[5]);
1530 1.37.8.2 nathanw
1531 1.37.8.2 nathanw bp->b_flags |= B_ERROR;
1532 1.37.8.2 nathanw bp->b_error = EIO;
1533 1.37.8.2 nathanw fdfinish(fd, bp);
1534 1.37.8.2 nathanw }
1535 1.37.8.2 nathanw fdc->sc_errors++;
1536 1.37.8.2 nathanw }
1537 1.37.8.2 nathanw
1538 1.37.8.2 nathanw int
1539 1.37.8.2 nathanw fdsize(dev)
1540 1.37.8.2 nathanw dev_t dev;
1541 1.37.8.2 nathanw {
1542 1.37.8.2 nathanw
1543 1.37.8.2 nathanw /* Swapping to floppies would not make sense. */
1544 1.37.8.2 nathanw return -1;
1545 1.37.8.2 nathanw }
1546 1.37.8.2 nathanw
1547 1.37.8.2 nathanw int
1548 1.37.8.2 nathanw fddump(dev, blkno, va, size)
1549 1.37.8.2 nathanw dev_t dev;
1550 1.37.8.2 nathanw daddr_t blkno;
1551 1.37.8.2 nathanw caddr_t va;
1552 1.37.8.2 nathanw size_t size;
1553 1.37.8.2 nathanw {
1554 1.37.8.2 nathanw
1555 1.37.8.2 nathanw /* Not implemented. */
1556 1.37.8.2 nathanw return ENXIO;
1557 1.37.8.2 nathanw }
1558 1.37.8.2 nathanw
1559 1.37.8.2 nathanw int
1560 1.37.8.2 nathanw fdioctl(dev, cmd, addr, flag, p)
1561 1.37.8.2 nathanw dev_t dev;
1562 1.37.8.2 nathanw u_long cmd;
1563 1.37.8.2 nathanw caddr_t addr;
1564 1.37.8.2 nathanw int flag;
1565 1.37.8.2 nathanw struct proc *p;
1566 1.37.8.2 nathanw {
1567 1.37.8.2 nathanw struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1568 1.37.8.2 nathanw struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1569 1.37.8.2 nathanw int unit = FDUNIT(dev);
1570 1.37.8.2 nathanw int part = DISKPART(dev);
1571 1.37.8.2 nathanw struct disklabel buffer;
1572 1.37.8.2 nathanw int error;
1573 1.37.8.2 nathanw
1574 1.37.8.2 nathanw DPRINTF(("fdioctl:\n"));
1575 1.37.8.2 nathanw switch (cmd) {
1576 1.37.8.2 nathanw case DIOCGDINFO:
1577 1.37.8.2 nathanw #if 1
1578 1.37.8.2 nathanw *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1579 1.37.8.2 nathanw return(0);
1580 1.37.8.2 nathanw #else
1581 1.37.8.2 nathanw memset(&buffer, 0, sizeof(buffer));
1582 1.37.8.2 nathanw
1583 1.37.8.2 nathanw buffer.d_secpercyl = fd->sc_type->seccyl;
1584 1.37.8.2 nathanw buffer.d_type = DTYPE_FLOPPY;
1585 1.37.8.2 nathanw buffer.d_secsize = 128 << fd->sc_type->secsize;
1586 1.37.8.2 nathanw
1587 1.37.8.2 nathanw if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1588 1.37.8.2 nathanw return EINVAL;
1589 1.37.8.2 nathanw
1590 1.37.8.2 nathanw *(struct disklabel *)addr = buffer;
1591 1.37.8.2 nathanw return 0;
1592 1.37.8.2 nathanw #endif
1593 1.37.8.2 nathanw
1594 1.37.8.2 nathanw case DIOCGPART:
1595 1.37.8.2 nathanw ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1596 1.37.8.2 nathanw ((struct partinfo *)addr)->part =
1597 1.37.8.2 nathanw &fd->sc_dk.dk_label->d_partitions[part];
1598 1.37.8.2 nathanw return(0);
1599 1.37.8.2 nathanw
1600 1.37.8.2 nathanw case DIOCWLABEL:
1601 1.37.8.2 nathanw if ((flag & FWRITE) == 0)
1602 1.37.8.2 nathanw return EBADF;
1603 1.37.8.2 nathanw /* XXX do something */
1604 1.37.8.2 nathanw return 0;
1605 1.37.8.2 nathanw
1606 1.37.8.2 nathanw case DIOCWDINFO:
1607 1.37.8.2 nathanw if ((flag & FWRITE) == 0)
1608 1.37.8.2 nathanw return EBADF;
1609 1.37.8.2 nathanw
1610 1.37.8.2 nathanw error = setdisklabel(&buffer, (struct disklabel *)addr, 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