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