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