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