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