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