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