hdfd.c revision 1.1 1 1.1 leo /* $NetBSD: hdfd.c,v 1.1 1996/11/09 22:27:25 leo Exp $ */
2 1.1 leo
3 1.1 leo /*-
4 1.1 leo * Copyright (c) 1996 Leo Weppelman
5 1.1 leo * Copyright (c) 1993, 1994, 1995, 1996
6 1.1 leo * Charles M. Hannum. All rights reserved.
7 1.1 leo * Copyright (c) 1990 The Regents of the University of California.
8 1.1 leo * All rights reserved.
9 1.1 leo *
10 1.1 leo * This code is derived from software contributed to Berkeley by
11 1.1 leo * Don Ahn.
12 1.1 leo *
13 1.1 leo * Redistribution and use in source and binary forms, with or without
14 1.1 leo * modification, are permitted provided that the following conditions
15 1.1 leo * are met:
16 1.1 leo * 1. Redistributions of source code must retain the above copyright
17 1.1 leo * notice, this list of conditions and the following disclaimer.
18 1.1 leo * 2. Redistributions in binary form must reproduce the above copyright
19 1.1 leo * notice, this list of conditions and the following disclaimer in the
20 1.1 leo * documentation and/or other materials provided with the distribution.
21 1.1 leo * 3. All advertising materials mentioning features or use of this software
22 1.1 leo * must display the following acknowledgement:
23 1.1 leo * This product includes software developed by the University of
24 1.1 leo * California, Berkeley and its contributors.
25 1.1 leo * 4. Neither the name of the University nor the names of its contributors
26 1.1 leo * may be used to endorse or promote products derived from this software
27 1.1 leo * without specific prior written permission.
28 1.1 leo *
29 1.1 leo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 1.1 leo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 1.1 leo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 1.1 leo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 1.1 leo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 1.1 leo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 1.1 leo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 1.1 leo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 1.1 leo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 1.1 leo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 1.1 leo * SUCH DAMAGE.
40 1.1 leo *
41 1.1 leo * @(#)fd.c 7.4 (Berkeley) 5/25/91
42 1.1 leo */
43 1.1 leo
44 1.1 leo #include <sys/param.h>
45 1.1 leo #include <sys/systm.h>
46 1.1 leo #include <sys/kernel.h>
47 1.1 leo #include <sys/file.h>
48 1.1 leo #include <sys/ioctl.h>
49 1.1 leo #include <sys/device.h>
50 1.1 leo #include <sys/disklabel.h>
51 1.1 leo #include <sys/dkstat.h>
52 1.1 leo #include <sys/disk.h>
53 1.1 leo #include <sys/buf.h>
54 1.1 leo #include <sys/uio.h>
55 1.1 leo #include <sys/syslog.h>
56 1.1 leo #include <sys/queue.h>
57 1.1 leo #include <sys/conf.h>
58 1.1 leo #include <sys/device.h>
59 1.1 leo
60 1.1 leo #include <machine/cpu.h>
61 1.1 leo #include <machine/bus.h>
62 1.1 leo #include <machine/iomap.h>
63 1.1 leo #include <machine/mfp.h>
64 1.1 leo
65 1.1 leo #include <atari/dev/hdfdreg.h>
66 1.1 leo #include <atari/atari/device.h>
67 1.1 leo
68 1.1 leo /*
69 1.1 leo * {b,c}devsw[] function prototypes
70 1.1 leo */
71 1.1 leo dev_type_open(fdopen);
72 1.1 leo dev_type_close(fdclose);
73 1.1 leo dev_type_read(fdread);
74 1.1 leo dev_type_write(fdwrite);
75 1.1 leo dev_type_ioctl(fdioctl);
76 1.1 leo dev_type_size(fdsize);
77 1.1 leo dev_type_dump(fddump);
78 1.1 leo
79 1.1 leo volatile u_char *fdio_addr;
80 1.1 leo
81 1.1 leo #define wrt_fdc_reg(reg, val) { fdio_addr[reg] = val; }
82 1.1 leo #define rd_fdc_reg(reg) ( fdio_addr[reg] )
83 1.1 leo
84 1.1 leo #define fdc_ienable() MFP2->mf_ierb |= IB_DCHG;
85 1.1 leo
86 1.1 leo /*
87 1.1 leo * Interface to the pseudo-dma handler
88 1.1 leo */
89 1.1 leo void fddma_intr(void);
90 1.1 leo caddr_t fddmaaddr = NULL;
91 1.1 leo int fddmalen = 0;
92 1.1 leo
93 1.1 leo /*
94 1.1 leo * Argument to fdcintr.....
95 1.1 leo */
96 1.1 leo static void *intr_arg = NULL; /* XXX: arg. to intr_establish() */
97 1.1 leo
98 1.1 leo
99 1.1 leo #define FDUNIT(dev) (minor(dev) / 8)
100 1.1 leo #define FDTYPE(dev) (minor(dev) % 8)
101 1.1 leo
102 1.1 leo #define b_cylin b_resid
103 1.1 leo
104 1.1 leo enum fdc_state {
105 1.1 leo DEVIDLE = 0,
106 1.1 leo MOTORWAIT,
107 1.1 leo DOSEEK,
108 1.1 leo SEEKWAIT,
109 1.1 leo SEEKTIMEDOUT,
110 1.1 leo SEEKCOMPLETE,
111 1.1 leo DOIO,
112 1.1 leo IOCOMPLETE,
113 1.1 leo IOTIMEDOUT,
114 1.1 leo DORESET,
115 1.1 leo RESETCOMPLETE,
116 1.1 leo RESETTIMEDOUT,
117 1.1 leo DORECAL,
118 1.1 leo RECALWAIT,
119 1.1 leo RECALTIMEDOUT,
120 1.1 leo RECALCOMPLETE,
121 1.1 leo };
122 1.1 leo
123 1.1 leo /* software state, per controller */
124 1.1 leo struct fdc_softc {
125 1.1 leo struct device sc_dev; /* boilerplate */
126 1.1 leo struct fd_softc *sc_fd[4]; /* pointers to children */
127 1.1 leo TAILQ_HEAD(drivehead, fd_softc) sc_drives;
128 1.1 leo enum fdc_state sc_state;
129 1.1 leo int sc_errors; /* number of retries so far */
130 1.1 leo int sc_overruns; /* number of overruns so far */
131 1.1 leo u_char sc_status[7]; /* copy of registers */
132 1.1 leo };
133 1.1 leo
134 1.1 leo /* controller driver configuration */
135 1.1 leo int fdcprobe __P((struct device *, void *, void *));
136 1.1 leo int fdprint __P((void *, const char *));
137 1.1 leo void fdcattach __P((struct device *, struct device *, void *));
138 1.1 leo
139 1.1 leo struct cfattach fdc_ca = {
140 1.1 leo sizeof(struct fdc_softc), fdcprobe, fdcattach
141 1.1 leo };
142 1.1 leo
143 1.1 leo struct cfdriver fdc_cd = {
144 1.1 leo NULL, "fdc", DV_DULL
145 1.1 leo };
146 1.1 leo
147 1.1 leo /*
148 1.1 leo * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
149 1.1 leo * we tell them apart.
150 1.1 leo */
151 1.1 leo struct fd_type {
152 1.1 leo int sectrac; /* sectors per track */
153 1.1 leo int heads; /* number of heads */
154 1.1 leo int seccyl; /* sectors per cylinder */
155 1.1 leo int secsize; /* size code for sectors */
156 1.1 leo int datalen; /* data len when secsize = 0 */
157 1.1 leo int steprate; /* step rate and head unload time */
158 1.1 leo int gap1; /* gap len between sectors */
159 1.1 leo int gap2; /* formatting gap */
160 1.1 leo int tracks; /* total num of tracks */
161 1.1 leo int size; /* size of disk in sectors */
162 1.1 leo int step; /* steps per cylinder */
163 1.1 leo int rate; /* transfer speed code */
164 1.1 leo char *name;
165 1.1 leo };
166 1.1 leo
167 1.1 leo /*
168 1.1 leo * The order of entries in the following table is important -- BEWARE!
169 1.1 leo * The order of the types is the same as for the TT/Falcon....
170 1.1 leo */
171 1.1 leo struct fd_type fd_types[] = {
172 1.1 leo /* 360kB in 720kB drive */
173 1.1 leo { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS, "360KB" },
174 1.1 leo /* 3.5" 720kB diskette */
175 1.1 leo { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS, "720KB" },
176 1.1 leo /* 1.44MB diskette */
177 1.1 leo { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS, "1.44MB" },
178 1.1 leo };
179 1.1 leo
180 1.1 leo /* software state, per disk (with up to 4 disks per ctlr) */
181 1.1 leo struct fd_softc {
182 1.1 leo struct device sc_dev;
183 1.1 leo struct disk sc_dk;
184 1.1 leo
185 1.1 leo struct fd_type *sc_deftype; /* default type descriptor */
186 1.1 leo struct fd_type *sc_type; /* current type descriptor */
187 1.1 leo
188 1.1 leo daddr_t sc_blkno; /* starting block number */
189 1.1 leo int sc_bcount; /* byte count left */
190 1.1 leo int sc_skip; /* bytes already transferred */
191 1.1 leo int sc_nblks; /* #blocks currently tranferring */
192 1.1 leo int sc_nbytes; /* #bytes currently tranferring */
193 1.1 leo
194 1.1 leo int sc_drive; /* physical unit number */
195 1.1 leo int sc_flags;
196 1.1 leo #define FD_OPEN 0x01 /* it's open */
197 1.1 leo #define FD_MOTOR 0x02 /* motor should be on */
198 1.1 leo #define FD_MOTOR_WAIT 0x04 /* motor coming up */
199 1.1 leo int sc_cylin; /* where we think the head is */
200 1.1 leo
201 1.1 leo void *sc_sdhook; /* saved shutdown hook for drive. */
202 1.1 leo
203 1.1 leo TAILQ_ENTRY(fd_softc) sc_drivechain;
204 1.1 leo int sc_ops; /* I/O ops since last switch */
205 1.1 leo struct buf sc_q; /* head of buf chain */
206 1.1 leo };
207 1.1 leo
208 1.1 leo /* floppy driver configuration */
209 1.1 leo int fdprobe __P((struct device *, void *, void *));
210 1.1 leo void fdattach __P((struct device *, struct device *, void *));
211 1.1 leo
212 1.1 leo struct cfattach hdfd_ca = {
213 1.1 leo sizeof(struct fd_softc), fdprobe, fdattach
214 1.1 leo };
215 1.1 leo
216 1.1 leo struct cfdriver hdfd_cd = {
217 1.1 leo NULL, "hdfd", DV_DISK
218 1.1 leo };
219 1.1 leo
220 1.1 leo void fdstrategy __P((struct buf *));
221 1.1 leo void fdstart __P((struct fd_softc *));
222 1.1 leo
223 1.1 leo struct dkdriver fddkdriver = { fdstrategy };
224 1.1 leo
225 1.1 leo void fd_set_motor __P((struct fdc_softc *fdc, int reset));
226 1.1 leo void fd_motor_off __P((void *arg));
227 1.1 leo void fd_motor_on __P((void *arg));
228 1.1 leo int fdcresult __P((struct fdc_softc *fdc));
229 1.1 leo int out_fdc __P((u_char x));
230 1.1 leo void fdc_ctrl_intr __P((struct clockframe *));
231 1.1 leo void fdcstart __P((struct fdc_softc *fdc));
232 1.1 leo void fdcstatus __P((struct device *dv, int n, char *s));
233 1.1 leo void fdctimeout __P((void *arg));
234 1.1 leo void fdcpseudointr __P((void *arg));
235 1.1 leo int fdcintr __P((void *));
236 1.1 leo void fdcretry __P((struct fdc_softc *fdc));
237 1.1 leo void fdfinish __P((struct fd_softc *fd, struct buf *bp));
238 1.1 leo __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
239 1.1 leo
240 1.1 leo int
241 1.1 leo fdcprobe(parent, match, aux)
242 1.1 leo struct device *parent;
243 1.1 leo void *match, *aux;
244 1.1 leo {
245 1.1 leo int rv = 0;
246 1.1 leo struct cfdata *cfp = match;
247 1.1 leo
248 1.1 leo if(strcmp("fdc", aux) || cfp->cf_unit != 0)
249 1.1 leo return(0);
250 1.1 leo
251 1.1 leo if (!atari_realconfig)
252 1.1 leo return 0;
253 1.1 leo
254 1.1 leo if (bus_space_map(NULL, 0xfff00000, NBPG, 0, (caddr_t*)&fdio_addr)) {
255 1.1 leo printf("fdcprobe: cannot map io-area\n");
256 1.1 leo return (0);
257 1.1 leo }
258 1.1 leo
259 1.1 leo #ifdef FD_DEBUG
260 1.1 leo printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr);
261 1.1 leo #endif
262 1.1 leo
263 1.1 leo /* reset */
264 1.1 leo wrt_fdc_reg(fdout, 0);
265 1.1 leo delay(100);
266 1.1 leo wrt_fdc_reg(fdout, FDO_FRST);
267 1.1 leo
268 1.1 leo /* see if it can handle a command */
269 1.1 leo if (out_fdc(NE7CMD_SPECIFY) < 0)
270 1.1 leo goto out;
271 1.1 leo out_fdc(0xdf);
272 1.1 leo out_fdc(7);
273 1.1 leo
274 1.1 leo rv = 1;
275 1.1 leo
276 1.1 leo out:
277 1.1 leo if (rv == 0)
278 1.1 leo bus_space_unmap(NULL, (caddr_t)fdio_addr, NBPG);
279 1.1 leo
280 1.1 leo return rv;
281 1.1 leo }
282 1.1 leo
283 1.1 leo /*
284 1.1 leo * Arguments passed between fdcattach and fdprobe.
285 1.1 leo */
286 1.1 leo struct fdc_attach_args {
287 1.1 leo int fa_drive;
288 1.1 leo struct fd_type *fa_deftype;
289 1.1 leo };
290 1.1 leo
291 1.1 leo /*
292 1.1 leo * Print the location of a disk drive (called just before attaching the
293 1.1 leo * the drive). If `fdc' is not NULL, the drive was found but was not
294 1.1 leo * in the system config file; print the drive name as well.
295 1.1 leo * Return QUIET (config_find ignores this if the device was configured) to
296 1.1 leo * avoid printing `fdN not configured' messages.
297 1.1 leo */
298 1.1 leo int
299 1.1 leo fdprint(aux, fdc)
300 1.1 leo void *aux;
301 1.1 leo const char *fdc;
302 1.1 leo {
303 1.1 leo register struct fdc_attach_args *fa = aux;
304 1.1 leo
305 1.1 leo if (!fdc)
306 1.1 leo printf(" drive %d", fa->fa_drive);
307 1.1 leo return QUIET;
308 1.1 leo }
309 1.1 leo
310 1.1 leo void
311 1.1 leo fdcattach(parent, self, aux)
312 1.1 leo struct device *parent, *self;
313 1.1 leo void *aux;
314 1.1 leo {
315 1.1 leo struct fdc_softc *fdc = (void *)self;
316 1.1 leo struct fdc_attach_args fa;
317 1.1 leo int has_fifo;
318 1.1 leo
319 1.1 leo has_fifo = 0;
320 1.1 leo
321 1.1 leo fdc->sc_state = DEVIDLE;
322 1.1 leo TAILQ_INIT(&fdc->sc_drives);
323 1.1 leo
324 1.1 leo out_fdc(NE7CMD_CONFIGURE);
325 1.1 leo if (out_fdc(0) == 0) {
326 1.1 leo out_fdc(0x1a); /* No polling, fifo depth = 10 */
327 1.1 leo out_fdc(0);
328 1.1 leo
329 1.1 leo /* Retain configuration across resets */
330 1.1 leo out_fdc(NE7CMD_LOCK);
331 1.1 leo (void)fdcresult(fdc);
332 1.1 leo has_fifo = 1;
333 1.1 leo }
334 1.1 leo else {
335 1.1 leo (void)rd_fdc_reg(fddata);
336 1.1 leo printf(": no fifo");
337 1.1 leo }
338 1.1 leo
339 1.1 leo printf("\n");
340 1.1 leo
341 1.1 leo /*
342 1.1 leo * Setup the interrupt vector.
343 1.1 leo * XXX: While no int_establish() functions are available,
344 1.1 leo * we do it the Dirty(Tm) way...
345 1.1 leo */
346 1.1 leo {
347 1.1 leo extern u_long uservects[];
348 1.1 leo extern void mfp_hdfd_nf(void), mfp_hdfd_fifo(void);
349 1.1 leo
350 1.1 leo uservects[22] = (u_long)(has_fifo ? mfp_hdfd_fifo:mfp_hdfd_nf);
351 1.1 leo }
352 1.1 leo
353 1.1 leo /*
354 1.1 leo * Setup the interrupt logic.
355 1.1 leo */
356 1.1 leo MFP2->mf_iprb &= ~IB_DCHG;
357 1.1 leo MFP2->mf_imrb |= IB_DCHG;
358 1.1 leo MFP2->mf_aer |= 0x10; /* fdc int low->high */
359 1.1 leo
360 1.1 leo /* physical limit: four drives per controller. */
361 1.1 leo for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
362 1.1 leo /*
363 1.1 leo * XXX: Choose something sensible as a default...
364 1.1 leo */
365 1.1 leo fa.fa_deftype = &fd_types[2]; /* 1.44MB */
366 1.1 leo (void)config_found(self, (void *)&fa, fdprint);
367 1.1 leo }
368 1.1 leo }
369 1.1 leo
370 1.1 leo int
371 1.1 leo fdprobe(parent, match, aux)
372 1.1 leo struct device *parent;
373 1.1 leo void *match, *aux;
374 1.1 leo {
375 1.1 leo struct fdc_softc *fdc = (void *)parent;
376 1.1 leo struct cfdata *cf = match;
377 1.1 leo struct fdc_attach_args *fa = aux;
378 1.1 leo int drive = fa->fa_drive;
379 1.1 leo int n;
380 1.1 leo
381 1.1 leo if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
382 1.1 leo return 0;
383 1.1 leo /*
384 1.1 leo * XXX
385 1.1 leo * This is to work around some odd interactions between this driver
386 1.1 leo * and SMC Ethernet cards.
387 1.1 leo */
388 1.1 leo if (cf->cf_loc[0] == -1 && drive >= 2)
389 1.1 leo return 0;
390 1.1 leo
391 1.1 leo /* select drive and turn on motor */
392 1.1 leo wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive));
393 1.1 leo
394 1.1 leo /* wait for motor to spin up */
395 1.1 leo delay(250000);
396 1.1 leo out_fdc(NE7CMD_RECAL);
397 1.1 leo out_fdc(drive);
398 1.1 leo
399 1.1 leo /* wait for recalibrate */
400 1.1 leo delay(2000000);
401 1.1 leo out_fdc(NE7CMD_SENSEI);
402 1.1 leo n = fdcresult(fdc);
403 1.1 leo
404 1.1 leo #ifdef FD_DEBUG
405 1.1 leo {
406 1.1 leo int i;
407 1.1 leo printf("fdprobe: status");
408 1.1 leo for (i = 0; i < n; i++)
409 1.1 leo printf(" %x", fdc->sc_status[i]);
410 1.1 leo printf("\n");
411 1.1 leo }
412 1.1 leo #endif
413 1.1 leo intr_arg = (void*)fdc;
414 1.1 leo if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
415 1.1 leo return 0;
416 1.1 leo /* turn off motor */
417 1.1 leo wrt_fdc_reg(fdout, FDO_FRST);
418 1.1 leo
419 1.1 leo return 1;
420 1.1 leo }
421 1.1 leo
422 1.1 leo /*
423 1.1 leo * Controller is working, and drive responded. Attach it.
424 1.1 leo */
425 1.1 leo void
426 1.1 leo fdattach(parent, self, aux)
427 1.1 leo struct device *parent, *self;
428 1.1 leo void *aux;
429 1.1 leo {
430 1.1 leo struct fdc_softc *fdc = (void *)parent;
431 1.1 leo struct fd_softc *fd = (void *)self;
432 1.1 leo struct fdc_attach_args *fa = aux;
433 1.1 leo struct fd_type *type = fa->fa_deftype;
434 1.1 leo int drive = fa->fa_drive;
435 1.1 leo
436 1.1 leo /* XXX Allow `flags' to override device type? */
437 1.1 leo
438 1.1 leo if (type)
439 1.1 leo printf(": %s %d cyl, %d head, %d sec\n", type->name,
440 1.1 leo type->tracks, type->heads, type->sectrac);
441 1.1 leo else
442 1.1 leo printf(": density unknown\n");
443 1.1 leo
444 1.1 leo fd->sc_cylin = -1;
445 1.1 leo fd->sc_drive = drive;
446 1.1 leo fd->sc_deftype = type;
447 1.1 leo fdc->sc_fd[drive] = fd;
448 1.1 leo
449 1.1 leo /*
450 1.1 leo * Initialize and attach the disk structure.
451 1.1 leo */
452 1.1 leo fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
453 1.1 leo fd->sc_dk.dk_driver = &fddkdriver;
454 1.1 leo disk_attach(&fd->sc_dk);
455 1.1 leo
456 1.1 leo /* XXX Need to do some more fiddling with sc_dk. */
457 1.1 leo dk_establish(&fd->sc_dk, &fd->sc_dev);
458 1.1 leo
459 1.1 leo /* Needed to power off if the motor is on when we halt. */
460 1.1 leo fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
461 1.1 leo }
462 1.1 leo
463 1.1 leo /*
464 1.1 leo * This is called from the assembly part of the interrupt handler
465 1.1 leo * when it is clear that the interrupt was not related to shoving
466 1.1 leo * data.
467 1.1 leo */
468 1.1 leo void
469 1.1 leo fdc_ctrl_intr(frame)
470 1.1 leo register struct clockframe *frame;
471 1.1 leo {
472 1.1 leo int s;
473 1.1 leo
474 1.1 leo /*
475 1.1 leo * Disable further interrupts. The fdcintr() routine
476 1.1 leo * explicitely enables them when needed.
477 1.1 leo */
478 1.1 leo MFP2->mf_ierb &= ~IB_DCHG;
479 1.1 leo
480 1.1 leo /*
481 1.1 leo * Set fddmalen to zero so no pseudo-dma transfers will
482 1.1 leo * occur.
483 1.1 leo */
484 1.1 leo fddmalen = 0;
485 1.1 leo
486 1.1 leo if (!BASEPRI(frame->sr)) {
487 1.1 leo /*
488 1.1 leo * We don't want to stay on ipl6.....
489 1.1 leo */
490 1.1 leo add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
491 1.1 leo }
492 1.1 leo else {
493 1.1 leo s = splbio();
494 1.1 leo (void) fdcintr(intr_arg);
495 1.1 leo splx(s);
496 1.1 leo }
497 1.1 leo }
498 1.1 leo
499 1.1 leo __inline struct fd_type *
500 1.1 leo fd_dev_to_type(fd, dev)
501 1.1 leo struct fd_softc *fd;
502 1.1 leo dev_t dev;
503 1.1 leo {
504 1.1 leo int type = FDTYPE(dev);
505 1.1 leo
506 1.1 leo if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
507 1.1 leo return NULL;
508 1.1 leo return type ? &fd_types[type - 1] : fd->sc_deftype;
509 1.1 leo }
510 1.1 leo
511 1.1 leo void
512 1.1 leo fdstrategy(bp)
513 1.1 leo register struct buf *bp; /* IO operation to perform */
514 1.1 leo {
515 1.1 leo struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
516 1.1 leo int sz;
517 1.1 leo int s;
518 1.1 leo
519 1.1 leo /* Valid unit, controller, and request? */
520 1.1 leo if (bp->b_blkno < 0 ||
521 1.1 leo (bp->b_bcount % FDC_BSIZE) != 0) {
522 1.1 leo bp->b_error = EINVAL;
523 1.1 leo goto bad;
524 1.1 leo }
525 1.1 leo
526 1.1 leo /* If it's a null transfer, return immediately. */
527 1.1 leo if (bp->b_bcount == 0)
528 1.1 leo goto done;
529 1.1 leo
530 1.1 leo sz = howmany(bp->b_bcount, FDC_BSIZE);
531 1.1 leo
532 1.1 leo if (bp->b_blkno + sz > fd->sc_type->size) {
533 1.1 leo sz = fd->sc_type->size - bp->b_blkno;
534 1.1 leo if (sz == 0) {
535 1.1 leo /* If exactly at end of disk, return EOF. */
536 1.1 leo goto done;
537 1.1 leo }
538 1.1 leo if (sz < 0) {
539 1.1 leo /* If past end of disk, return EINVAL. */
540 1.1 leo bp->b_error = EINVAL;
541 1.1 leo goto bad;
542 1.1 leo }
543 1.1 leo /* Otherwise, truncate request. */
544 1.1 leo bp->b_bcount = sz << DEV_BSHIFT;
545 1.1 leo }
546 1.1 leo
547 1.1 leo bp->b_cylin = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
548 1.1 leo
549 1.1 leo #ifdef FD_DEBUG
550 1.1 leo printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz"
551 1.1 leo " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
552 1.1 leo bp->b_cylin, sz);
553 1.1 leo #endif
554 1.1 leo
555 1.1 leo /* Queue transfer on drive, activate drive and controller if idle. */
556 1.1 leo s = splbio();
557 1.1 leo disksort(&fd->sc_q, bp);
558 1.1 leo untimeout(fd_motor_off, fd); /* a good idea */
559 1.1 leo if (!fd->sc_q.b_active)
560 1.1 leo fdstart(fd);
561 1.1 leo #ifdef DIAGNOSTIC
562 1.1 leo else {
563 1.1 leo struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
564 1.1 leo if (fdc->sc_state == DEVIDLE) {
565 1.1 leo printf("fdstrategy: controller inactive\n");
566 1.1 leo fdcstart(fdc);
567 1.1 leo }
568 1.1 leo }
569 1.1 leo #endif
570 1.1 leo splx(s);
571 1.1 leo return;
572 1.1 leo
573 1.1 leo bad:
574 1.1 leo bp->b_flags |= B_ERROR;
575 1.1 leo done:
576 1.1 leo /* Toss transfer; we're done early. */
577 1.1 leo bp->b_resid = bp->b_bcount;
578 1.1 leo biodone(bp);
579 1.1 leo }
580 1.1 leo
581 1.1 leo void
582 1.1 leo fdstart(fd)
583 1.1 leo struct fd_softc *fd;
584 1.1 leo {
585 1.1 leo struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
586 1.1 leo int active = fdc->sc_drives.tqh_first != 0;
587 1.1 leo
588 1.1 leo /* Link into controller queue. */
589 1.1 leo fd->sc_q.b_active = 1;
590 1.1 leo TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
591 1.1 leo
592 1.1 leo /* If controller not already active, start it. */
593 1.1 leo if (!active)
594 1.1 leo fdcstart(fdc);
595 1.1 leo }
596 1.1 leo
597 1.1 leo void
598 1.1 leo fdfinish(fd, bp)
599 1.1 leo struct fd_softc *fd;
600 1.1 leo struct buf *bp;
601 1.1 leo {
602 1.1 leo struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
603 1.1 leo
604 1.1 leo /*
605 1.1 leo * Move this drive to the end of the queue to give others a `fair'
606 1.1 leo * chance. We only force a switch if N operations are completed while
607 1.1 leo * another drive is waiting to be serviced, since there is a long motor
608 1.1 leo * startup delay whenever we switch.
609 1.1 leo */
610 1.1 leo if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
611 1.1 leo fd->sc_ops = 0;
612 1.1 leo TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
613 1.1 leo if (bp->b_actf) {
614 1.1 leo TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
615 1.1 leo } else
616 1.1 leo fd->sc_q.b_active = 0;
617 1.1 leo }
618 1.1 leo bp->b_resid = fd->sc_bcount;
619 1.1 leo fd->sc_skip = 0;
620 1.1 leo fd->sc_q.b_actf = bp->b_actf;
621 1.1 leo
622 1.1 leo biodone(bp);
623 1.1 leo /* turn off motor 5s from now */
624 1.1 leo timeout(fd_motor_off, fd, 5 * hz);
625 1.1 leo fdc->sc_state = DEVIDLE;
626 1.1 leo }
627 1.1 leo
628 1.1 leo int
629 1.1 leo fdread(dev, uio, flags)
630 1.1 leo dev_t dev;
631 1.1 leo struct uio *uio;
632 1.1 leo int flags;
633 1.1 leo {
634 1.1 leo return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
635 1.1 leo }
636 1.1 leo
637 1.1 leo int
638 1.1 leo fdwrite(dev, uio, flags)
639 1.1 leo dev_t dev;
640 1.1 leo struct uio *uio;
641 1.1 leo int flags;
642 1.1 leo {
643 1.1 leo return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
644 1.1 leo }
645 1.1 leo
646 1.1 leo void
647 1.1 leo fd_set_motor(fdc, reset)
648 1.1 leo struct fdc_softc *fdc;
649 1.1 leo int reset;
650 1.1 leo {
651 1.1 leo struct fd_softc *fd;
652 1.1 leo u_char status;
653 1.1 leo int n;
654 1.1 leo
655 1.1 leo if ((fd = fdc->sc_drives.tqh_first) != NULL)
656 1.1 leo status = fd->sc_drive;
657 1.1 leo else
658 1.1 leo status = 0;
659 1.1 leo if (!reset)
660 1.1 leo status |= FDO_FRST | FDO_FDMAEN;
661 1.1 leo for (n = 0; n < 4; n++)
662 1.1 leo if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
663 1.1 leo status |= FDO_MOEN(n);
664 1.1 leo wrt_fdc_reg(fdout, status);
665 1.1 leo }
666 1.1 leo
667 1.1 leo void
668 1.1 leo fd_motor_off(arg)
669 1.1 leo void *arg;
670 1.1 leo {
671 1.1 leo struct fd_softc *fd = arg;
672 1.1 leo int s;
673 1.1 leo
674 1.1 leo s = splbio();
675 1.1 leo fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
676 1.1 leo fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
677 1.1 leo splx(s);
678 1.1 leo }
679 1.1 leo
680 1.1 leo void
681 1.1 leo fd_motor_on(arg)
682 1.1 leo void *arg;
683 1.1 leo {
684 1.1 leo struct fd_softc *fd = arg;
685 1.1 leo struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
686 1.1 leo int s;
687 1.1 leo
688 1.1 leo s = splbio();
689 1.1 leo fd->sc_flags &= ~FD_MOTOR_WAIT;
690 1.1 leo if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
691 1.1 leo (void) fdcintr(fdc);
692 1.1 leo splx(s);
693 1.1 leo }
694 1.1 leo
695 1.1 leo int
696 1.1 leo fdcresult(fdc)
697 1.1 leo struct fdc_softc *fdc;
698 1.1 leo {
699 1.1 leo u_char i;
700 1.1 leo int j = 100000,
701 1.1 leo n = 0;
702 1.1 leo
703 1.1 leo for (; j; j--) {
704 1.1 leo i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
705 1.1 leo if (i == NE7_RQM)
706 1.1 leo return n;
707 1.1 leo if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
708 1.1 leo if (n >= sizeof(fdc->sc_status)) {
709 1.1 leo log(LOG_ERR, "fdcresult: overrun\n");
710 1.1 leo return -1;
711 1.1 leo }
712 1.1 leo fdc->sc_status[n++] = rd_fdc_reg(fddata);
713 1.1 leo }
714 1.1 leo }
715 1.1 leo log(LOG_ERR, "fdcresult: timeout\n");
716 1.1 leo return -1;
717 1.1 leo }
718 1.1 leo
719 1.1 leo int
720 1.1 leo out_fdc(x)
721 1.1 leo u_char x;
722 1.1 leo {
723 1.1 leo int i = 100000;
724 1.1 leo
725 1.1 leo while ((rd_fdc_reg(fdsts) & NE7_RQM) == 0 && i-- > 0);
726 1.1 leo if (i <= 0)
727 1.1 leo return -1;
728 1.1 leo while ((rd_fdc_reg(fdsts) & NE7_DIO) && i-- > 0);
729 1.1 leo if (i <= 0)
730 1.1 leo return -1;
731 1.1 leo wrt_fdc_reg(fddata, x);
732 1.1 leo return 0;
733 1.1 leo }
734 1.1 leo
735 1.1 leo int
736 1.1 leo fdopen(dev, flags, mode, p)
737 1.1 leo dev_t dev;
738 1.1 leo int flags;
739 1.1 leo int mode;
740 1.1 leo struct proc *p;
741 1.1 leo {
742 1.1 leo int unit;
743 1.1 leo struct fd_softc *fd;
744 1.1 leo struct fd_type *type;
745 1.1 leo
746 1.1 leo unit = FDUNIT(dev);
747 1.1 leo if (unit >= hdfd_cd.cd_ndevs)
748 1.1 leo return ENXIO;
749 1.1 leo fd = hdfd_cd.cd_devs[unit];
750 1.1 leo if (fd == 0)
751 1.1 leo return ENXIO;
752 1.1 leo type = fd_dev_to_type(fd, dev);
753 1.1 leo if (type == NULL)
754 1.1 leo return ENXIO;
755 1.1 leo
756 1.1 leo if ((fd->sc_flags & FD_OPEN) != 0 &&
757 1.1 leo fd->sc_type != type)
758 1.1 leo return EBUSY;
759 1.1 leo
760 1.1 leo fd->sc_type = type;
761 1.1 leo fd->sc_cylin = -1;
762 1.1 leo fd->sc_flags |= FD_OPEN;
763 1.1 leo
764 1.1 leo return 0;
765 1.1 leo }
766 1.1 leo
767 1.1 leo int
768 1.1 leo fdclose(dev, flags, mode, p)
769 1.1 leo dev_t dev;
770 1.1 leo int flags;
771 1.1 leo int mode;
772 1.1 leo struct proc *p;
773 1.1 leo {
774 1.1 leo struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
775 1.1 leo
776 1.1 leo fd->sc_flags &= ~FD_OPEN;
777 1.1 leo return 0;
778 1.1 leo }
779 1.1 leo
780 1.1 leo void
781 1.1 leo fdcstart(fdc)
782 1.1 leo struct fdc_softc *fdc;
783 1.1 leo {
784 1.1 leo
785 1.1 leo #ifdef DIAGNOSTIC
786 1.1 leo /* only got here if controller's drive queue was inactive; should
787 1.1 leo be in idle state */
788 1.1 leo if (fdc->sc_state != DEVIDLE) {
789 1.1 leo printf("fdcstart: not idle\n");
790 1.1 leo return;
791 1.1 leo }
792 1.1 leo #endif
793 1.1 leo (void) fdcintr(fdc);
794 1.1 leo }
795 1.1 leo
796 1.1 leo void
797 1.1 leo fdcstatus(dv, n, s)
798 1.1 leo struct device *dv;
799 1.1 leo int n;
800 1.1 leo char *s;
801 1.1 leo {
802 1.1 leo struct fdc_softc *fdc = (void *)dv->dv_parent;
803 1.1 leo
804 1.1 leo if (n == 0) {
805 1.1 leo out_fdc(NE7CMD_SENSEI);
806 1.1 leo (void) fdcresult(fdc);
807 1.1 leo n = 2;
808 1.1 leo }
809 1.1 leo
810 1.1 leo printf("%s: %s", dv->dv_xname, s);
811 1.1 leo
812 1.1 leo switch (n) {
813 1.1 leo case 0:
814 1.1 leo printf("\n");
815 1.1 leo break;
816 1.1 leo case 2:
817 1.1 leo printf(" (st0 %b cyl %d)\n",
818 1.1 leo fdc->sc_status[0], NE7_ST0BITS,
819 1.1 leo fdc->sc_status[1]);
820 1.1 leo break;
821 1.1 leo case 7:
822 1.1 leo printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
823 1.1 leo fdc->sc_status[0], NE7_ST0BITS,
824 1.1 leo fdc->sc_status[1], NE7_ST1BITS,
825 1.1 leo fdc->sc_status[2], NE7_ST2BITS,
826 1.1 leo fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
827 1.1 leo break;
828 1.1 leo #ifdef DIAGNOSTIC
829 1.1 leo default:
830 1.1 leo printf("\nfdcstatus: weird size");
831 1.1 leo break;
832 1.1 leo #endif
833 1.1 leo }
834 1.1 leo }
835 1.1 leo
836 1.1 leo void
837 1.1 leo fdctimeout(arg)
838 1.1 leo void *arg;
839 1.1 leo {
840 1.1 leo struct fdc_softc *fdc = arg;
841 1.1 leo struct fd_softc *fd = fdc->sc_drives.tqh_first;
842 1.1 leo int s;
843 1.1 leo
844 1.1 leo s = splbio();
845 1.1 leo fdcstatus(&fd->sc_dev, 0, "timeout");
846 1.1 leo
847 1.1 leo if (fd->sc_q.b_actf)
848 1.1 leo fdc->sc_state++;
849 1.1 leo else
850 1.1 leo fdc->sc_state = DEVIDLE;
851 1.1 leo
852 1.1 leo (void) fdcintr(fdc);
853 1.1 leo splx(s);
854 1.1 leo }
855 1.1 leo
856 1.1 leo void
857 1.1 leo fdcpseudointr(arg)
858 1.1 leo void *arg;
859 1.1 leo {
860 1.1 leo int s;
861 1.1 leo
862 1.1 leo /* Just ensure it has the right spl. */
863 1.1 leo s = splbio();
864 1.1 leo (void) fdcintr(arg);
865 1.1 leo splx(s);
866 1.1 leo }
867 1.1 leo
868 1.1 leo int
869 1.1 leo fdcintr(arg)
870 1.1 leo void *arg;
871 1.1 leo {
872 1.1 leo struct fdc_softc *fdc = arg;
873 1.1 leo #define st0 fdc->sc_status[0]
874 1.1 leo #define st1 fdc->sc_status[1]
875 1.1 leo #define cyl fdc->sc_status[1]
876 1.1 leo struct fd_softc *fd;
877 1.1 leo struct buf *bp;
878 1.1 leo int read, head, sec, i, nblks;
879 1.1 leo struct fd_type *type;
880 1.1 leo
881 1.1 leo loop:
882 1.1 leo /* Is there a drive for the controller to do a transfer with? */
883 1.1 leo fd = fdc->sc_drives.tqh_first;
884 1.1 leo if (fd == NULL) {
885 1.1 leo fdc->sc_state = DEVIDLE;
886 1.1 leo return 1;
887 1.1 leo }
888 1.1 leo
889 1.1 leo /* Is there a transfer to this drive? If not, deactivate drive. */
890 1.1 leo bp = fd->sc_q.b_actf;
891 1.1 leo if (bp == NULL) {
892 1.1 leo fd->sc_ops = 0;
893 1.1 leo TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
894 1.1 leo fd->sc_q.b_active = 0;
895 1.1 leo goto loop;
896 1.1 leo }
897 1.1 leo
898 1.1 leo switch (fdc->sc_state) {
899 1.1 leo case DEVIDLE:
900 1.1 leo fdc->sc_errors = 0;
901 1.1 leo fdc->sc_overruns = 0;
902 1.1 leo fd->sc_skip = 0;
903 1.1 leo fd->sc_bcount = bp->b_bcount;
904 1.1 leo fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
905 1.1 leo untimeout(fd_motor_off, fd);
906 1.1 leo if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
907 1.1 leo fdc->sc_state = MOTORWAIT;
908 1.1 leo return 1;
909 1.1 leo }
910 1.1 leo if ((fd->sc_flags & FD_MOTOR) == 0) {
911 1.1 leo /* Turn on the motor, being careful about pairing. */
912 1.1 leo struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
913 1.1 leo if (ofd && ofd->sc_flags & FD_MOTOR) {
914 1.1 leo untimeout(fd_motor_off, ofd);
915 1.1 leo ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
916 1.1 leo }
917 1.1 leo fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
918 1.1 leo fd_set_motor(fdc, 0);
919 1.1 leo fdc->sc_state = MOTORWAIT;
920 1.1 leo /* Allow .25s for motor to stabilize. */
921 1.1 leo timeout(fd_motor_on, fd, hz / 4);
922 1.1 leo return 1;
923 1.1 leo }
924 1.1 leo /* Make sure the right drive is selected. */
925 1.1 leo fd_set_motor(fdc, 0);
926 1.1 leo
927 1.1 leo /* fall through */
928 1.1 leo case DOSEEK:
929 1.1 leo doseek:
930 1.1 leo if (fd->sc_cylin == bp->b_cylin)
931 1.1 leo goto doio;
932 1.1 leo
933 1.1 leo out_fdc(NE7CMD_SPECIFY);/* specify command */
934 1.1 leo out_fdc(fd->sc_type->steprate);
935 1.1 leo out_fdc(0x7); /* XXX head load time == 6ms - non-dma */
936 1.1 leo
937 1.1 leo fdc_ienable();
938 1.1 leo
939 1.1 leo out_fdc(NE7CMD_SEEK); /* seek function */
940 1.1 leo out_fdc(fd->sc_drive); /* drive number */
941 1.1 leo out_fdc(bp->b_cylin * fd->sc_type->step);
942 1.1 leo
943 1.1 leo fd->sc_cylin = -1;
944 1.1 leo fdc->sc_state = SEEKWAIT;
945 1.1 leo
946 1.1 leo fd->sc_dk.dk_seek++;
947 1.1 leo disk_busy(&fd->sc_dk);
948 1.1 leo
949 1.1 leo timeout(fdctimeout, fdc, 4 * hz);
950 1.1 leo return 1;
951 1.1 leo
952 1.1 leo case DOIO:
953 1.1 leo doio:
954 1.1 leo type = fd->sc_type;
955 1.1 leo sec = fd->sc_blkno % type->seccyl;
956 1.1 leo head = sec / type->sectrac;
957 1.1 leo sec -= head * type->sectrac;
958 1.1 leo nblks = type->sectrac - sec;
959 1.1 leo nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
960 1.1 leo nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
961 1.1 leo fd->sc_nblks = nblks;
962 1.1 leo fd->sc_nbytes = nblks * FDC_BSIZE;
963 1.1 leo #ifdef DIAGNOSTIC
964 1.1 leo {
965 1.1 leo int block;
966 1.1 leo
967 1.1 leo block = (fd->sc_cylin * type->heads + head)
968 1.1 leo * type->sectrac + sec;
969 1.1 leo if (block != fd->sc_blkno) {
970 1.1 leo printf("fdcintr: block %d != blkno %d\n",
971 1.1 leo block, fd->sc_blkno);
972 1.1 leo #ifdef DDB
973 1.1 leo Debugger();
974 1.1 leo #endif
975 1.1 leo }
976 1.1 leo }
977 1.1 leo #endif
978 1.1 leo read = bp->b_flags & B_READ ? 1 : 0;
979 1.1 leo
980 1.1 leo /*
981 1.1 leo * Setup pseudo-dma address & count
982 1.1 leo */
983 1.1 leo fddmaaddr = bp->b_data + fd->sc_skip;
984 1.1 leo fddmalen = fd->sc_nbytes;
985 1.1 leo
986 1.1 leo wrt_fdc_reg(fdctl, type->rate);
987 1.1 leo #ifdef FD_DEBUG
988 1.1 leo printf("fdcintr: %s drive %d track %d head %d sec %d"
989 1.1 leo " nblks %d\n", read ? "read" : "write",
990 1.1 leo fd->sc_drive, fd->sc_cylin, head, sec, nblks);
991 1.1 leo #endif
992 1.1 leo fdc_ienable();
993 1.1 leo
994 1.1 leo if (read)
995 1.1 leo out_fdc(NE7CMD_READ); /* READ */
996 1.1 leo else
997 1.1 leo out_fdc(NE7CMD_WRITE); /* WRITE */
998 1.1 leo out_fdc((head << 2) | fd->sc_drive);
999 1.1 leo out_fdc(fd->sc_cylin); /* track */
1000 1.1 leo out_fdc(head); /* head */
1001 1.1 leo out_fdc(sec + 1); /* sector +1 */
1002 1.1 leo out_fdc(type->secsize); /* sector size */
1003 1.1 leo out_fdc(sec + nblks); /* last sectors */
1004 1.1 leo out_fdc(type->gap1); /* gap1 size */
1005 1.1 leo out_fdc(type->datalen); /* data length */
1006 1.1 leo fdc->sc_state = IOCOMPLETE;
1007 1.1 leo
1008 1.1 leo disk_busy(&fd->sc_dk);
1009 1.1 leo
1010 1.1 leo /* allow 2 seconds for operation */
1011 1.1 leo timeout(fdctimeout, fdc, 2 * hz);
1012 1.1 leo return 1; /* will return later */
1013 1.1 leo
1014 1.1 leo case SEEKWAIT:
1015 1.1 leo untimeout(fdctimeout, fdc);
1016 1.1 leo fdc->sc_state = SEEKCOMPLETE;
1017 1.1 leo /* allow 1/50 second for heads to settle */
1018 1.1 leo timeout(fdcpseudointr, fdc, hz / 50);
1019 1.1 leo return 1;
1020 1.1 leo
1021 1.1 leo case SEEKCOMPLETE:
1022 1.1 leo disk_unbusy(&fd->sc_dk, 0); /* no data on seek */
1023 1.1 leo
1024 1.1 leo /* Make sure seek really happened. */
1025 1.1 leo out_fdc(NE7CMD_SENSEI);
1026 1.1 leo if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1027 1.1 leo cyl != bp->b_cylin * fd->sc_type->step) {
1028 1.1 leo #ifdef FD_DEBUG
1029 1.1 leo fdcstatus(&fd->sc_dev, 2, "seek failed");
1030 1.1 leo #endif
1031 1.1 leo fdcretry(fdc);
1032 1.1 leo goto loop;
1033 1.1 leo }
1034 1.1 leo fd->sc_cylin = bp->b_cylin;
1035 1.1 leo goto doio;
1036 1.1 leo
1037 1.1 leo case IOTIMEDOUT:
1038 1.1 leo case SEEKTIMEDOUT:
1039 1.1 leo case RECALTIMEDOUT:
1040 1.1 leo case RESETTIMEDOUT:
1041 1.1 leo fdcretry(fdc);
1042 1.1 leo goto loop;
1043 1.1 leo
1044 1.1 leo case IOCOMPLETE: /* IO DONE, post-analyze */
1045 1.1 leo untimeout(fdctimeout, fdc);
1046 1.1 leo
1047 1.1 leo disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1048 1.1 leo
1049 1.1 leo if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
1050 1.1 leo /*
1051 1.1 leo * As the damn chip doesn't seem to have a FIFO,
1052 1.1 leo * accept a few overruns as a fact of life *sigh*
1053 1.1 leo */
1054 1.1 leo if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
1055 1.1 leo fdc->sc_state = DOSEEK;
1056 1.1 leo goto loop;
1057 1.1 leo }
1058 1.1 leo #ifdef FD_DEBUG
1059 1.1 leo fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1060 1.1 leo "read failed" : "write failed");
1061 1.1 leo printf("blkno %d nblks %d\n",
1062 1.1 leo fd->sc_blkno, fd->sc_nblks);
1063 1.1 leo #endif
1064 1.1 leo fdcretry(fdc);
1065 1.1 leo goto loop;
1066 1.1 leo }
1067 1.1 leo if (fdc->sc_errors) {
1068 1.1 leo diskerr(bp, "fd", "soft error", LOG_PRINTF,
1069 1.1 leo fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1070 1.1 leo printf("\n");
1071 1.1 leo fdc->sc_errors = 0;
1072 1.1 leo }
1073 1.1 leo fdc->sc_overruns = 0;
1074 1.1 leo fd->sc_blkno += fd->sc_nblks;
1075 1.1 leo fd->sc_skip += fd->sc_nbytes;
1076 1.1 leo fd->sc_bcount -= fd->sc_nbytes;
1077 1.1 leo if (fd->sc_bcount > 0) {
1078 1.1 leo bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
1079 1.1 leo goto doseek;
1080 1.1 leo }
1081 1.1 leo fdfinish(fd, bp);
1082 1.1 leo goto loop;
1083 1.1 leo
1084 1.1 leo case DORESET:
1085 1.1 leo /* try a reset, keep motor on */
1086 1.1 leo fd_set_motor(fdc, 1);
1087 1.1 leo delay(100);
1088 1.1 leo fd_set_motor(fdc, 0);
1089 1.1 leo fdc->sc_state = RESETCOMPLETE;
1090 1.1 leo timeout(fdctimeout, fdc, hz / 2);
1091 1.1 leo return 1; /* will return later */
1092 1.1 leo
1093 1.1 leo case RESETCOMPLETE:
1094 1.1 leo untimeout(fdctimeout, fdc);
1095 1.1 leo /* clear the controller output buffer */
1096 1.1 leo for (i = 0; i < 4; i++) {
1097 1.1 leo out_fdc(NE7CMD_SENSEI);
1098 1.1 leo (void) fdcresult(fdc);
1099 1.1 leo }
1100 1.1 leo
1101 1.1 leo /* fall through */
1102 1.1 leo case DORECAL:
1103 1.1 leo fdc_ienable();
1104 1.1 leo
1105 1.1 leo out_fdc(NE7CMD_RECAL); /* recalibrate function */
1106 1.1 leo out_fdc(fd->sc_drive);
1107 1.1 leo fdc->sc_state = RECALWAIT;
1108 1.1 leo timeout(fdctimeout, fdc, 5 * hz);
1109 1.1 leo return 1; /* will return later */
1110 1.1 leo
1111 1.1 leo case RECALWAIT:
1112 1.1 leo untimeout(fdctimeout, fdc);
1113 1.1 leo fdc->sc_state = RECALCOMPLETE;
1114 1.1 leo /* allow 1/30 second for heads to settle */
1115 1.1 leo timeout(fdcpseudointr, fdc, hz / 30);
1116 1.1 leo return 1; /* will return later */
1117 1.1 leo
1118 1.1 leo case RECALCOMPLETE:
1119 1.1 leo out_fdc(NE7CMD_SENSEI);
1120 1.1 leo if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1121 1.1 leo #ifdef FD_DEBUG
1122 1.1 leo fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1123 1.1 leo #endif
1124 1.1 leo fdcretry(fdc);
1125 1.1 leo goto loop;
1126 1.1 leo }
1127 1.1 leo fd->sc_cylin = 0;
1128 1.1 leo goto doseek;
1129 1.1 leo
1130 1.1 leo case MOTORWAIT:
1131 1.1 leo if (fd->sc_flags & FD_MOTOR_WAIT)
1132 1.1 leo return 1; /* time's not up yet */
1133 1.1 leo goto doseek;
1134 1.1 leo
1135 1.1 leo default:
1136 1.1 leo fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1137 1.1 leo return 1;
1138 1.1 leo }
1139 1.1 leo #ifdef DIAGNOSTIC
1140 1.1 leo panic("fdcintr: impossible");
1141 1.1 leo #endif
1142 1.1 leo #undef st0
1143 1.1 leo #undef st1
1144 1.1 leo #undef cyl
1145 1.1 leo }
1146 1.1 leo
1147 1.1 leo void
1148 1.1 leo fdcretry(fdc)
1149 1.1 leo struct fdc_softc *fdc;
1150 1.1 leo {
1151 1.1 leo struct fd_softc *fd;
1152 1.1 leo struct buf *bp;
1153 1.1 leo
1154 1.1 leo fd = fdc->sc_drives.tqh_first;
1155 1.1 leo bp = fd->sc_q.b_actf;
1156 1.1 leo
1157 1.1 leo switch (fdc->sc_errors) {
1158 1.1 leo case 0:
1159 1.1 leo /* try again */
1160 1.1 leo fdc->sc_state = DOSEEK;
1161 1.1 leo break;
1162 1.1 leo
1163 1.1 leo case 1: case 2: case 3:
1164 1.1 leo /* didn't work; try recalibrating */
1165 1.1 leo fdc->sc_state = DORECAL;
1166 1.1 leo break;
1167 1.1 leo
1168 1.1 leo case 4:
1169 1.1 leo /* still no go; reset the bastard */
1170 1.1 leo fdc->sc_state = DORESET;
1171 1.1 leo break;
1172 1.1 leo
1173 1.1 leo default:
1174 1.1 leo diskerr(bp, "fd", "hard error", LOG_PRINTF,
1175 1.1 leo fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1176 1.1 leo printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
1177 1.1 leo fdc->sc_status[0], NE7_ST0BITS,
1178 1.1 leo fdc->sc_status[1], NE7_ST1BITS,
1179 1.1 leo fdc->sc_status[2], NE7_ST2BITS,
1180 1.1 leo fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1181 1.1 leo
1182 1.1 leo bp->b_flags |= B_ERROR;
1183 1.1 leo bp->b_error = EIO;
1184 1.1 leo fdfinish(fd, bp);
1185 1.1 leo }
1186 1.1 leo fdc->sc_errors++;
1187 1.1 leo }
1188 1.1 leo
1189 1.1 leo int
1190 1.1 leo fdsize(dev)
1191 1.1 leo dev_t dev;
1192 1.1 leo {
1193 1.1 leo
1194 1.1 leo /* Swapping to floppies would not make sense. */
1195 1.1 leo return -1;
1196 1.1 leo }
1197 1.1 leo
1198 1.1 leo int
1199 1.1 leo fddump(dev, blkno, va, size)
1200 1.1 leo dev_t dev;
1201 1.1 leo daddr_t blkno;
1202 1.1 leo caddr_t va;
1203 1.1 leo size_t size;
1204 1.1 leo {
1205 1.1 leo
1206 1.1 leo /* Not implemented. */
1207 1.1 leo return ENXIO;
1208 1.1 leo }
1209 1.1 leo
1210 1.1 leo int
1211 1.1 leo fdioctl(dev, cmd, addr, flag, p)
1212 1.1 leo dev_t dev;
1213 1.1 leo u_long cmd;
1214 1.1 leo caddr_t addr;
1215 1.1 leo int flag;
1216 1.1 leo struct proc *p;
1217 1.1 leo {
1218 1.1 leo struct fd_softc *fd;
1219 1.1 leo struct disklabel buffer;
1220 1.1 leo struct cpu_disklabel cpulab;
1221 1.1 leo int error;
1222 1.1 leo
1223 1.1 leo fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1224 1.1 leo
1225 1.1 leo switch (cmd) {
1226 1.1 leo case DIOCGDINFO:
1227 1.1 leo bzero(&buffer, sizeof(buffer));
1228 1.1 leo bzero(&cpulab, sizeof(cpulab));
1229 1.1 leo
1230 1.1 leo buffer.d_secpercyl = fd->sc_type->seccyl;
1231 1.1 leo buffer.d_type = DTYPE_FLOPPY;
1232 1.1 leo buffer.d_secsize = FDC_BSIZE;
1233 1.1 leo buffer.d_secperunit = fd->sc_type->size;
1234 1.1 leo
1235 1.1 leo if (readdisklabel(dev, fdstrategy, &buffer, &cpulab) != NULL)
1236 1.1 leo return EINVAL;
1237 1.1 leo *(struct disklabel *)addr = buffer;
1238 1.1 leo return 0;
1239 1.1 leo
1240 1.1 leo case DIOCWLABEL:
1241 1.1 leo if ((flag & FWRITE) == 0)
1242 1.1 leo return EBADF;
1243 1.1 leo /* XXX do something */
1244 1.1 leo return 0;
1245 1.1 leo
1246 1.1 leo case DIOCWDINFO:
1247 1.1 leo if ((flag & FWRITE) == 0)
1248 1.1 leo return EBADF;
1249 1.1 leo
1250 1.1 leo error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1251 1.1 leo if (error)
1252 1.1 leo return error;
1253 1.1 leo
1254 1.1 leo error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1255 1.1 leo return error;
1256 1.1 leo
1257 1.1 leo default:
1258 1.1 leo return ENOTTY;
1259 1.1 leo }
1260 1.1 leo
1261 1.1 leo #ifdef DIAGNOSTIC
1262 1.1 leo panic("fdioctl: impossible");
1263 1.1 leo #endif
1264 1.1 leo }
1265