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