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