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