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