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