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