1 /* $OpenBSD: fd.c,v 1.36 2004/04/02 04:31:21 deraadt Exp $ */
2 /* $NetBSD: fd.c,v 1.51 1997/05/24 20:16:19 pk Exp $ */
3
4 /*-
5 * Copyright (c) 1993, 1994, 1995 Charles Hannum.
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Don Ahn.
11 *
12 * Portions Copyright (c) 1993, 1994 by
13 * jc@irbs.UUCP (John Capo)
14 * vak@zebub.msk.su (Serge Vakulenko)
15 * ache@astral.msk.su (Andrew A. Chernov)
16 * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 * @(#)fd.c 7.4 (Berkeley) 5/25/91
43 */
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/file.h>
49 #include <sys/ioctl.h>
50 #include <sys/device.h>
51 #include <sys/disklabel.h>
52 #include <sys/dkstat.h>
53 #include <sys/disk.h>
54 #include <sys/buf.h>
55 #include <sys/malloc.h>
56 #include <sys/proc.h>
57 #include <sys/uio.h>
58 #include <sys/mtio.h>
59 #include <sys/stat.h>
60 #include <sys/syslog.h>
61 #include <sys/queue.h>
62 #include <sys/conf.h>
63 #include <sys/timeout.h>
64
65 #include <dev/cons.h>
66
67 #include <uvm/uvm_extern.h>
68
69 #include <machine/cpu.h>
70 #include <machine/autoconf.h>
71 #include <machine/conf.h>
72 #include <machine/ioctl_fd.h>
73
74 #include <sparc/sparc/auxioreg.h>
75 #include <sparc/dev/fdreg.h>
76 #include <sparc/dev/fdvar.h>
77
78 #define FDUNIT(dev) ((dev & 0x80) >> 7)
79 #define FDTYPE(dev) ((minor(dev) & 0x70) >> 4)
80 #define FDPART(dev) (minor(dev) & 0x0f)
81
82 /* XXX misuse a flag to identify format operation */
83 #define B_FORMAT B_XXX
84
85 #define b_cylin b_resid
86
87 #define FD_DEBUG
88 #ifdef FD_DEBUG
89 int fdc_debug = 0;
90 #endif
91
92 enum fdc_state {
93 DEVIDLE = 0,
94 MOTORWAIT,
95 DOSEEK,
96 SEEKWAIT,
97 SEEKTIMEDOUT,
98 SEEKCOMPLETE,
99 DOIO,
100 IOCOMPLETE,
101 IOTIMEDOUT,
102 DORESET,
103 RESETCOMPLETE,
104 RESETTIMEDOUT,
105 DORECAL,
106 RECALWAIT,
107 RECALTIMEDOUT,
108 RECALCOMPLETE,
109 };
110
111 /* software state, per controller */
112 struct fdc_softc {
113 struct device sc_dev; /* boilerplate */
114 struct intrhand sc_sih;
115 struct intrhand sc_hih;
116 caddr_t sc_reg;
117 struct fd_softc *sc_fd[4]; /* pointers to children */
118 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
119 enum fdc_state sc_state;
120 int sc_flags;
121 #define FDC_82077 0x01
122 #define FDC_NEEDHEADSETTLE 0x02
123 #define FDC_EIS 0x04
124 int sc_errors; /* number of retries so far */
125 int sc_overruns; /* number of DMA overruns */
126 int sc_cfg; /* current configuration */
127 struct fdcio sc_io;
128 #define sc_reg_msr sc_io.fdcio_reg_msr
129 #define sc_reg_fifo sc_io.fdcio_reg_fifo
130 #define sc_reg_dor sc_io.fdcio_reg_dor
131 #define sc_reg_drs sc_io.fdcio_reg_msr
132 #define sc_istate sc_io.fdcio_istate
133 #define sc_data sc_io.fdcio_data
134 #define sc_tc sc_io.fdcio_tc
135 #define sc_nstat sc_io.fdcio_nstat
136 #define sc_status sc_io.fdcio_status
137 #define sc_intrcnt sc_io.fdcio_intrcnt
138 struct timeout fdctimeout_to;
139 struct timeout fdcpseudointr_to;
140 };
141
142 #ifndef FDC_C_HANDLER
143 extern struct fdcio *fdciop;
144 #endif
145
146 /* controller driver configuration */
147 int fdcmatch(struct device *, void *, void *);
148 void fdcattach(struct device *, struct device *, void *);
149
150 struct cfattach fdc_ca = {
151 sizeof(struct fdc_softc), fdcmatch, fdcattach
152 };
153
154 struct cfdriver fdc_cd = {
155 NULL, "fdc", DV_DULL
156 };
157
158 __inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
159
160 /* The order of entries in the following table is important -- BEWARE! */
161 struct fd_type fd_types[] = {
162 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS, "1.44MB" }, /* 1.44MB diskette */
163 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
164 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
165 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
166 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
167 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
168 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
169 };
170
171 /* software state, per disk (with up to 4 disks per ctlr) */
172 struct fd_softc {
173 struct device sc_dv; /* generic device info */
174 struct disk sc_dk; /* generic disk info */
175
176 struct fd_type *sc_deftype; /* default type descriptor */
177 struct fd_type *sc_type; /* current type descriptor */
178
179 daddr_t sc_blkno; /* starting block number */
180 int sc_bcount; /* byte count left */
181 int sc_skip; /* bytes already transferred */
182 int sc_nblks; /* number of blocks currently transferring */
183 int sc_nbytes; /* number of bytes currently transferring */
184
185 int sc_drive; /* physical unit number */
186 int sc_flags;
187 #define FD_OPEN 0x01 /* it's open */
188 #define FD_MOTOR 0x02 /* motor should be on */
189 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
190 int sc_cylin; /* where we think the head is */
191 int sc_opts; /* user-set options */
192
193 void *sc_sdhook; /* shutdownhook cookie */
194
195 TAILQ_ENTRY(fd_softc) sc_drivechain;
196 int sc_ops; /* I/O ops since last switch */
197 struct buf sc_q; /* head of buf chain */
198
199 struct timeout fd_motor_on_to;
200 struct timeout fd_motor_off_to;
201 };
202
203 /* floppy driver configuration */
204 int fdmatch(struct device *, void *, void *);
205 void fdattach(struct device *, struct device *, void *);
206
207 struct cfattach fd_ca = {
208 sizeof(struct fd_softc), fdmatch, fdattach
209 };
210
211 struct cfdriver fd_cd = {
212 NULL, "fd", DV_DISK
213 };
214
215 void fdgetdisklabel(dev_t);
216 int fd_get_parms(struct fd_softc *);
217 void fdstrategy(struct buf *);
218 void fdstart(struct fd_softc *);
219 int fdprint(void *, const char *);
220
221 struct dkdriver fddkdriver = { fdstrategy };
222
223 struct fd_type *fd_nvtotype(char *, int, int);
224 void fd_set_motor(struct fdc_softc *fdc);
225 void fd_motor_off(void *arg);
226 void fd_motor_on(void *arg);
227 int fdcresult(struct fdc_softc *fdc);
228 int out_fdc(struct fdc_softc *fdc, u_char x);
229 void fdcstart(struct fdc_softc *fdc);
230 void fdcstatus(struct device *dv, int n, char *s);
231 void fdc_reset(struct fdc_softc *fdc);
232 void fdctimeout(void *arg);
233 void fdcpseudointr(void *arg);
234 #ifdef FDC_C_HANDLER
235 int fdchwintr(struct fdc_softc *);
236 #else
237 void fdchwintr(void);
238 #endif
239 int fdcswintr(struct fdc_softc *);
240 int fdcstate(struct fdc_softc *);
241 void fdcretry(struct fdc_softc *fdc);
242 void fdfinish(struct fd_softc *fd, struct buf *bp);
243 int fdformat(dev_t, struct fd_formb *, struct proc *);
244 void fd_do_eject(struct fd_softc *);
245 void fd_mountroot_hook(struct device *);
246 static void fdconf(struct fdc_softc *);
247
248 #if IPL_FDSOFT == 4
249 #define IE_FDSOFT IE_L4
250 #else
251 #error 4
252 #endif
253
254 #ifdef FDC_C_HANDLER
255 #if defined(SUN4M)
256 #define FD_SET_SWINTR do { \
257 if (CPU_ISSUN4M) \
258 raise(0, IPL_FDSOFT); \
259 else \
260 ienab_bis(IE_FDSOFT); \
261 } while(0)
262 #else
263 #define FD_SET_SWINTR ienab_bis(IE_FDSOFT)
264 #endif /* defined(SUN4M) */
265 #endif /* FDC_C_HANDLER */
266
267 #define OBP_FDNAME (CPU_ISSUN4M ? "SUNW,fdtwo" : "fd")
268
269 int
fdcmatch(parent,match,aux)270 fdcmatch(parent, match, aux)
271 struct device *parent;
272 void *match, *aux;
273 {
274 register struct confargs *ca = aux;
275 register struct romaux *ra = &ca->ca_ra;
276
277 /*
278 * Floppy doesn't exist on sun4.
279 */
280 if (CPU_ISSUN4)
281 return (0);
282
283 /*
284 * Floppy controller is on mainbus on sun4c.
285 */
286 if ((CPU_ISSUN4C) && (ca->ca_bustype != BUS_MAIN))
287 return (0);
288
289 /*
290 * Floppy controller is on obio on sun4m.
291 */
292 if ((CPU_ISSUN4M) && (ca->ca_bustype != BUS_OBIO))
293 return (0);
294
295 /* Sun PROMs call the controller an "fd" or "SUNW,fdtwo" */
296 if (strcmp(OBP_FDNAME, ra->ra_name))
297 return (0);
298
299 if (ca->ca_ra.ra_vaddr &&
300 probeget(ca->ca_ra.ra_vaddr, 1) == -1) {
301 return (0);
302 }
303
304 return (1);
305 }
306
307 /*
308 * Arguments passed between fdcattach and fdprobe.
309 */
310 struct fdc_attach_args {
311 int fa_drive;
312 struct bootpath *fa_bootpath;
313 struct fd_type *fa_deftype;
314 };
315
316 /*
317 * Print the location of a disk drive (called just before attaching the
318 * the drive). If `fdc' is not NULL, the drive was found but was not
319 * in the system config file; print the drive name as well.
320 * Return QUIET (config_find ignores this if the device was configured) to
321 * avoid printing `fdN not configured' messages.
322 */
323 int
fdprint(aux,fdc)324 fdprint(aux, fdc)
325 void *aux;
326 const char *fdc;
327 {
328 register struct fdc_attach_args *fa = aux;
329
330 if (!fdc)
331 printf(" drive %d", fa->fa_drive);
332 return (QUIET);
333 }
334
335 static void
fdconf(fdc)336 fdconf(fdc)
337 struct fdc_softc *fdc;
338 {
339 int vroom;
340
341 if (out_fdc(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10)
342 return;
343
344 /*
345 * dumpreg[7] seems to be a motor-off timeout; set it to whatever
346 * the PROM thinks is appropriate.
347 */
348 if ((vroom = fdc->sc_status[7]) == 0)
349 vroom = 0x64;
350
351 /* Configure controller to use FIFO and Implied Seek */
352 out_fdc(fdc, NE7CMD_CFG);
353 out_fdc(fdc, vroom);
354 out_fdc(fdc, fdc->sc_cfg);
355 out_fdc(fdc, 0); /* PRETRK */
356 /* No result phase */
357 }
358
359 void
fdcattach(parent,self,aux)360 fdcattach(parent, self, aux)
361 struct device *parent, *self;
362 void *aux;
363 {
364 register struct confargs *ca = aux;
365 struct fdc_softc *fdc = (void *)self;
366 struct fdc_attach_args fa;
367 struct bootpath *bp;
368 int pri;
369 char code;
370
371 if (ca->ca_ra.ra_vaddr)
372 fdc->sc_reg = (caddr_t)ca->ca_ra.ra_vaddr;
373 else
374 fdc->sc_reg = (caddr_t)mapiodev(ca->ca_ra.ra_reg, 0,
375 ca->ca_ra.ra_len);
376
377 fdc->sc_state = DEVIDLE;
378 fdc->sc_istate = ISTATE_IDLE;
379 fdc->sc_flags |= FDC_EIS;
380 TAILQ_INIT(&fdc->sc_drives);
381
382 pri = ca->ca_ra.ra_intr[0].int_pri;
383 #ifdef FDC_C_HANDLER
384 fdc->sc_hih.ih_fun = (void *)fdchwintr;
385 fdc->sc_hih.ih_arg = fdc;
386 intr_establish(pri, &fdc->sc_hih, IPL_FD);
387 #else
388 fdciop = &fdc->sc_io;
389 intr_fasttrap(pri, fdchwintr);
390 #endif
391 fdc->sc_sih.ih_fun = (void *)fdcswintr;
392 fdc->sc_sih.ih_arg = fdc;
393 intr_establish(IPL_FDSOFT, &fdc->sc_sih, IPL_BIO);
394
395 /* Assume a 82077 */
396 fdc->sc_reg_msr = &((struct fdreg_77 *)fdc->sc_reg)->fd_msr;
397 fdc->sc_reg_fifo = &((struct fdreg_77 *)fdc->sc_reg)->fd_fifo;
398 fdc->sc_reg_dor = &((struct fdreg_77 *)fdc->sc_reg)->fd_dor;
399
400 code = '7';
401 if (*fdc->sc_reg_dor == NE7_RQM) {
402 /*
403 * This hack from Chris Torek: apparently DOR really
404 * addresses MSR/DRS on a 82072.
405 * We used to rely on the VERSION command to tell the
406 * difference (which did not work).
407 */
408 *fdc->sc_reg_dor = FDC_250KBPS;
409 if (*fdc->sc_reg_dor == NE7_RQM)
410 code = '2';
411 }
412 if (code == '7') {
413 fdc->sc_flags |= FDC_82077;
414 } else {
415 fdc->sc_reg_msr = &((struct fdreg_72 *)fdc->sc_reg)->fd_msr;
416 fdc->sc_reg_fifo = &((struct fdreg_72 *)fdc->sc_reg)->fd_fifo;
417 fdc->sc_reg_dor = 0;
418 }
419
420 #ifdef FD_DEBUG
421 if (out_fdc(fdc, NE7CMD_VERSION) == 0 &&
422 fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) {
423 if (fdc_debug)
424 printf("[version cmd]");
425 }
426 #endif
427
428 /*
429 * Configure controller; enable FIFO, Implied seek, no POLL mode?.
430 * Note: CFG_EFIFO is active-low, initial threshold value: 8
431 */
432 fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK);
433 fdconf(fdc);
434
435 if (fdc->sc_flags & FDC_82077) {
436 /* Lock configuration across soft resets. */
437 out_fdc(fdc, NE7CMD_LOCK | CFG_LOCK);
438 if (fdcresult(fdc) != 1)
439 printf(" CFGLOCK: unexpected response");
440 }
441
442 evcnt_attach(&fdc->sc_dev, "intr", &fdc->sc_intrcnt);
443
444 printf(" pri %d, softpri %d: chip 8207%c\n", pri, IPL_FDSOFT, code);
445
446 /*
447 * Controller and drives are represented by one and the same
448 * Openprom node, so we can as well check for the floppy boots here.
449 */
450 fa.fa_bootpath = 0;
451 if ((bp = ca->ca_ra.ra_bp) && strcmp(bp->name, OBP_FDNAME) == 0) {
452
453 switch (ca->ca_bustype) {
454 case BUS_MAIN:
455 /*
456 * We can get the bootpath in several different
457 * formats! The faked v1 bootpath looks like /fd@0,0.
458 * The v2 bootpath is either just /fd0, in which case
459 * `bp->val[0]' will have been set to -1, or /fd@x,y
460 * where <x,y> is the prom address specifier.
461 */
462 if (((bp->val[0] == ca->ca_ra.ra_iospace) &&
463 (bp->val[1] == (int)ca->ca_ra.ra_paddr)) ||
464
465 ((bp->val[0] == -1) && /* v2: /fd0 */
466 (bp->val[1] == 0)) ||
467
468 ((bp->val[0] == 0) && /* v1: /fd@0,0 */
469 (bp->val[1] == 0))
470 )
471 fa.fa_bootpath = bp;
472 break;
473
474 case BUS_OBIO:
475 /*
476 * floppy controller on obio (such as on the sun4m),
477 * e.g.: `/obio0/SUNW,fdtwo@0,700000'.
478 * We use "slot, offset" to determine if this is the
479 * right one.
480 */
481 if ((bp->val[0] == ca->ca_slot) &&
482 (bp->val[1] == ca->ca_offset))
483 fa.fa_bootpath = bp;
484 break;
485 }
486
487 }
488
489 timeout_set(&fdc->fdctimeout_to, fdctimeout, fdc);
490 timeout_set(&fdc->fdcpseudointr_to, fdcpseudointr, fdc);
491
492 /*
493 * physical limit: four drives per controller, but the dev_t
494 * only has room for 2
495 */
496 for (fa.fa_drive = 0; fa.fa_drive < 2; fa.fa_drive++) {
497 fa.fa_deftype = NULL; /* unknown */
498 fa.fa_deftype = &fd_types[0]; /* XXX */
499 (void)config_found(self, (void *)&fa, fdprint);
500 }
501
502 bootpath_store(1, NULL);
503 }
504
505 int
fdmatch(parent,match,aux)506 fdmatch(parent, match, aux)
507 struct device *parent;
508 void *match, *aux;
509 {
510 struct fdc_softc *fdc = (void *)parent;
511 struct fdc_attach_args *fa = aux;
512 int drive = fa->fa_drive;
513 int n, ok;
514
515 if (drive > 0)
516 /* XXX - for now, punt on more than one drive */
517 return (0);
518
519 if (fdc->sc_flags & FDC_82077) {
520 /* select drive and turn on motor */
521 *fdc->sc_reg_dor = drive | FDO_FRST | FDO_MOEN(drive);
522 } else {
523 auxregbisc(AUXIO4C_FDS, 0);
524 }
525 /* wait for motor to spin up */
526 delay(250000);
527
528 fdc->sc_nstat = 0;
529 out_fdc(fdc, NE7CMD_RECAL);
530 out_fdc(fdc, drive);
531 /* wait for recalibrate */
532 for (n = 0; n < 10000; n++) {
533 delay(1000);
534 if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) {
535 /* wait a bit longer till device *really* is ready */
536 delay(100000);
537 if (out_fdc(fdc, NE7CMD_SENSEI))
538 break;
539 if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80)
540 /*
541 * Got `invalid command'; we interpret it
542 * to mean that the re-calibrate hasn't in
543 * fact finished yet
544 */
545 continue;
546 break;
547 }
548 }
549 n = fdc->sc_nstat;
550 #ifdef FD_DEBUG
551 if (fdc_debug) {
552 int i;
553 printf("fdprobe: %d stati:", n);
554 for (i = 0; i < n; i++)
555 printf(" %x", fdc->sc_status[i]);
556 printf("\n");
557 }
558 #endif
559 ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0;
560
561 /* turn off motor */
562 if (fdc->sc_flags & FDC_82077) {
563 /* deselect drive and turn motor off */
564 *fdc->sc_reg_dor = FDO_FRST | FDO_DS;
565 } else {
566 auxregbisc(0, AUXIO4C_FDS);
567 }
568
569 return (ok);
570 }
571
572 /*
573 * Controller is working, and drive responded. Attach it.
574 */
575 void
fdattach(parent,self,aux)576 fdattach(parent, self, aux)
577 struct device *parent, *self;
578 void *aux;
579 {
580 struct fdc_softc *fdc = (void *)parent;
581 struct fd_softc *fd = (void *)self;
582 struct fdc_attach_args *fa = aux;
583 struct fd_type *type = fa->fa_deftype;
584 int drive = fa->fa_drive;
585
586 /* XXX Allow `flags' to override device type? */
587
588 if (type)
589 printf(": %s %d cyl, %d head, %d sec\n", type->name,
590 type->tracks, type->heads, type->sectrac);
591 else
592 printf(": density unknown\n");
593
594 fd->sc_cylin = -1;
595 fd->sc_drive = drive;
596 fd->sc_deftype = type;
597 fdc->sc_fd[drive] = fd;
598
599 out_fdc(fdc, NE7CMD_SPECIFY);
600 out_fdc(fdc, type->steprate);
601 out_fdc(fdc, 6 | NE7_SPECIFY_NODMA);
602
603 /*
604 * Initialize and attach the disk structure.
605 */
606 fd->sc_dk.dk_name = fd->sc_dv.dv_xname;
607 fd->sc_dk.dk_driver = &fddkdriver;
608 disk_attach(&fd->sc_dk);
609
610 /*
611 * We're told if we're the boot device in fdcattach().
612 */
613 if (fa->fa_bootpath)
614 fa->fa_bootpath->dev = &fd->sc_dv;
615
616 /*
617 * Establish a mountroot_hook anyway in case we booted
618 * with RB_ASKNAME and get selected as the boot device.
619 */
620 mountroot_hook_establish(fd_mountroot_hook, &fd->sc_dv);
621
622 /* Make sure the drive motor gets turned off at shutdown time. */
623 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
624
625 /* XXX Need to do some more fiddling with sc_dk. */
626 dk_establish(&fd->sc_dk, &fd->sc_dv);
627
628 /* Setup timeouts */
629 timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
630 timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
631 }
632
633 __inline struct fd_type *
fd_dev_to_type(fd,dev)634 fd_dev_to_type(fd, dev)
635 struct fd_softc *fd;
636 dev_t dev;
637 {
638 int type = FDTYPE(dev);
639
640 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
641 return (NULL);
642 return (type ? &fd_types[type - 1] : fd->sc_deftype);
643 }
644
645 void
fdstrategy(bp)646 fdstrategy(bp)
647 register struct buf *bp; /* IO operation to perform */
648 {
649 struct fd_softc *fd;
650 int unit = FDUNIT(bp->b_dev);
651 int sz;
652 int s;
653
654 /* Valid unit, controller, and request? */
655 if (unit >= fd_cd.cd_ndevs ||
656 (fd = fd_cd.cd_devs[unit]) == 0 ||
657 bp->b_blkno < 0 ||
658 ((bp->b_bcount % FDC_BSIZE) != 0 &&
659 (bp->b_flags & B_FORMAT) == 0)) {
660 bp->b_error = EINVAL;
661 goto bad;
662 }
663
664 /* If it's a null transfer, return immediately. */
665 if (bp->b_bcount == 0)
666 goto done;
667
668 sz = howmany(bp->b_bcount, FDC_BSIZE);
669
670 if (bp->b_blkno + sz > fd->sc_type->size) {
671 sz = fd->sc_type->size - bp->b_blkno;
672 if (sz == 0) {
673 /* If exactly at end of disk, return EOF. */
674 bp->b_resid = bp->b_bcount;
675 goto done;
676 }
677 if (sz < 0) {
678 /* If past end of disk, return EINVAL. */
679 bp->b_error = EINVAL;
680 goto bad;
681 }
682 /* Otherwise, truncate request. */
683 bp->b_bcount = sz << DEV_BSHIFT;
684 }
685
686 bp->b_cylin = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
687
688 #ifdef FD_DEBUG
689 if (fdc_debug > 1)
690 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %d cylin %ld\n",
691 bp->b_blkno, bp->b_bcount, fd->sc_blkno, (long)bp->b_cylin);
692 #endif
693
694 /* Queue transfer on drive, activate drive and controller if idle. */
695 s = splbio();
696 disksort(&fd->sc_q, bp);
697 timeout_del(&fd->fd_motor_off_to); /* a good idea */
698 if (!fd->sc_q.b_active)
699 fdstart(fd);
700 #ifdef DIAGNOSTIC
701 else {
702 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
703 if (fdc->sc_state == DEVIDLE) {
704 printf("fdstrategy: controller inactive\n");
705 fdcstart(fdc);
706 }
707 }
708 #endif
709 splx(s);
710 return;
711
712 bad:
713 bp->b_flags |= B_ERROR;
714 done:
715 /* Toss transfer; we're done early. */
716 s = splbio();
717 biodone(bp);
718 splx(s);
719 }
720
721 void
fdstart(fd)722 fdstart(fd)
723 struct fd_softc *fd;
724 {
725 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
726 int active = fdc->sc_drives.tqh_first != 0;
727
728 /* Link into controller queue. */
729 fd->sc_q.b_active = 1;
730 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
731
732 /* If controller not already active, start it. */
733 if (!active)
734 fdcstart(fdc);
735 }
736
737 void
fdfinish(fd,bp)738 fdfinish(fd, bp)
739 struct fd_softc *fd;
740 struct buf *bp;
741 {
742 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
743
744 /*
745 * Move this drive to the end of the queue to give others a `fair'
746 * chance. We only force a switch if N operations are completed while
747 * another drive is waiting to be serviced, since there is a long motor
748 * startup delay whenever we switch.
749 */
750 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
751 fd->sc_ops = 0;
752 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
753 if (bp->b_actf) {
754 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
755 } else
756 fd->sc_q.b_active = 0;
757 }
758 bp->b_resid = fd->sc_bcount;
759 fd->sc_skip = 0;
760 fd->sc_q.b_actf = bp->b_actf;
761
762 biodone(bp);
763 /* turn off motor 5s from now */
764 timeout_add(&fd->fd_motor_off_to, 5 * hz);
765 fdc->sc_state = DEVIDLE;
766 }
767
768 void
fdc_reset(fdc)769 fdc_reset(fdc)
770 struct fdc_softc *fdc;
771 {
772 if (fdc->sc_flags & FDC_82077) {
773 *fdc->sc_reg_dor = FDO_FDMAEN | FDO_MOEN(0);
774 }
775
776 *fdc->sc_reg_drs = DRS_RESET;
777 delay(10);
778 *fdc->sc_reg_drs = 0;
779
780 if (fdc->sc_flags & FDC_82077) {
781 *fdc->sc_reg_dor = FDO_FRST | FDO_FDMAEN | FDO_DS;
782 }
783 #ifdef FD_DEBUG
784 if (fdc_debug)
785 printf("fdc reset\n");
786 #endif
787 }
788
789 void
fd_set_motor(fdc)790 fd_set_motor(fdc)
791 struct fdc_softc *fdc;
792 {
793 struct fd_softc *fd;
794 u_char status;
795 int n;
796
797 if (fdc->sc_flags & FDC_82077) {
798 status = FDO_FRST | FDO_FDMAEN;
799 if ((fd = fdc->sc_drives.tqh_first) != NULL)
800 status |= fd->sc_drive;
801
802 for (n = 0; n < 4; n++)
803 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
804 status |= FDO_MOEN(n);
805 *fdc->sc_reg_dor = status;
806 } else {
807 int on = 0;
808
809 for (n = 0; n < 4; n++)
810 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
811 on = 1;
812 if (on) {
813 auxregbisc(AUXIO4C_FDS, 0);
814 } else {
815 auxregbisc(0, AUXIO4C_FDS);
816 }
817 }
818 }
819
820 void
fd_motor_off(arg)821 fd_motor_off(arg)
822 void *arg;
823 {
824 struct fd_softc *fd = arg;
825 int s;
826
827 s = splbio();
828 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
829 fd_set_motor((struct fdc_softc *)fd->sc_dv.dv_parent);
830 splx(s);
831 }
832
833 void
fd_motor_on(arg)834 fd_motor_on(arg)
835 void *arg;
836 {
837 struct fd_softc *fd = arg;
838 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
839 int s;
840
841 s = splbio();
842 fd->sc_flags &= ~FD_MOTOR_WAIT;
843 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
844 (void) fdcstate(fdc);
845 splx(s);
846 }
847
848 int
fdcresult(fdc)849 fdcresult(fdc)
850 struct fdc_softc *fdc;
851 {
852 u_char i;
853 int j = 100000,
854 n = 0;
855
856 for (; j; j--) {
857 i = *fdc->sc_reg_msr & (NE7_DIO | NE7_RQM | NE7_CB);
858 if (i == NE7_RQM)
859 return (fdc->sc_nstat = n);
860 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
861 if (n >= sizeof(fdc->sc_status)) {
862 log(LOG_ERR, "fdcresult: overrun\n");
863 return (-1);
864 }
865 fdc->sc_status[n++] = *fdc->sc_reg_fifo;
866 } else
867 delay(10);
868 }
869 log(LOG_ERR, "fdcresult: timeout\n");
870 return (fdc->sc_nstat = -1);
871 }
872
873 int
out_fdc(fdc,x)874 out_fdc(fdc, x)
875 struct fdc_softc *fdc;
876 u_char x;
877 {
878 int i = 100000;
879
880 while (((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
881 delay(1);
882 if (i <= 0)
883 return (-1);
884
885 *fdc->sc_reg_fifo = x;
886 return (0);
887 }
888
889 int
fdopen(dev,flags,fmt,p)890 fdopen(dev, flags, fmt, p)
891 dev_t dev;
892 int flags, fmt;
893 struct proc *p;
894 {
895 int unit, pmask;
896 struct fd_softc *fd;
897 struct fd_type *type;
898
899 unit = FDUNIT(dev);
900 if (unit >= fd_cd.cd_ndevs)
901 return (ENXIO);
902 fd = fd_cd.cd_devs[unit];
903 if (fd == 0)
904 return (ENXIO);
905 type = fd_dev_to_type(fd, dev);
906 if (type == NULL)
907 return (ENXIO);
908
909 if ((fd->sc_flags & FD_OPEN) != 0 &&
910 fd->sc_type != type)
911 return (EBUSY);
912
913 fd->sc_type = type;
914 fd->sc_cylin = -1;
915 fd->sc_flags |= FD_OPEN;
916
917 /*
918 * Only update the disklabel if we're not open anywhere else.
919 */
920 if (fd->sc_dk.dk_openmask == 0)
921 fdgetdisklabel(dev);
922
923 pmask = (1 << FDPART(dev));
924
925 switch (fmt) {
926 case S_IFCHR:
927 fd->sc_dk.dk_copenmask |= pmask;
928 break;
929
930 case S_IFBLK:
931 fd->sc_dk.dk_bopenmask |= pmask;
932 break;
933 }
934 fd->sc_dk.dk_openmask =
935 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
936
937 return (0);
938 }
939
940 int
fdclose(dev,flags,fmt,p)941 fdclose(dev, flags, fmt, p)
942 dev_t dev;
943 int flags, fmt;
944 struct proc *p;
945 {
946 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
947 int pmask = (1 << FDPART(dev));
948
949 fd->sc_flags &= ~FD_OPEN;
950 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
951
952 switch (fmt) {
953 case S_IFCHR:
954 fd->sc_dk.dk_copenmask &= ~pmask;
955 break;
956
957 case S_IFBLK:
958 fd->sc_dk.dk_bopenmask &= ~pmask;
959 break;
960 }
961 fd->sc_dk.dk_openmask =
962 fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
963
964 return (0);
965 }
966
967 int
fdread(dev,uio,flag)968 fdread(dev, uio, flag)
969 dev_t dev;
970 struct uio *uio;
971 int flag;
972 {
973
974 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
975 }
976
977 int
fdwrite(dev,uio,flag)978 fdwrite(dev, uio, flag)
979 dev_t dev;
980 struct uio *uio;
981 int flag;
982 {
983
984 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
985 }
986
987 void
fdcstart(fdc)988 fdcstart(fdc)
989 struct fdc_softc *fdc;
990 {
991
992 #ifdef DIAGNOSTIC
993 /* only got here if controller's drive queue was inactive; should
994 be in idle state */
995 if (fdc->sc_state != DEVIDLE) {
996 printf("fdcstart: not idle\n");
997 return;
998 }
999 #endif
1000 (void) fdcstate(fdc);
1001 }
1002
1003 void
fdcstatus(dv,n,s)1004 fdcstatus(dv, n, s)
1005 struct device *dv;
1006 int n;
1007 char *s;
1008 {
1009 struct fdc_softc *fdc = (void *)dv->dv_parent;
1010
1011 #if 0
1012 /*
1013 * A 82072 seems to return <invalid command> on
1014 * gratuitous Sense Interrupt commands.
1015 */
1016 if (n == 0 && (fdc->sc_flags & FDC_82077)) {
1017 out_fdc(fdc, NE7CMD_SENSEI);
1018 (void) fdcresult(fdc);
1019 n = 2;
1020 }
1021 #endif
1022
1023 /* Just print last status */
1024 n = fdc->sc_nstat;
1025
1026 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
1027
1028 switch (n) {
1029 case 0:
1030 printf("\n");
1031 break;
1032 case 2:
1033 printf(" (st0 %b cyl %d)\n",
1034 fdc->sc_status[0], NE7_ST0BITS,
1035 fdc->sc_status[1]);
1036 break;
1037 case 7:
1038 printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
1039 fdc->sc_status[0], NE7_ST0BITS,
1040 fdc->sc_status[1], NE7_ST1BITS,
1041 fdc->sc_status[2], NE7_ST2BITS,
1042 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1043 break;
1044 #ifdef DIAGNOSTIC
1045 default:
1046 printf(" fdcstatus: weird size: %d\n", n);
1047 break;
1048 #endif
1049 }
1050 }
1051
1052 void
fdctimeout(arg)1053 fdctimeout(arg)
1054 void *arg;
1055 {
1056 struct fdc_softc *fdc = arg;
1057 struct fd_softc *fd = fdc->sc_drives.tqh_first;
1058 int s;
1059
1060 s = splbio();
1061 fdcstatus(&fd->sc_dv, 0, "timeout");
1062
1063 if (fd->sc_q.b_actf)
1064 fdc->sc_state++;
1065 else
1066 fdc->sc_state = DEVIDLE;
1067
1068 (void) fdcstate(fdc);
1069 splx(s);
1070 }
1071
1072 void
fdcpseudointr(arg)1073 fdcpseudointr(arg)
1074 void *arg;
1075 {
1076 struct fdc_softc *fdc = arg;
1077 int s;
1078
1079 /* Just ensure it has the right spl. */
1080 s = splbio();
1081 (void) fdcstate(fdc);
1082 splx(s);
1083 }
1084
1085
1086 #ifdef FDC_C_HANDLER
1087 /*
1088 * hardware interrupt entry point: must be converted to `fast'
1089 * (in-window) handler.
1090 */
1091 int
fdchwintr(fdc)1092 fdchwintr(fdc)
1093 struct fdc_softc *fdc;
1094 {
1095
1096 switch (fdc->sc_istate) {
1097 case ISTATE_IDLE:
1098 return (0);
1099 case ISTATE_SENSEI:
1100 out_fdc(fdc, NE7CMD_SENSEI);
1101 fdcresult(fdc);
1102 fdc->sc_istate = ISTATE_IDLE;
1103 FD_SET_SWINTR;
1104 goto done;
1105 case ISTATE_SPURIOUS:
1106 fdcresult(fdc);
1107 fdc->sc_istate = ISTATE_SPURIOUS;
1108 printf("fdc: stray hard interrupt... ");
1109 FD_SET_SWINTR;
1110 goto done;
1111 case ISTATE_DMA:
1112 break;
1113 default:
1114 printf("fdc: goofed ...\n");
1115 goto done;
1116 }
1117
1118 for (;;) {
1119 register int msr;
1120
1121 msr = *fdc->sc_reg_msr;
1122
1123 if ((msr & NE7_RQM) == 0)
1124 break;
1125
1126 if ((msr & NE7_NDM) == 0) {
1127 fdcresult(fdc);
1128 fdc->sc_istate = ISTATE_IDLE;
1129 FD_SET_SWINTR;
1130 printf("fdc: overrun: tc = %d\n", fdc->sc_tc);
1131 break;
1132 }
1133
1134 if (msr & NE7_DIO) {
1135 *fdc->sc_data++ = *fdc->sc_reg_fifo;
1136 } else {
1137 *fdc->sc_reg_fifo = *fdc->sc_data++;
1138 }
1139 if (--fdc->sc_tc == 0) {
1140 fdc->sc_istate = ISTATE_DONE;
1141 FTC_FLIP;
1142 fdcresult(fdc);
1143 FD_SET_SWINTR;
1144 break;
1145 }
1146 }
1147 done:
1148 fdc->sc_intrcnt.ev_count++;
1149 return (1);
1150 }
1151 #endif
1152
1153 int
fdcswintr(fdc)1154 fdcswintr(fdc)
1155 struct fdc_softc *fdc;
1156 {
1157 int s;
1158
1159 if (fdc->sc_istate != ISTATE_DONE)
1160 return (0);
1161
1162 fdc->sc_istate = ISTATE_IDLE;
1163 s = splbio();
1164 fdcstate(fdc);
1165 splx(s);
1166 return (1);
1167 }
1168
1169 int
fdcstate(fdc)1170 fdcstate(fdc)
1171 struct fdc_softc *fdc;
1172 {
1173 #define st0 fdc->sc_status[0]
1174 #define st1 fdc->sc_status[1]
1175 #define cyl fdc->sc_status[1]
1176 #define OUT_FDC(fdc, c, s) \
1177 do { if (out_fdc(fdc, (c))) { (fdc)->sc_state = (s); goto loop; } } while(0)
1178
1179 struct fd_softc *fd;
1180 struct buf *bp;
1181 int read, head, sec, nblks;
1182 struct fd_type *type;
1183 struct fd_formb *finfo = NULL;
1184
1185
1186 if (fdc->sc_istate != ISTATE_IDLE) {
1187 /* Trouble... */
1188 printf("fdc: spurious interrupt: state %d, istate=%d\n",
1189 fdc->sc_state, fdc->sc_istate);
1190 fdc->sc_istate = ISTATE_IDLE;
1191 if (fdc->sc_state == RESETCOMPLETE ||
1192 fdc->sc_state == RESETTIMEDOUT) {
1193 panic("fdcintr: spurious interrupt can't be cleared");
1194 }
1195 goto doreset;
1196 }
1197
1198 loop:
1199 /* Is there a drive for the controller to do a transfer with? */
1200 fd = fdc->sc_drives.tqh_first;
1201 if (fd == NULL) {
1202 fdc->sc_state = DEVIDLE;
1203 return (0);
1204 }
1205
1206 /* Is there a transfer to this drive? If not, deactivate drive. */
1207 bp = fd->sc_q.b_actf;
1208 if (bp == NULL) {
1209 fd->sc_ops = 0;
1210 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1211 fd->sc_q.b_active = 0;
1212 goto loop;
1213 }
1214
1215 if (bp->b_flags & B_FORMAT)
1216 finfo = (struct fd_formb *)bp->b_data;
1217
1218 switch (fdc->sc_state) {
1219 case DEVIDLE:
1220 fdc->sc_errors = 0;
1221 fd->sc_skip = 0;
1222 fd->sc_bcount = bp->b_bcount;
1223 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1224 timeout_del(&fd->fd_motor_off_to);
1225 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1226 fdc->sc_state = MOTORWAIT;
1227 return (1);
1228 }
1229 if ((fd->sc_flags & FD_MOTOR) == 0) {
1230 /* Turn on the motor, being careful about pairing. */
1231 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1232 if (ofd && ofd->sc_flags & FD_MOTOR) {
1233 timeout_del(&ofd->fd_motor_off_to);
1234 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1235 }
1236 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1237 fd_set_motor(fdc);
1238 fdc->sc_state = MOTORWAIT;
1239 if (fdc->sc_flags & FDC_82077) { /* XXX */
1240 /* Allow .25s for motor to stabilize. */
1241 timeout_add(&fd->fd_motor_on_to, hz / 4);
1242 } else {
1243 fd->sc_flags &= ~FD_MOTOR_WAIT;
1244 goto loop;
1245 }
1246 return (1);
1247 }
1248 /* Make sure the right drive is selected. */
1249 fd_set_motor(fdc);
1250
1251 /*FALLTHROUGH*/
1252 case DOSEEK:
1253 doseek:
1254 if ((fdc->sc_flags & FDC_EIS) &&
1255 (bp->b_flags & B_FORMAT) == 0) {
1256 fd->sc_cylin = bp->b_cylin;
1257 /* We use implied seek */
1258 goto doio;
1259 }
1260
1261 if (fd->sc_cylin == bp->b_cylin)
1262 goto doio;
1263
1264 /* specify command */
1265 OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT);
1266 OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT);
1267 /* XXX head load time == 6ms */
1268 OUT_FDC(fdc, 6 | NE7_SPECIFY_NODMA, SEEKTIMEDOUT);
1269
1270 fdc->sc_istate = ISTATE_SENSEI;
1271 /* seek function */
1272 OUT_FDC(fdc, NE7CMD_SEEK, SEEKTIMEDOUT);
1273 OUT_FDC(fdc, fd->sc_drive, SEEKTIMEDOUT); /* drive number */
1274 OUT_FDC(fdc, bp->b_cylin * fd->sc_type->step, SEEKTIMEDOUT);
1275
1276 fd->sc_cylin = -1;
1277 fdc->sc_state = SEEKWAIT;
1278 fdc->sc_nstat = 0;
1279
1280 fd->sc_dk.dk_seek++;
1281 disk_busy(&fd->sc_dk);
1282
1283 timeout_add(&fdc->fdctimeout_to, 4 * hz);
1284 return (1);
1285
1286 case DOIO:
1287 doio:
1288 if (finfo != NULL)
1289 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1290 (char *)finfo;
1291 type = fd->sc_type;
1292 sec = fd->sc_blkno % type->seccyl;
1293 nblks = type->seccyl - sec;
1294 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1295 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1296 fd->sc_nblks = nblks;
1297 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1298 head = sec / type->sectrac;
1299 sec -= head * type->sectrac;
1300 #ifdef DIAGNOSTIC
1301 {int block;
1302 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
1303 if (block != fd->sc_blkno) {
1304 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1305 #ifdef DDB
1306 Debugger();
1307 #endif
1308 }}
1309 #endif
1310 read = bp->b_flags & B_READ;
1311
1312 /* Setup for pseudo DMA */
1313 fdc->sc_data = bp->b_data + fd->sc_skip;
1314 fdc->sc_tc = fd->sc_nbytes;
1315
1316 *fdc->sc_reg_drs = type->rate;
1317 #ifdef FD_DEBUG
1318 if (fdc_debug > 1)
1319 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1320 read ? "read" : "write", fd->sc_drive,
1321 fd->sc_cylin, head, sec, nblks);
1322 #endif
1323 fdc->sc_state = IOCOMPLETE;
1324 fdc->sc_istate = ISTATE_DMA;
1325 fdc->sc_nstat = 0;
1326 if (finfo != NULL) {
1327 /* formatting */
1328 OUT_FDC(fdc, NE7CMD_FORMAT, IOTIMEDOUT);
1329 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
1330 OUT_FDC(fdc, finfo->fd_formb_secshift, IOTIMEDOUT);
1331 OUT_FDC(fdc, finfo->fd_formb_nsecs, IOTIMEDOUT);
1332 OUT_FDC(fdc, finfo->fd_formb_gaplen, IOTIMEDOUT);
1333 OUT_FDC(fdc, finfo->fd_formb_fillbyte, IOTIMEDOUT);
1334 } else {
1335 if (read)
1336 OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT);
1337 else
1338 OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT);
1339 OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
1340 OUT_FDC(fdc, fd->sc_cylin, IOTIMEDOUT); /*track*/
1341 OUT_FDC(fdc, head, IOTIMEDOUT);
1342 OUT_FDC(fdc, sec + 1, IOTIMEDOUT); /*sector+1*/
1343 OUT_FDC(fdc, type->secsize, IOTIMEDOUT);/*sector size*/
1344 OUT_FDC(fdc, type->sectrac, IOTIMEDOUT);/*secs/track*/
1345 OUT_FDC(fdc, type->gap1, IOTIMEDOUT); /*gap1 size*/
1346 OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/*data length*/
1347 }
1348
1349 disk_busy(&fd->sc_dk);
1350
1351 /* allow 2 seconds for operation */
1352 timeout_add(&fdc->fdctimeout_to, 2 * hz);
1353 return (1); /* will return later */
1354
1355 case SEEKWAIT:
1356 timeout_del(&fdc->fdctimeout_to);
1357 fdc->sc_state = SEEKCOMPLETE;
1358 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1359 /* allow 1/50 second for heads to settle */
1360 timeout_add(&fdc->fdcpseudointr_to, hz / 50);
1361 return (1); /* will return later */
1362 }
1363 /*FALLTHROUGH*/
1364 case SEEKCOMPLETE:
1365 disk_unbusy(&fd->sc_dk, 0, 0); /* no data on seek */
1366
1367 /* Make sure seek really happened. */
1368 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 ||
1369 cyl != bp->b_cylin * fd->sc_type->step) {
1370 #ifdef FD_DEBUG
1371 if (fdc_debug)
1372 fdcstatus(&fd->sc_dv, 2, "seek failed");
1373 #endif
1374 fdcretry(fdc);
1375 goto loop;
1376 }
1377 fd->sc_cylin = bp->b_cylin;
1378 goto doio;
1379
1380 case IOTIMEDOUT:
1381 FTC_FLIP;
1382 (void)fdcresult(fdc);
1383 /*FALLTHROUGH*/
1384 case SEEKTIMEDOUT:
1385 case RECALTIMEDOUT:
1386 case RESETTIMEDOUT:
1387 fdcretry(fdc);
1388 goto loop;
1389
1390 case IOCOMPLETE: /* IO DONE, post-analyze */
1391 timeout_del(&fdc->fdctimeout_to);
1392
1393 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1394 (bp->b_flags & B_READ));
1395
1396 if (fdc->sc_nstat != 7 || st1 != 0 ||
1397 ((st0 & 0xf8) != 0 &&
1398 ((st0 & 0xf8) != 0x20 || (fdc->sc_cfg & CFG_EIS) == 0))) {
1399 #ifdef FD_DEBUG
1400 if (fdc_debug) {
1401 fdcstatus(&fd->sc_dv, 7,
1402 bp->b_flags & B_READ
1403 ? "read failed" : "write failed");
1404 printf("blkno %d nblks %d nstat %d tc %d\n",
1405 fd->sc_blkno, fd->sc_nblks,
1406 fdc->sc_nstat, fdc->sc_tc);
1407 }
1408 #endif
1409 if (fdc->sc_nstat == 7 &&
1410 (st1 & ST1_OVERRUN) == ST1_OVERRUN) {
1411
1412 /*
1413 * Silently retry overruns if no other
1414 * error bit is set. Adjust threshold.
1415 */
1416 int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1417 if (thr < 15) {
1418 thr++;
1419 fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1420 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1421 #ifdef FD_DEBUG
1422 if (fdc_debug)
1423 printf("fdc: %d -> threshold\n", thr);
1424 #endif
1425 fdconf(fdc);
1426 fdc->sc_overruns = 0;
1427 }
1428 if (++fdc->sc_overruns < 3) {
1429 fdc->sc_state = DOIO;
1430 goto loop;
1431 }
1432 }
1433 fdcretry(fdc);
1434 goto loop;
1435 }
1436 if (fdc->sc_errors) {
1437 diskerr(bp, "fd", "soft error", LOG_PRINTF,
1438 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1439 printf("\n");
1440 fdc->sc_errors = 0;
1441 } else {
1442 if (--fdc->sc_overruns < -20) {
1443 int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1444 if (thr > 0) {
1445 thr--;
1446 fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1447 fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1448 #ifdef FD_DEBUG
1449 if (fdc_debug)
1450 printf("fdc: %d -> threshold\n", thr);
1451 #endif
1452 fdconf(fdc);
1453 }
1454 fdc->sc_overruns = 0;
1455 }
1456 }
1457 fd->sc_blkno += fd->sc_nblks;
1458 fd->sc_skip += fd->sc_nbytes;
1459 fd->sc_bcount -= fd->sc_nbytes;
1460 if (finfo == NULL && fd->sc_bcount > 0) {
1461 bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
1462 goto doseek;
1463 }
1464 fdfinish(fd, bp);
1465 goto loop;
1466
1467 case DORESET:
1468 doreset:
1469 /* try a reset, keep motor on */
1470 fd_set_motor(fdc);
1471 delay(100);
1472 fdc_reset(fdc);
1473 fdc->sc_nstat = 0;
1474 fdc->sc_istate = ISTATE_SENSEI;
1475 fdc->sc_state = RESETCOMPLETE;
1476 timeout_add(&fdc->fdctimeout_to, hz / 2);
1477 return (1); /* will return later */
1478
1479 case RESETCOMPLETE:
1480 timeout_del(&fdc->fdctimeout_to);
1481 fdconf(fdc);
1482
1483 /* fall through */
1484 case DORECAL:
1485 fdc->sc_state = RECALWAIT;
1486 fdc->sc_istate = ISTATE_SENSEI;
1487 fdc->sc_nstat = 0;
1488 /* recalibrate function */
1489 OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT);
1490 OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT);
1491 timeout_add(&fdc->fdctimeout_to, 5 * hz);
1492 return (1); /* will return later */
1493
1494 case RECALWAIT:
1495 timeout_del(&fdc->fdctimeout_to);
1496 fdc->sc_state = RECALCOMPLETE;
1497 if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1498 /* allow 1/30 second for heads to settle */
1499 timeout_add(&fdc->fdcpseudointr_to, hz / 30);
1500 return (1); /* will return later */
1501 }
1502
1503 case RECALCOMPLETE:
1504 if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1505 #ifdef FD_DEBUG
1506 if (fdc_debug)
1507 fdcstatus(&fd->sc_dv, 2, "recalibrate failed");
1508 #endif
1509 fdcretry(fdc);
1510 goto loop;
1511 }
1512 fd->sc_cylin = 0;
1513 goto doseek;
1514
1515 case MOTORWAIT:
1516 if (fd->sc_flags & FD_MOTOR_WAIT)
1517 return (1); /* time's not up yet */
1518 goto doseek;
1519
1520 default:
1521 fdcstatus(&fd->sc_dv, 0, "stray interrupt");
1522 return (1);
1523 }
1524 #ifdef DIAGNOSTIC
1525 panic("fdcintr: impossible");
1526 #endif
1527 #undef st0
1528 #undef st1
1529 #undef cyl
1530 }
1531
1532 void
fdcretry(fdc)1533 fdcretry(fdc)
1534 struct fdc_softc *fdc;
1535 {
1536 struct fd_softc *fd;
1537 struct buf *bp;
1538
1539 fd = fdc->sc_drives.tqh_first;
1540 bp = fd->sc_q.b_actf;
1541
1542 fdc->sc_overruns = 0;
1543 if (fd->sc_opts & FDOPT_NORETRY)
1544 goto fail;
1545
1546 switch (fdc->sc_errors) {
1547 case 0:
1548 /* try again */
1549 fdc->sc_state =
1550 (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK;
1551 break;
1552
1553 case 1: case 2: case 3:
1554 /* didn't work; try recalibrating */
1555 fdc->sc_state = DORECAL;
1556 break;
1557
1558 case 4:
1559 /* still no go; reset the bastard */
1560 fdc->sc_state = DORESET;
1561 break;
1562
1563 default:
1564 fail:
1565 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1566 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1567 fd->sc_skip / FDC_BSIZE,
1568 (struct disklabel *)NULL);
1569
1570 printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
1571 fdc->sc_status[0], NE7_ST0BITS,
1572 fdc->sc_status[1], NE7_ST1BITS,
1573 fdc->sc_status[2], NE7_ST2BITS,
1574 fdc->sc_status[3], fdc->sc_status[4],
1575 fdc->sc_status[5]);
1576 }
1577
1578 bp->b_flags |= B_ERROR;
1579 bp->b_error = EIO;
1580 fdfinish(fd, bp);
1581 }
1582 fdc->sc_errors++;
1583 }
1584
1585 int
fdsize(dev)1586 fdsize(dev)
1587 dev_t dev;
1588 {
1589
1590 /* Swapping to floppies would not make sense. */
1591 return (-1);
1592 }
1593
1594 int
fddump(dev,blkno,va,size)1595 fddump(dev, blkno, va, size)
1596 dev_t dev;
1597 daddr_t blkno;
1598 caddr_t va;
1599 size_t size;
1600 {
1601
1602 /* Not implemented. */
1603 return (EINVAL);
1604 }
1605
1606 int
fdioctl(dev,cmd,addr,flag,p)1607 fdioctl(dev, cmd, addr, flag, p)
1608 dev_t dev;
1609 u_long cmd;
1610 caddr_t addr;
1611 int flag;
1612 struct proc *p;
1613 {
1614 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1615 int error;
1616
1617 switch (cmd) {
1618 case DIOCGDINFO:
1619 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1620 return 0;
1621
1622 case DIOCWLABEL:
1623 if ((flag & FWRITE) == 0)
1624 return EBADF;
1625 /* XXX do something */
1626 return (0);
1627
1628 case DIOCWDINFO:
1629 if ((flag & FWRITE) == 0)
1630 return (EBADF);
1631
1632 error = setdisklabel(fd->sc_dk.dk_label,
1633 (struct disklabel *)addr, 0,
1634 fd->sc_dk.dk_cpulabel);
1635 if (error)
1636 return (error);
1637
1638 error = writedisklabel(dev, fdstrategy,
1639 fd->sc_dk.dk_label,
1640 fd->sc_dk.dk_cpulabel);
1641 return (error);
1642
1643 case DIOCLOCK:
1644 /*
1645 * Nothing to do here, really.
1646 */
1647 return (0);
1648
1649 case MTIOCTOP:
1650 if (((struct mtop *)addr)->mt_op != MTOFFL)
1651 return EIO;
1652
1653 case DIOCEJECT:
1654 fd_do_eject(fd);
1655 return (0);
1656
1657 case FD_FORM:
1658 if((flag & FWRITE) == 0)
1659 return EBADF; /* must be opened for writing */
1660 else if(((struct fd_formb *)addr)->format_version !=
1661 FD_FORMAT_VERSION)
1662 return EINVAL; /* wrong version of formatting prog */
1663 else
1664 return fdformat(dev, (struct fd_formb *)addr, p);
1665 break;
1666
1667 case FD_GTYPE: /* get drive type */
1668 *(struct fd_type *)addr = *fd->sc_type;
1669 return (0);
1670
1671 case FD_GOPTS: /* get drive options */
1672 *(int *)addr = fd->sc_opts;
1673 return (0);
1674
1675 case FD_SOPTS: /* set drive options */
1676 fd->sc_opts = *(int *)addr;
1677 return (0);
1678
1679 #ifdef DEBUG
1680 case _IO('f', 100):
1681 {
1682 int i;
1683 struct fdc_softc *fdc = (struct fdc_softc *)
1684 fd->sc_dv.dv_parent;
1685
1686 out_fdc(fdc, NE7CMD_DUMPREG);
1687 fdcresult(fdc);
1688 printf("dumpreg(%d regs): <", fdc->sc_nstat);
1689 for (i = 0; i < fdc->sc_nstat; i++)
1690 printf(" %x", fdc->sc_status[i]);
1691 printf(">\n");
1692 }
1693
1694 return (0);
1695 case _IOW('f', 101, int):
1696 ((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg &=
1697 ~CFG_THRHLD_MASK;
1698 ((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg |=
1699 (*(int *)addr & CFG_THRHLD_MASK);
1700 fdconf((struct fdc_softc *) fd->sc_dv.dv_parent);
1701 return (0);
1702 case _IO('f', 102):
1703 {
1704 int i;
1705 struct fdc_softc *fdc = (struct fdc_softc *)
1706 fd->sc_dv.dv_parent;
1707 out_fdc(fdc, NE7CMD_SENSEI);
1708 fdcresult(fdc);
1709 printf("sensei(%d regs): <", fdc->sc_nstat);
1710 for (i=0; i< fdc->sc_nstat; i++)
1711 printf(" 0x%x", fdc->sc_status[i]);
1712 }
1713 printf(">\n");
1714 return (0);
1715 #endif
1716 default:
1717 return (ENOTTY);
1718 }
1719
1720 #ifdef DIAGNOSTIC
1721 panic("fdioctl: impossible");
1722 #endif
1723 }
1724
1725 int
fdformat(dev,finfo,p)1726 fdformat(dev, finfo, p)
1727 dev_t dev;
1728 struct fd_formb *finfo;
1729 struct proc *p;
1730 {
1731 int rv = 0, s;
1732 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1733 struct fd_type *type = fd->sc_type;
1734 struct buf *bp;
1735
1736 /* set up a buffer header for fdstrategy() */
1737 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1738 if (bp == 0)
1739 return (ENOBUFS);
1740
1741 PHOLD(p);
1742 bzero((void *)bp, sizeof(struct buf));
1743 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1744 bp->b_proc = p;
1745 bp->b_dev = dev;
1746
1747 /*
1748 * Calculate a fake blkno, so fdstrategy() would initiate a
1749 * seek to the requested cylinder.
1750 */
1751 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1752 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1753
1754 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1755 bp->b_data = (caddr_t)finfo;
1756
1757 #ifdef FD_DEBUG
1758 if (fdc_debug)
1759 printf("fdformat: blkno %x count %ld\n",
1760 bp->b_blkno, bp->b_bcount);
1761 #endif
1762
1763 /* now do the format */
1764 fdstrategy(bp);
1765
1766 /* ...and wait for it to complete */
1767 s = splbio();
1768 while (!(bp->b_flags & B_DONE)) {
1769 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1770 if (rv == EWOULDBLOCK)
1771 break;
1772 }
1773 splx(s);
1774
1775 if (rv == EWOULDBLOCK) {
1776 /* timed out */
1777 rv = EIO;
1778 s = splbio();
1779 biodone(bp);
1780 splx(s);
1781 }
1782 if (bp->b_flags & B_ERROR) {
1783 rv = bp->b_error;
1784 }
1785 PRELE(p);
1786 free(bp, M_TEMP);
1787 return (rv);
1788 }
1789
1790 void
fdgetdisklabel(dev)1791 fdgetdisklabel(dev)
1792 dev_t dev;
1793 {
1794 int unit = FDUNIT(dev);
1795 struct fd_softc *fd = fd_cd.cd_devs[unit];
1796 struct disklabel *lp = fd->sc_dk.dk_label;
1797 struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel;
1798 char *errstring;
1799
1800 bzero(lp, sizeof(struct disklabel));
1801 bzero(clp, sizeof(struct cpu_disklabel));
1802
1803 lp->d_secsize = FDC_BSIZE;
1804 lp->d_secpercyl = fd->sc_type->seccyl;
1805 lp->d_ntracks = fd->sc_type->heads; /* Go figure... */
1806 lp->d_nsectors = fd->sc_type->sectrac;
1807 lp->d_ncylinders = fd->sc_type->tracks;
1808
1809 strncpy(lp->d_typename, "floppy disk", sizeof(lp->d_typename));
1810 lp->d_type = DTYPE_FLOPPY;
1811 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1812 lp->d_rpm = 300; /* XXX like it matters... */
1813 lp->d_secperunit = fd->sc_type->size;
1814 lp->d_interleave = 1;
1815 lp->d_flags = D_REMOVABLE;
1816
1817 lp->d_partitions[RAW_PART].p_offset = 0;
1818 lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders;
1819 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1820 lp->d_npartitions = RAW_PART + 1;
1821
1822 lp->d_magic = DISKMAGIC;
1823 lp->d_magic2 = DISKMAGIC;
1824 lp->d_checksum = dkcksum(lp);
1825
1826 /*
1827 * Call the generic disklabel extraction routine.
1828 */
1829 errstring = readdisklabel(dev, fdstrategy, lp, clp, 0);
1830 if (errstring) {
1831 printf("%s: %s\n", fd->sc_dv.dv_xname, errstring);
1832 return;
1833 }
1834 }
1835
1836 void
fd_do_eject(fd)1837 fd_do_eject(fd)
1838 struct fd_softc *fd;
1839 {
1840 struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
1841
1842 if (CPU_ISSUN4C) {
1843 auxregbisc(AUXIO4C_FDS, AUXIO4C_FEJ);
1844 delay(10);
1845 auxregbisc(AUXIO4C_FEJ, AUXIO4C_FDS);
1846 return;
1847 }
1848 if (CPU_ISSUN4M && (fdc->sc_flags & FDC_82077)) {
1849 int dor = FDO_FRST | FDO_FDMAEN | FDO_MOEN(0);
1850 *fdc->sc_reg_dor = dor | FDO_EJ;
1851 delay(10);
1852 *fdc->sc_reg_dor = FDO_FRST | FDO_DS;
1853 return;
1854 }
1855 }
1856
1857 /*
1858 * The mountroot_hook is called once the root and swap device have been
1859 * established. NULL implies that we may have been the boot device but
1860 * haven't been elected for the root device.
1861 */
1862
1863 /* ARGSUSED */
1864 void
fd_mountroot_hook(dev)1865 fd_mountroot_hook(dev)
1866 struct device *dev;
1867 {
1868 int c;
1869
1870 if (dev) {
1871 fd_do_eject((struct fd_softc *)dev);
1872
1873 printf("Insert filesystem floppy and press return.");
1874 for (;;) {
1875 c = cngetc();
1876 if ((c == '\r') || (c == '\n')) {
1877 printf("\n");
1878 break;
1879 }
1880 }
1881 }
1882 }
1883