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