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