hdfd.c revision 1.19 1 /* $NetBSD: hdfd.c,v 1.19 2000/02/07 20:16:50 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 enum fdc_state {
134 DEVIDLE = 0,
135 MOTORWAIT,
136 DOSEEK,
137 SEEKWAIT,
138 SEEKTIMEDOUT,
139 SEEKCOMPLETE,
140 DOIO,
141 IOCOMPLETE,
142 IOTIMEDOUT,
143 DORESET,
144 RESETCOMPLETE,
145 RESETTIMEDOUT,
146 DORECAL,
147 RECALWAIT,
148 RECALTIMEDOUT,
149 RECALCOMPLETE,
150 };
151
152 /* software state, per controller */
153 struct fdc_softc {
154 struct device sc_dev; /* boilerplate */
155 struct fd_softc *sc_fd[4]; /* pointers to children */
156 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
157 enum fdc_state sc_state;
158 int sc_errors; /* number of retries so far */
159 int sc_overruns; /* number of overruns so far */
160 u_char sc_status[7]; /* copy of registers */
161 };
162
163 /* controller driver configuration */
164 int fdcprobe __P((struct device *, struct cfdata *, void *));
165 int fdprint __P((void *, const char *));
166 void fdcattach __P((struct device *, struct device *, void *));
167
168 struct cfattach fdc_ca = {
169 sizeof(struct fdc_softc), fdcprobe, fdcattach
170 };
171
172 /*
173 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
174 * we tell them apart.
175 */
176 struct fd_type {
177 int sectrac; /* sectors per track */
178 int heads; /* number of heads */
179 int seccyl; /* sectors per cylinder */
180 int secsize; /* size code for sectors */
181 int datalen; /* data len when secsize = 0 */
182 int steprate; /* step rate and head unload time */
183 int gap1; /* gap len between sectors */
184 int gap2; /* formatting gap */
185 int tracks; /* total num of tracks */
186 int size; /* size of disk in sectors */
187 int step; /* steps per cylinder */
188 int rate; /* transfer speed code */
189 u_char fillbyte; /* format fill byte */
190 u_char interleave; /* interleave factor (formatting) */
191 char *name;
192 };
193
194 /*
195 * The order of entries in the following table is important -- BEWARE!
196 * The order of the types is the same as for the TT/Falcon....
197 */
198 struct fd_type fd_types[] = {
199 /* 360kB in 720kB drive */
200 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB" },
201 /* 3.5" 720kB diskette */
202 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB" },
203 /* 1.44MB diskette */
204 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" },
205 };
206
207 /* software state, per disk (with up to 4 disks per ctlr) */
208 struct fd_softc {
209 struct device sc_dev;
210 struct disk sc_dk;
211
212 struct fd_type *sc_deftype; /* default type descriptor */
213 struct fd_type *sc_type; /* current type descriptor */
214
215 daddr_t sc_blkno; /* starting block number */
216 int sc_bcount; /* byte count left */
217 int sc_opts; /* user-set options */
218 int sc_skip; /* bytes already transferred */
219 int sc_nblks; /* #blocks currently tranferring */
220 int sc_nbytes; /* #bytes currently tranferring */
221
222 int sc_drive; /* physical unit number */
223 int sc_flags;
224 #define FD_OPEN 0x01 /* it's open */
225 #define FD_MOTOR 0x02 /* motor should be on */
226 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
227 int sc_cylin; /* where we think the head is */
228
229 void *sc_sdhook; /* saved shutdown hook for drive. */
230
231 TAILQ_ENTRY(fd_softc) sc_drivechain;
232 int sc_ops; /* I/O ops since last switch */
233 struct buf_queue sc_q; /* pending I/O requests */
234 int sc_active; /* number of active I/O operations */
235 };
236
237 /* floppy driver configuration */
238 int fdprobe __P((struct device *, struct cfdata *, void *));
239 void fdattach __P((struct device *, struct device *, void *));
240
241 struct cfattach hdfd_ca = {
242 sizeof(struct fd_softc), fdprobe, fdattach
243 };
244
245 extern struct cfdriver hdfd_cd;
246
247 void fdstrategy __P((struct buf *));
248 void fdstart __P((struct fd_softc *));
249
250 struct dkdriver fddkdriver = { fdstrategy };
251
252 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
253 void fd_motor_off __P((void *arg));
254 void fd_motor_on __P((void *arg));
255 int fdcresult __P((struct fdc_softc *fdc));
256 int out_fdc __P((u_char x));
257 void fdc_ctrl_intr __P((struct clockframe));
258 void fdcstart __P((struct fdc_softc *fdc));
259 void fdcstatus __P((struct device *dv, int n, char *s));
260 void fdctimeout __P((void *arg));
261 void fdcpseudointr __P((void *arg));
262 int fdcintr __P((void *));
263 void fdcretry __P((struct fdc_softc *fdc));
264 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
265 int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
266
267 static void fdgetdisklabel __P((struct fd_softc *, dev_t));
268 static void fdgetdefaultlabel __P((struct fd_softc *, struct disklabel *,
269 int));
270
271 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
272
273 int
274 fdcprobe(parent, cfp, aux)
275 struct device *parent;
276 struct cfdata *cfp;
277 void *aux;
278 {
279 int rv = 0;
280 bus_space_tag_t mb_tag;
281
282 if(strcmp("fdc", aux) || cfp->cf_unit != 0)
283 return(0);
284
285 if (!atari_realconfig)
286 return 0;
287
288 if ((mb_tag = mb_alloc_bus_space_tag()) == NULL)
289 return 0;
290
291 if (bus_space_map(mb_tag, FD_IOBASE, FD_IOSIZE, 0,
292 (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, FD_IOSIZE);
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 = (u_int8_t)~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 BUFQ_INIT(&fd->sc_q);
482 fd->sc_cylin = -1;
483 fd->sc_drive = drive;
484 fd->sc_deftype = type;
485 fdc->sc_fd[drive] = fd;
486
487 /*
488 * Initialize and attach the disk structure.
489 */
490 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
491 fd->sc_dk.dk_driver = &fddkdriver;
492 disk_attach(&fd->sc_dk);
493
494 /* XXX Need to do some more fiddling with sc_dk. */
495 dk_establish(&fd->sc_dk, &fd->sc_dev);
496
497 /* Needed to power off if the motor is on when we halt. */
498 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
499 }
500
501 /*
502 * This is called from the assembly part of the interrupt handler
503 * when it is clear that the interrupt was not related to shoving
504 * data.
505 */
506 void
507 fdc_ctrl_intr(frame)
508 struct clockframe frame;
509 {
510 int s;
511
512 /*
513 * Disable further interrupts. The fdcintr() routine
514 * explicitely enables them when needed.
515 */
516 MFP2->mf_ierb &= ~IB_DCHG;
517
518 /*
519 * Set fddmalen to zero so no pseudo-dma transfers will
520 * occur.
521 */
522 fddmalen = 0;
523
524 if (!BASEPRI(frame.cf_sr)) {
525 /*
526 * We don't want to stay on ipl6.....
527 */
528 add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
529 }
530 else {
531 s = splbio();
532 (void) fdcintr(intr_arg);
533 splx(s);
534 }
535 }
536
537 __inline struct fd_type *
538 fd_dev_to_type(fd, dev)
539 struct fd_softc *fd;
540 dev_t dev;
541 {
542 int type = FDTYPE(dev);
543
544 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
545 return NULL;
546 return type ? &fd_types[type - 1] : fd->sc_deftype;
547 }
548
549 void
550 fdstrategy(bp)
551 register struct buf *bp; /* IO operation to perform */
552 {
553 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
554 int sz;
555 int s;
556
557 /* Valid unit, controller, and request? */
558 if (bp->b_blkno < 0 ||
559 ((bp->b_bcount % FDC_BSIZE) != 0 &&
560 (bp->b_flags & B_FORMAT) == 0)) {
561 bp->b_error = EINVAL;
562 goto bad;
563 }
564
565 /* If it's a null transfer, return immediately. */
566 if (bp->b_bcount == 0)
567 goto done;
568
569 sz = howmany(bp->b_bcount, FDC_BSIZE);
570
571 if (bp->b_blkno + sz > fd->sc_type->size) {
572 sz = fd->sc_type->size - bp->b_blkno;
573 if (sz == 0) {
574 /* If exactly at end of disk, return EOF. */
575 goto done;
576 }
577 if (sz < 0) {
578 /* If past end of disk, return EINVAL. */
579 bp->b_error = EINVAL;
580 goto bad;
581 }
582 /* Otherwise, truncate request. */
583 bp->b_bcount = sz << DEV_BSHIFT;
584 }
585
586 bp->b_rawblkno = bp->b_blkno;
587 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
588
589 #ifdef FD_DEBUG
590 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz"
591 " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
592 bp->b_cylinder, sz);
593 #endif
594
595 /* Queue transfer on drive, activate drive and controller if idle. */
596 s = splbio();
597 disksort_cylinder(&fd->sc_q, bp);
598 untimeout(fd_motor_off, fd); /* a good idea */
599 if (fd->sc_active == 0)
600 fdstart(fd);
601 #ifdef DIAGNOSTIC
602 else {
603 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
604 if (fdc->sc_state == DEVIDLE) {
605 printf("fdstrategy: controller inactive\n");
606 fdcstart(fdc);
607 }
608 }
609 #endif
610 splx(s);
611 return;
612
613 bad:
614 bp->b_flags |= B_ERROR;
615 done:
616 /* Toss transfer; we're done early. */
617 bp->b_resid = bp->b_bcount;
618 biodone(bp);
619 }
620
621 void
622 fdstart(fd)
623 struct fd_softc *fd;
624 {
625 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
626 int active = fdc->sc_drives.tqh_first != 0;
627
628 /* Link into controller queue. */
629 fd->sc_active = 1;
630 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
631
632 /* If controller not already active, start it. */
633 if (!active)
634 fdcstart(fdc);
635 }
636
637 void
638 fdfinish(fd, bp)
639 struct fd_softc *fd;
640 struct buf *bp;
641 {
642 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
643
644 /*
645 * Move this drive to the end of the queue to give others a `fair'
646 * chance. We only force a switch if N operations are completed while
647 * another drive is waiting to be serviced, since there is a long motor
648 * startup delay whenever we switch.
649 */
650 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
651 fd->sc_ops = 0;
652 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
653 if (BUFQ_NEXT(bp) != NULL)
654 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
655 else
656 fd->sc_active = 0;
657 }
658 bp->b_resid = fd->sc_bcount;
659 fd->sc_skip = 0;
660 BUFQ_REMOVE(&fd->sc_q, bp);
661
662 biodone(bp);
663 /* turn off motor 5s from now */
664 timeout(fd_motor_off, fd, 5 * hz);
665 fdc->sc_state = DEVIDLE;
666 }
667
668 int
669 fdread(dev, uio, flags)
670 dev_t dev;
671 struct uio *uio;
672 int flags;
673 {
674 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
675 }
676
677 int
678 fdwrite(dev, uio, flags)
679 dev_t dev;
680 struct uio *uio;
681 int flags;
682 {
683 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
684 }
685
686 void
687 fd_set_motor(fdc, reset)
688 struct fdc_softc *fdc;
689 int reset;
690 {
691 struct fd_softc *fd;
692 u_char status;
693 int n;
694
695 if ((fd = fdc->sc_drives.tqh_first) != NULL)
696 status = fd->sc_drive;
697 else
698 status = 0;
699 if (!reset)
700 status |= FDO_FRST | FDO_FDMAEN;
701 for (n = 0; n < 4; n++)
702 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
703 status |= FDO_MOEN(n);
704 wrt_fdc_reg(fdout, status);
705 }
706
707 void
708 fd_motor_off(arg)
709 void *arg;
710 {
711 struct fd_softc *fd = arg;
712 int s;
713
714 s = splbio();
715 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
716 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
717 splx(s);
718 }
719
720 void
721 fd_motor_on(arg)
722 void *arg;
723 {
724 struct fd_softc *fd = arg;
725 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
726 int s;
727
728 s = splbio();
729 fd->sc_flags &= ~FD_MOTOR_WAIT;
730 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
731 (void) fdcintr(fdc);
732 splx(s);
733 }
734
735 int
736 fdcresult(fdc)
737 struct fdc_softc *fdc;
738 {
739 u_char i;
740 int j = 100000,
741 n = 0;
742
743 for (; j; j--) {
744 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
745 if (i == NE7_RQM)
746 return n;
747 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
748 if (n >= sizeof(fdc->sc_status)) {
749 log(LOG_ERR, "fdcresult: overrun\n");
750 return -1;
751 }
752 fdc->sc_status[n++] = rd_fdc_reg(fddata);
753 }
754 else delay(10);
755 }
756 log(LOG_ERR, "fdcresult: timeout\n");
757 return -1;
758 }
759
760 int
761 out_fdc(x)
762 u_char x;
763 {
764 int i = 100000;
765
766 while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
767 delay(1);
768 if (i <= 0)
769 return -1;
770 wrt_fdc_reg(fddata, x);
771 return 0;
772 }
773
774 int
775 fdopen(dev, flags, mode, p)
776 dev_t dev;
777 int flags;
778 int mode;
779 struct proc *p;
780 {
781 int unit;
782 struct fd_softc *fd;
783 struct fd_type *type;
784
785 unit = FDUNIT(dev);
786 if (unit >= hdfd_cd.cd_ndevs)
787 return ENXIO;
788 fd = hdfd_cd.cd_devs[unit];
789 if (fd == 0)
790 return ENXIO;
791 type = fd_dev_to_type(fd, dev);
792 if (type == NULL)
793 return ENXIO;
794
795 if ((fd->sc_flags & FD_OPEN) != 0 &&
796 fd->sc_type != type)
797 return EBUSY;
798
799 fd->sc_type = type;
800 fd->sc_cylin = -1;
801 fd->sc_flags |= FD_OPEN;
802
803 return 0;
804 }
805
806 int
807 fdclose(dev, flags, mode, p)
808 dev_t dev;
809 int flags;
810 int mode;
811 struct proc *p;
812 {
813 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
814
815 fd->sc_flags &= ~FD_OPEN;
816 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
817 return 0;
818 }
819
820 void
821 fdcstart(fdc)
822 struct fdc_softc *fdc;
823 {
824
825 #ifdef DIAGNOSTIC
826 /* only got here if controller's drive queue was inactive; should
827 be in idle state */
828 if (fdc->sc_state != DEVIDLE) {
829 printf("fdcstart: not idle\n");
830 return;
831 }
832 #endif
833 (void) fdcintr(fdc);
834 }
835
836 void
837 fdcstatus(dv, n, s)
838 struct device *dv;
839 int n;
840 char *s;
841 {
842 struct fdc_softc *fdc = (void *)dv->dv_parent;
843 char bits[64];
844
845 if (n == 0) {
846 out_fdc(NE7CMD_SENSEI);
847 (void) fdcresult(fdc);
848 n = 2;
849 }
850
851 printf("%s: %s", dv->dv_xname, s);
852
853 switch (n) {
854 case 0:
855 printf("\n");
856 break;
857 case 2:
858 printf(" (st0 %s cyl %d)\n",
859 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
860 bits, sizeof(bits)), fdc->sc_status[1]);
861 break;
862 case 7:
863 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
864 NE7_ST0BITS, bits, sizeof(bits)));
865 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
866 NE7_ST1BITS, bits, sizeof(bits)));
867 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
868 NE7_ST2BITS, bits, sizeof(bits)));
869 printf(" cyl %d head %d sec %d)\n",
870 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
871 break;
872 #ifdef DIAGNOSTIC
873 default:
874 printf("\nfdcstatus: weird size");
875 break;
876 #endif
877 }
878 }
879
880 void
881 fdctimeout(arg)
882 void *arg;
883 {
884 struct fdc_softc *fdc = arg;
885 struct fd_softc *fd = fdc->sc_drives.tqh_first;
886 int s;
887
888 s = splbio();
889 fdcstatus(&fd->sc_dev, 0, "timeout");
890
891 if (BUFQ_FIRST(&fd->sc_q) != NULL)
892 fdc->sc_state++;
893 else
894 fdc->sc_state = DEVIDLE;
895
896 (void) fdcintr(fdc);
897 splx(s);
898 }
899
900 void
901 fdcpseudointr(arg)
902 void *arg;
903 {
904 int s;
905
906 /* Just ensure it has the right spl. */
907 s = splbio();
908 (void) fdcintr(arg);
909 splx(s);
910 }
911
912 int
913 fdcintr(arg)
914 void *arg;
915 {
916 struct fdc_softc *fdc = arg;
917 #define st0 fdc->sc_status[0]
918 #define st1 fdc->sc_status[1]
919 #define cyl fdc->sc_status[1]
920
921 struct fd_softc *fd;
922 struct buf *bp;
923 int read, head, sec, i, nblks;
924 struct fd_type *type;
925 struct ne7_fd_formb *finfo = NULL;
926
927 loop:
928 /* Is there a drive for the controller to do a transfer with? */
929 fd = fdc->sc_drives.tqh_first;
930 if (fd == NULL) {
931 fdc->sc_state = DEVIDLE;
932 return 1;
933 }
934
935 /* Is there a transfer to this drive? If not, deactivate drive. */
936 bp = BUFQ_FIRST(&fd->sc_q);
937 if (bp == NULL) {
938 fd->sc_ops = 0;
939 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
940 fd->sc_active = 0;
941 goto loop;
942 }
943
944 if (bp->b_flags & B_FORMAT)
945 finfo = (struct ne7_fd_formb *)bp->b_data;
946
947 switch (fdc->sc_state) {
948 case DEVIDLE:
949 fdc->sc_errors = 0;
950 fdc->sc_overruns = 0;
951 fd->sc_skip = 0;
952 fd->sc_bcount = bp->b_bcount;
953 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
954 untimeout(fd_motor_off, fd);
955 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
956 fdc->sc_state = MOTORWAIT;
957 return 1;
958 }
959 if ((fd->sc_flags & FD_MOTOR) == 0) {
960 /* Turn on the motor, being careful about pairing. */
961 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
962 if (ofd && ofd->sc_flags & FD_MOTOR) {
963 untimeout(fd_motor_off, ofd);
964 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
965 }
966 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
967 fd_set_motor(fdc, 0);
968 fdc->sc_state = MOTORWAIT;
969 /* Allow .25s for motor to stabilize. */
970 timeout(fd_motor_on, fd, hz / 4);
971 return 1;
972 }
973 /* Make sure the right drive is selected. */
974 fd_set_motor(fdc, 0);
975
976 /* fall through */
977 case DOSEEK:
978 doseek:
979 if (fd->sc_cylin == bp->b_cylinder)
980 goto doio;
981
982 out_fdc(NE7CMD_SPECIFY);/* specify command */
983 out_fdc(fd->sc_type->steprate);
984 out_fdc(0x7); /* XXX head load time == 6ms - non-dma */
985
986 fdc_ienable();
987
988 out_fdc(NE7CMD_SEEK); /* seek function */
989 out_fdc(fd->sc_drive); /* drive number */
990 out_fdc(bp->b_cylinder * fd->sc_type->step);
991
992 fd->sc_cylin = -1;
993 fdc->sc_state = SEEKWAIT;
994
995 fd->sc_dk.dk_seek++;
996 disk_busy(&fd->sc_dk);
997
998 timeout(fdctimeout, fdc, 4 * hz);
999 return 1;
1000
1001 case DOIO:
1002 doio:
1003 if (finfo)
1004 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1005 (char *)finfo;
1006
1007 type = fd->sc_type;
1008 sec = fd->sc_blkno % type->seccyl;
1009 head = sec / type->sectrac;
1010 sec -= head * type->sectrac;
1011 nblks = type->sectrac - sec;
1012 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1013 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1014 fd->sc_nblks = nblks;
1015 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1016 #ifdef DIAGNOSTIC
1017 {
1018 int block;
1019
1020 block = (fd->sc_cylin * type->heads + head)
1021 * type->sectrac + sec;
1022 if (block != fd->sc_blkno) {
1023 printf("fdcintr: block %d != blkno %d\n",
1024 block, fd->sc_blkno);
1025 #ifdef DDB
1026 Debugger();
1027 #endif
1028 }
1029 }
1030 #endif
1031 read = bp->b_flags & B_READ ? 1 : 0;
1032
1033 /*
1034 * Setup pseudo-dma address & count
1035 */
1036 fddmaaddr = bp->b_data + fd->sc_skip;
1037 fddmalen = fd->sc_nbytes;
1038
1039 wrt_fdc_reg(fdctl, type->rate);
1040 #ifdef FD_DEBUG
1041 printf("fdcintr: %s drive %d track %d head %d sec %d"
1042 " nblks %d\n", read ? "read" : "write",
1043 fd->sc_drive, fd->sc_cylin, head, sec, nblks);
1044 #endif
1045 fdc_ienable();
1046
1047 if (finfo) {
1048 /* formatting */
1049 if (out_fdc(NE7CMD_FORMAT) < 0) {
1050 fdc->sc_errors = 4;
1051 fdcretry(fdc);
1052 goto loop;
1053 }
1054 out_fdc((head << 2) | fd->sc_drive);
1055 out_fdc(finfo->fd_formb_secshift);
1056 out_fdc(finfo->fd_formb_nsecs);
1057 out_fdc(finfo->fd_formb_gaplen);
1058 out_fdc(finfo->fd_formb_fillbyte);
1059 } else {
1060 if (read)
1061 out_fdc(NE7CMD_READ); /* READ */
1062 else
1063 out_fdc(NE7CMD_WRITE); /* WRITE */
1064 out_fdc((head << 2) | fd->sc_drive);
1065 out_fdc(fd->sc_cylin); /* track */
1066 out_fdc(head); /* head */
1067 out_fdc(sec + 1); /* sector +1 */
1068 out_fdc(type->secsize); /* sector size */
1069 out_fdc(sec + nblks); /* last sectors */
1070 out_fdc(type->gap1); /* gap1 size */
1071 out_fdc(type->datalen); /* data length */
1072 }
1073 fdc->sc_state = IOCOMPLETE;
1074
1075 disk_busy(&fd->sc_dk);
1076
1077 /* allow 2 seconds for operation */
1078 timeout(fdctimeout, fdc, 2 * hz);
1079 return 1; /* will return later */
1080
1081 case SEEKWAIT:
1082 untimeout(fdctimeout, fdc);
1083 fdc->sc_state = SEEKCOMPLETE;
1084 /* allow 1/50 second for heads to settle */
1085 timeout(fdcpseudointr, fdc, hz / 50);
1086 return 1;
1087
1088 case SEEKCOMPLETE:
1089 disk_unbusy(&fd->sc_dk, 0); /* no data on seek */
1090
1091 /* Make sure seek really happened. */
1092 out_fdc(NE7CMD_SENSEI);
1093 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1094 cyl != bp->b_cylinder * fd->sc_type->step) {
1095 #ifdef FD_DEBUG
1096 fdcstatus(&fd->sc_dev, 2, "seek failed");
1097 #endif
1098 fdcretry(fdc);
1099 goto loop;
1100 }
1101 fd->sc_cylin = bp->b_cylinder;
1102 goto doio;
1103
1104 case IOTIMEDOUT:
1105 case SEEKTIMEDOUT:
1106 case RECALTIMEDOUT:
1107 case RESETTIMEDOUT:
1108 fdcretry(fdc);
1109 goto loop;
1110
1111 case IOCOMPLETE: /* IO DONE, post-analyze */
1112 untimeout(fdctimeout, fdc);
1113
1114 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1115
1116 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
1117 /*
1118 * As the damn chip doesn't seem to have a FIFO,
1119 * accept a few overruns as a fact of life *sigh*
1120 */
1121 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
1122 fdc->sc_state = DOSEEK;
1123 goto loop;
1124 }
1125 #ifdef FD_DEBUG
1126 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1127 "read failed" : "write failed");
1128 printf("blkno %d nblks %d\n",
1129 fd->sc_blkno, fd->sc_nblks);
1130 #endif
1131 fdcretry(fdc);
1132 goto loop;
1133 }
1134 if (fdc->sc_errors) {
1135 diskerr(bp, "fd", "soft error", LOG_PRINTF,
1136 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1137 printf("\n");
1138 fdc->sc_errors = 0;
1139 }
1140 fdc->sc_overruns = 0;
1141 fd->sc_blkno += fd->sc_nblks;
1142 fd->sc_skip += fd->sc_nbytes;
1143 fd->sc_bcount -= fd->sc_nbytes;
1144 if (!finfo && fd->sc_bcount > 0) {
1145 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1146 goto doseek;
1147 }
1148 fdfinish(fd, bp);
1149 goto loop;
1150
1151 case DORESET:
1152 /* try a reset, keep motor on */
1153 fd_set_motor(fdc, 1);
1154 delay(100);
1155 fd_set_motor(fdc, 0);
1156 fdc->sc_state = RESETCOMPLETE;
1157 timeout(fdctimeout, fdc, hz / 2);
1158 return 1; /* will return later */
1159
1160 case RESETCOMPLETE:
1161 untimeout(fdctimeout, fdc);
1162 /* clear the controller output buffer */
1163 for (i = 0; i < 4; i++) {
1164 out_fdc(NE7CMD_SENSEI);
1165 (void) fdcresult(fdc);
1166 }
1167
1168 /* fall through */
1169 case DORECAL:
1170 fdc_ienable();
1171
1172 out_fdc(NE7CMD_RECAL); /* recalibrate function */
1173 out_fdc(fd->sc_drive);
1174 fdc->sc_state = RECALWAIT;
1175 timeout(fdctimeout, fdc, 5 * hz);
1176 return 1; /* will return later */
1177
1178 case RECALWAIT:
1179 untimeout(fdctimeout, fdc);
1180 fdc->sc_state = RECALCOMPLETE;
1181 /* allow 1/30 second for heads to settle */
1182 timeout(fdcpseudointr, fdc, hz / 30);
1183 return 1; /* will return later */
1184
1185 case RECALCOMPLETE:
1186 out_fdc(NE7CMD_SENSEI);
1187 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1188 #ifdef FD_DEBUG
1189 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1190 #endif
1191 fdcretry(fdc);
1192 goto loop;
1193 }
1194 fd->sc_cylin = 0;
1195 goto doseek;
1196
1197 case MOTORWAIT:
1198 if (fd->sc_flags & FD_MOTOR_WAIT)
1199 return 1; /* time's not up yet */
1200 goto doseek;
1201
1202 default:
1203 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1204 return 1;
1205 }
1206 #ifdef DIAGNOSTIC
1207 panic("fdcintr: impossible");
1208 #endif
1209 #undef st0
1210 #undef st1
1211 #undef cyl
1212 }
1213
1214 void
1215 fdcretry(fdc)
1216 struct fdc_softc *fdc;
1217 {
1218 char bits[64];
1219 struct fd_softc *fd;
1220 struct buf *bp;
1221
1222 fd = fdc->sc_drives.tqh_first;
1223 bp = BUFQ_FIRST(&fd->sc_q);
1224
1225 if (fd->sc_opts & FDOPT_NORETRY)
1226 goto fail;
1227
1228 switch (fdc->sc_errors) {
1229 case 0:
1230 /* try again */
1231 fdc->sc_state = DOSEEK;
1232 break;
1233
1234 case 1: case 2: case 3:
1235 /* didn't work; try recalibrating */
1236 fdc->sc_state = DORECAL;
1237 break;
1238
1239 case 4:
1240 /* still no go; reset the bastard */
1241 fdc->sc_state = DORESET;
1242 break;
1243
1244 default:
1245 fail:
1246 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1247 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1248 fd->sc_skip / FDC_BSIZE,
1249 (struct disklabel *)NULL);
1250
1251 printf(" (st0 %s",
1252 bitmask_snprintf(fdc->sc_status[0],
1253 NE7_ST0BITS, bits,
1254 sizeof(bits)));
1255 printf(" st1 %s",
1256 bitmask_snprintf(fdc->sc_status[1],
1257 NE7_ST1BITS, bits,
1258 sizeof(bits)));
1259 printf(" st2 %s",
1260 bitmask_snprintf(fdc->sc_status[2],
1261 NE7_ST2BITS, bits,
1262 sizeof(bits)));
1263 printf(" cyl %d head %d sec %d)\n",
1264 fdc->sc_status[3],
1265 fdc->sc_status[4],
1266 fdc->sc_status[5]);
1267 }
1268 bp->b_flags |= B_ERROR;
1269 bp->b_error = EIO;
1270 fdfinish(fd, bp);
1271 }
1272 fdc->sc_errors++;
1273 }
1274
1275 int
1276 fdsize(dev)
1277 dev_t dev;
1278 {
1279
1280 /* Swapping to floppies would not make sense. */
1281 return -1;
1282 }
1283
1284 int
1285 fddump(dev, blkno, va, size)
1286 dev_t dev;
1287 daddr_t blkno;
1288 caddr_t va;
1289 size_t size;
1290 {
1291
1292 /* Not implemented. */
1293 return ENXIO;
1294 }
1295
1296 int
1297 fdioctl(dev, cmd, addr, flag, p)
1298 dev_t dev;
1299 u_long cmd;
1300 caddr_t addr;
1301 int flag;
1302 struct proc *p;
1303 {
1304 struct fd_softc *fd;
1305 struct disklabel buffer;
1306 int error;
1307 struct fdformat_parms *form_parms;
1308 struct fdformat_cmd *form_cmd;
1309 struct ne7_fd_formb fd_formb;
1310 unsigned int scratch;
1311 int il[FD_MAX_NSEC + 1];
1312 register int i, j;
1313
1314 fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1315
1316 switch (cmd) {
1317 case DIOCGDINFO:
1318 fdgetdisklabel(fd, dev);
1319 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1320 return 0;
1321
1322 case DIOCGPART:
1323 fdgetdisklabel(fd, dev);
1324 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1325 ((struct partinfo *)addr)->part =
1326 &fd->sc_dk.dk_label->d_partitions[RAW_PART];
1327 return(0);
1328
1329 case DIOCWLABEL:
1330 if ((flag & FWRITE) == 0)
1331 return EBADF;
1332 /* XXX do something */
1333 return 0;
1334
1335 case DIOCSDINFO:
1336 case DIOCWDINFO:
1337 if ((flag & FWRITE) == 0)
1338 return EBADF;
1339
1340 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
1341 if (error)
1342 return error;
1343
1344 if (cmd == DIOCWDINFO)
1345 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1346 return error;
1347
1348 case FDIOCGETFORMAT:
1349 form_parms = (struct fdformat_parms *)addr;
1350 form_parms->fdformat_version = FDFORMAT_VERSION;
1351 form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1352 form_parms->ncyl = fd->sc_type->tracks;
1353 form_parms->nspt = fd->sc_type->sectrac;
1354 form_parms->ntrk = fd->sc_type->heads;
1355 form_parms->stepspercyl = fd->sc_type->step;
1356 form_parms->gaplen = fd->sc_type->gap2;
1357 form_parms->fillbyte = fd->sc_type->fillbyte;
1358 form_parms->interleave = fd->sc_type->interleave;
1359 switch (fd->sc_type->rate) {
1360 case FDC_500KBPS:
1361 form_parms->xfer_rate = 500 * 1024;
1362 break;
1363 case FDC_300KBPS:
1364 form_parms->xfer_rate = 300 * 1024;
1365 break;
1366 case FDC_250KBPS:
1367 form_parms->xfer_rate = 250 * 1024;
1368 break;
1369 case FDC_125KBPS:
1370 form_parms->xfer_rate = 125 * 1024;
1371 break;
1372 default:
1373 return EINVAL;
1374 }
1375 return 0;
1376
1377 case FDIOCSETFORMAT:
1378 if((flag & FWRITE) == 0)
1379 return EBADF; /* must be opened for writing */
1380 form_parms = (struct fdformat_parms *)addr;
1381 if (form_parms->fdformat_version != FDFORMAT_VERSION)
1382 return EINVAL; /* wrong version of formatting prog */
1383
1384 scratch = form_parms->nbps >> 7;
1385 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1386 scratch & ~(1 << (ffs(scratch)-1)))
1387 /* not a power-of-two multiple of 128 */
1388 return EINVAL;
1389
1390 switch (form_parms->xfer_rate) {
1391 case 500 * 1024:
1392 fd->sc_type->rate = FDC_500KBPS;
1393 break;
1394 case 300 * 1024:
1395 fd->sc_type->rate = FDC_300KBPS;
1396 break;
1397 case 250 * 1024:
1398 fd->sc_type->rate = FDC_250KBPS;
1399 break;
1400 case 125 * 1024:
1401 fd->sc_type->rate = FDC_125KBPS;
1402 break;
1403 default:
1404 return EINVAL;
1405 }
1406
1407 if (form_parms->nspt > FD_MAX_NSEC ||
1408 form_parms->fillbyte > 0xff ||
1409 form_parms->interleave > 0xff)
1410 return EINVAL;
1411 fd->sc_type->sectrac = form_parms->nspt;
1412 if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1413 return EINVAL;
1414 fd->sc_type->heads = form_parms->ntrk;
1415 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1416 fd->sc_type->secsize = ffs(scratch)-1;
1417 fd->sc_type->gap2 = form_parms->gaplen;
1418 fd->sc_type->tracks = form_parms->ncyl;
1419 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1420 form_parms->nbps / DEV_BSIZE;
1421 fd->sc_type->step = form_parms->stepspercyl;
1422 fd->sc_type->fillbyte = form_parms->fillbyte;
1423 fd->sc_type->interleave = form_parms->interleave;
1424 return 0;
1425
1426 case FDIOCFORMAT_TRACK:
1427 if((flag & FWRITE) == 0)
1428 return EBADF; /* must be opened for writing */
1429 form_cmd = (struct fdformat_cmd *)addr;
1430 if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1431 return EINVAL; /* wrong version of formatting prog */
1432
1433 if (form_cmd->head >= fd->sc_type->heads ||
1434 form_cmd->cylinder >= fd->sc_type->tracks) {
1435 return EINVAL;
1436 }
1437
1438 fd_formb.head = form_cmd->head;
1439 fd_formb.cyl = form_cmd->cylinder;
1440 fd_formb.transfer_rate = fd->sc_type->rate;
1441 fd_formb.fd_formb_secshift = fd->sc_type->secsize;
1442 fd_formb.fd_formb_nsecs = fd->sc_type->sectrac;
1443 fd_formb.fd_formb_gaplen = fd->sc_type->gap2;
1444 fd_formb.fd_formb_fillbyte = fd->sc_type->fillbyte;
1445
1446 bzero(il,sizeof il);
1447 for (j = 0, i = 1; i <= fd_formb.fd_formb_nsecs; i++) {
1448 while (il[(j%fd_formb.fd_formb_nsecs)+1])
1449 j++;
1450 il[(j%fd_formb.fd_formb_nsecs)+1] = i;
1451 j += fd->sc_type->interleave;
1452 }
1453 for (i = 0; i < fd_formb.fd_formb_nsecs; i++) {
1454 fd_formb.fd_formb_cylno(i) = form_cmd->cylinder;
1455 fd_formb.fd_formb_headno(i) = form_cmd->head;
1456 fd_formb.fd_formb_secno(i) = il[i+1];
1457 fd_formb.fd_formb_secsize(i) = fd->sc_type->secsize;
1458 }
1459 case FDIOCGETOPTS: /* get drive options */
1460 *(int *)addr = fd->sc_opts;
1461 return 0;
1462
1463 case FDIOCSETOPTS: /* set drive options */
1464 fd->sc_opts = *(int *)addr;
1465 return 0;
1466
1467
1468 default:
1469 return ENOTTY;
1470 }
1471
1472 #ifdef DIAGNOSTIC
1473 panic("fdioctl: impossible");
1474 #endif
1475 }
1476
1477 int
1478 fdformat(dev, finfo, p)
1479 dev_t dev;
1480 struct ne7_fd_formb *finfo;
1481 struct proc *p;
1482 {
1483 int rv = 0, s;
1484 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1485 struct fd_type *type = fd->sc_type;
1486 struct buf *bp;
1487
1488 /* set up a buffer header for fdstrategy() */
1489 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1490 if(bp == 0)
1491 return ENOBUFS;
1492 PHOLD(p);
1493 bzero((void *)bp, sizeof(struct buf));
1494 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1495 bp->b_proc = p;
1496 bp->b_dev = dev;
1497
1498 /*
1499 * calculate a fake blkno, so fdstrategy() would initiate a
1500 * seek to the requested cylinder
1501 */
1502 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1503 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1504
1505 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1506 bp->b_data = (caddr_t)finfo;
1507
1508 #ifdef DEBUG
1509 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
1510 #endif
1511
1512 /* now do the format */
1513 fdstrategy(bp);
1514
1515 /* ...and wait for it to complete */
1516 s = splbio();
1517 while(!(bp->b_flags & B_DONE)) {
1518 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1519 if (rv == EWOULDBLOCK)
1520 break;
1521 }
1522 splx(s);
1523
1524 if (rv == EWOULDBLOCK) {
1525 /* timed out */
1526 rv = EIO;
1527 biodone(bp);
1528 }
1529 if(bp->b_flags & B_ERROR) {
1530 rv = bp->b_error;
1531 }
1532 PRELE(p);
1533 free(bp, M_TEMP);
1534 return rv;
1535 }
1536
1537
1538 /*
1539 * Obtain a disklabel. Either a real one from the disk or, if there
1540 * is none, a fake one.
1541 */
1542 static void
1543 fdgetdisklabel(fd, dev)
1544 struct fd_softc *fd;
1545 dev_t dev;
1546 {
1547 struct disklabel *lp;
1548 struct cpu_disklabel cpulab;
1549
1550 lp = fd->sc_dk.dk_label;
1551
1552 bzero(lp, sizeof(*lp));
1553 bzero(&cpulab, sizeof(cpulab));
1554
1555 lp->d_secpercyl = fd->sc_type->seccyl;
1556 lp->d_type = DTYPE_FLOPPY;
1557 lp->d_secsize = FDC_BSIZE;
1558 lp->d_secperunit = fd->sc_type->size;
1559
1560 /*
1561 * If there is no label on the disk: fake one
1562 */
1563 if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL)
1564 fdgetdefaultlabel(fd, lp, RAW_PART);
1565
1566 if ((FDC_BSIZE * fd->sc_type->size)
1567 < (lp->d_secsize * lp->d_secperunit)) {
1568 /*
1569 * XXX: Ignore these fields. If you drop a vnddisk
1570 * on more than one floppy, you'll get disturbing
1571 * sounds!
1572 */
1573 lp->d_secpercyl = fd->sc_type->seccyl;
1574 lp->d_type = DTYPE_FLOPPY;
1575 lp->d_secsize = FDC_BSIZE;
1576 lp->d_secperunit = fd->sc_type->size;
1577 }
1578 }
1579
1580 /*
1581 * Build defaultdisk label. For now we only create a label from what we
1582 * know from 'sc'.
1583 */
1584 static void
1585 fdgetdefaultlabel(fd, lp, part)
1586 struct fd_softc *fd;
1587 struct disklabel *lp;
1588 int part;
1589 {
1590 bzero(lp, sizeof(struct disklabel));
1591
1592 lp->d_secsize = 128 * (1 << fd->sc_type->secsize);
1593 lp->d_ntracks = fd->sc_type->heads;
1594 lp->d_nsectors = fd->sc_type->sectrac;
1595 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1596 lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl;
1597 lp->d_secperunit = fd->sc_type->size;
1598
1599 lp->d_type = DTYPE_FLOPPY;
1600 lp->d_rpm = 300; /* good guess I suppose. */
1601 lp->d_interleave = 1; /* FIXME: is this OK? */
1602 lp->d_bbsize = 0;
1603 lp->d_sbsize = 0;
1604 lp->d_npartitions = part + 1;
1605 lp->d_trkseek = 6000; /* Who cares... */
1606 lp->d_magic = DISKMAGIC;
1607 lp->d_magic2 = DISKMAGIC;
1608 lp->d_checksum = dkcksum(lp);
1609 lp->d_partitions[part].p_size = lp->d_secperunit;
1610 lp->d_partitions[part].p_fstype = FS_UNUSED;
1611 lp->d_partitions[part].p_fsize = 1024;
1612 lp->d_partitions[part].p_frag = 8;
1613 }
1614