hdfd.c revision 1.61.12.1 1 /* $NetBSD: hdfd.c,v 1.61.12.1 2008/06/23 04:30:12 wrstuden 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.61.12.1 2008/06/23 04:30:12 wrstuden 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 void * 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 /* (mis)use device use flag to identify format operation */
167 #define B_FORMAT B_DEVPRIVATE
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 bus_space_handle_t handle;
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, &handle)) {
344 printf("fdcprobe: cannot map io-area\n");
345 mb_free_bus_space_tag(mb_tag);
346 return (0);
347 }
348 fdio_addr = bus_space_vaddr(mb_tag, handle); /* XXX */
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, handle, 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, 0);
435 callout_init(&fdc->sc_intr_ch, 0);
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, 0);
529 callout_init(&fd->sc_motoroff_ch, 0);
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 disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &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(struct fd_softc *fd, dev_t dev)
593 {
594 int type = FDTYPE(dev);
595
596 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
597 return NULL;
598 return type ? &fd_types[type - 1] : fd->sc_deftype;
599 }
600
601 void
602 fdstrategy(struct buf *bp)
603 {
604 struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(bp->b_dev));
605 int sz;
606 int s;
607
608 /* Valid unit, controller, and request? */
609 if (bp->b_blkno < 0 ||
610 ((bp->b_bcount % FDC_BSIZE) != 0 &&
611 (bp->b_flags & B_FORMAT) == 0)) {
612 bp->b_error = EINVAL;
613 goto done;
614 }
615
616 /* If it's a null transfer, return immediately. */
617 if (bp->b_bcount == 0)
618 goto done;
619
620 sz = howmany(bp->b_bcount, FDC_BSIZE);
621
622 if (bp->b_blkno + sz > fd->sc_type->size) {
623 sz = fd->sc_type->size - bp->b_blkno;
624 if (sz == 0) {
625 /* If exactly at end of disk, return EOF. */
626 goto done;
627 }
628 if (sz < 0) {
629 /* If past end of disk, return EINVAL. */
630 bp->b_error = EINVAL;
631 goto done;
632 }
633 /* Otherwise, truncate request. */
634 bp->b_bcount = sz << DEV_BSHIFT;
635 }
636
637 bp->b_rawblkno = bp->b_blkno;
638 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
639
640 #ifdef FD_DEBUG
641 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %qd cylin %ld sz"
642 " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
643 bp->b_cylinder, sz);
644 #endif
645
646 /* Queue transfer on drive, activate drive and controller if idle. */
647 s = splbio();
648 BUFQ_PUT(fd->sc_q, bp);
649 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
650 if (fd->sc_active == 0)
651 fdstart(fd);
652 #ifdef DIAGNOSTIC
653 else {
654 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
655 if (fdc->sc_state == DEVIDLE) {
656 printf("fdstrategy: controller inactive\n");
657 fdcstart(fdc);
658 }
659 }
660 #endif
661 splx(s);
662 return;
663
664 done:
665 /* Toss transfer; we're done early. */
666 bp->b_resid = bp->b_bcount;
667 biodone(bp);
668 }
669
670 void
671 fdstart(fd)
672 struct fd_softc *fd;
673 {
674 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
675 int active = fdc->sc_drives.tqh_first != 0;
676
677 /* Link into controller queue. */
678 fd->sc_active = 1;
679 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
680
681 /* If controller not already active, start it. */
682 if (!active)
683 fdcstart(fdc);
684 }
685
686 void
687 fdfinish(fd, bp)
688 struct fd_softc *fd;
689 struct buf *bp;
690 {
691 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
692
693 /*
694 * Move this drive to the end of the queue to give others a `fair'
695 * chance. We only force a switch if N operations are completed while
696 * another drive is waiting to be serviced, since there is a long motor
697 * startup delay whenever we switch.
698 */
699 (void)BUFQ_GET(fd->sc_q);
700 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
701 fd->sc_ops = 0;
702 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
703 if (BUFQ_PEEK(fd->sc_q) != NULL)
704 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
705 else
706 fd->sc_active = 0;
707 }
708 bp->b_resid = fd->sc_bcount;
709 fd->sc_skip = 0;
710
711 biodone(bp);
712 /* turn off motor 5s from now */
713 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
714 fdc->sc_state = DEVIDLE;
715 }
716
717 int
718 fdread(dev, uio, flags)
719 dev_t dev;
720 struct uio *uio;
721 int flags;
722 {
723 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
724 }
725
726 int
727 fdwrite(dev, uio, flags)
728 dev_t dev;
729 struct uio *uio;
730 int flags;
731 {
732 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
733 }
734
735 void
736 fd_set_motor(fdc, reset)
737 struct fdc_softc *fdc;
738 int reset;
739 {
740 struct fd_softc *fd;
741 u_char status;
742 int n;
743
744 if ((fd = fdc->sc_drives.tqh_first) != NULL)
745 status = fd->sc_drive;
746 else
747 status = 0;
748 if (!reset)
749 status |= FDO_FRST | FDO_FDMAEN;
750 for (n = 0; n < 4; n++)
751 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
752 status |= FDO_MOEN(n);
753 wrt_fdc_reg(fdout, status);
754 }
755
756 void
757 fd_motor_off(arg)
758 void *arg;
759 {
760 struct fd_softc *fd = arg;
761 int s;
762
763 s = splbio();
764 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
765 fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0);
766 splx(s);
767 }
768
769 void
770 fd_motor_on(arg)
771 void *arg;
772 {
773 struct fd_softc *fd = arg;
774 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
775 int s;
776
777 s = splbio();
778 fd->sc_flags &= ~FD_MOTOR_WAIT;
779 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
780 (void) fdcintr(fdc);
781 splx(s);
782 }
783
784 int
785 fdcresult(fdc)
786 struct fdc_softc *fdc;
787 {
788 u_char i;
789 int j = 100000,
790 n = 0;
791
792 for (; j; j--) {
793 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
794 if (i == NE7_RQM)
795 return n;
796 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
797 if (n >= sizeof(fdc->sc_status)) {
798 log(LOG_ERR, "fdcresult: overrun\n");
799 return -1;
800 }
801 fdc->sc_status[n++] = rd_fdc_reg(fddata);
802 }
803 else delay(10);
804 }
805 log(LOG_ERR, "fdcresult: timeout\n");
806 return -1;
807 }
808
809 int
810 out_fdc(x)
811 u_char x;
812 {
813 int i = 100000;
814
815 while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
816 delay(1);
817 if (i <= 0)
818 return -1;
819 wrt_fdc_reg(fddata, x);
820 return 0;
821 }
822
823 int
824 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
825 {
826 struct fd_softc *fd;
827 struct fd_type *type;
828
829 fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
830 if (fd == NULL)
831 return ENXIO;
832 type = fd_dev_to_type(fd, dev);
833 if (type == NULL)
834 return ENXIO;
835
836 if ((fd->sc_flags & FD_OPEN) != 0 &&
837 fd->sc_type != type)
838 return EBUSY;
839
840 fd->sc_type = type;
841 fd->sc_cylin = -1;
842 fd->sc_flags |= FD_OPEN;
843 fdgetdisklabel(fd, dev);
844
845 return 0;
846 }
847
848 int
849 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
850 {
851 struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
852
853 fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB);
854 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
855 return 0;
856 }
857
858 void
859 fdcstart(fdc)
860 struct fdc_softc *fdc;
861 {
862
863 #ifdef DIAGNOSTIC
864 /* only got here if controller's drive queue was inactive; should
865 be in idle state */
866 if (fdc->sc_state != DEVIDLE) {
867 printf("fdcstart: not idle\n");
868 return;
869 }
870 #endif
871 (void) fdcintr(fdc);
872 }
873
874 void
875 fdcstatus(dv, n, s)
876 struct device *dv;
877 int n;
878 const char *s;
879 {
880 struct fdc_softc *fdc = (void *) device_parent(dv);
881 char bits[64];
882
883 if (n == 0) {
884 out_fdc(NE7CMD_SENSEI);
885 (void) fdcresult(fdc);
886 n = 2;
887 }
888
889 printf("%s: %s", dv->dv_xname, s);
890
891 switch (n) {
892 case 0:
893 printf("\n");
894 break;
895 case 2:
896 printf(" (st0 %s cyl %d)\n",
897 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
898 bits, sizeof(bits)), fdc->sc_status[1]);
899 break;
900 case 7:
901 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
902 NE7_ST0BITS, bits, sizeof(bits)));
903 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
904 NE7_ST1BITS, bits, sizeof(bits)));
905 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
906 NE7_ST2BITS, bits, sizeof(bits)));
907 printf(" cyl %d head %d sec %d)\n",
908 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
909 break;
910 #ifdef DIAGNOSTIC
911 default:
912 printf("\nfdcstatus: weird size");
913 break;
914 #endif
915 }
916 }
917
918 void
919 fdctimeout(arg)
920 void *arg;
921 {
922 struct fdc_softc *fdc = arg;
923 struct fd_softc *fd = fdc->sc_drives.tqh_first;
924 int s;
925
926 s = splbio();
927 fdcstatus(&fd->sc_dev, 0, "timeout");
928
929 if (BUFQ_PEEK(fd->sc_q) != NULL)
930 fdc->sc_state++;
931 else
932 fdc->sc_state = DEVIDLE;
933
934 (void) fdcintr(fdc);
935 splx(s);
936 }
937
938 void
939 fdcpseudointr(arg)
940 void *arg;
941 {
942 int s;
943
944 /* Just ensure it has the right spl. */
945 s = splbio();
946 (void) fdcintr(arg);
947 splx(s);
948 }
949
950 int
951 fdcintr(arg)
952 void *arg;
953 {
954 struct fdc_softc *fdc = arg;
955 #define st0 fdc->sc_status[0]
956 #define st1 fdc->sc_status[1]
957 #define cyl fdc->sc_status[1]
958
959 struct fd_softc *fd;
960 struct buf *bp;
961 int read, head, sec, i, nblks;
962 struct fd_type *type;
963 struct ne7_fd_formb *finfo = NULL;
964
965 loop:
966 /* Is there a drive for the controller to do a transfer with? */
967 fd = fdc->sc_drives.tqh_first;
968 if (fd == NULL) {
969 fdc->sc_state = DEVIDLE;
970 return 1;
971 }
972
973 /* Is there a transfer to this drive? If not, deactivate drive. */
974 bp = BUFQ_PEEK(fd->sc_q);
975 if (bp == NULL) {
976 fd->sc_ops = 0;
977 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
978 fd->sc_active = 0;
979 goto loop;
980 }
981
982 if (bp->b_flags & B_FORMAT)
983 finfo = (struct ne7_fd_formb *)bp->b_data;
984
985 switch (fdc->sc_state) {
986 case DEVIDLE:
987 fdc->sc_errors = 0;
988 fdc->sc_overruns = 0;
989 fd->sc_skip = 0;
990 fd->sc_bcount = bp->b_bcount;
991 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
992 callout_stop(&fd->sc_motoroff_ch);
993 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
994 fdc->sc_state = MOTORWAIT;
995 return 1;
996 }
997 if ((fd->sc_flags & FD_MOTOR) == 0) {
998 /* Turn on the motor, being careful about pairing. */
999 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1000 if (ofd && ofd->sc_flags & FD_MOTOR) {
1001 callout_stop(&ofd->sc_motoroff_ch);
1002 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1003 }
1004 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1005 fd_set_motor(fdc, 0);
1006 fdc->sc_state = MOTORWAIT;
1007 /* Allow .25s for motor to stabilize. */
1008 callout_reset(&fd->sc_motoron_ch, hz / 4,
1009 fd_motor_on, fd);
1010 return 1;
1011 }
1012 /* Make sure the right drive is selected. */
1013 fd_set_motor(fdc, 0);
1014
1015 /* fall through */
1016 case DOSEEK:
1017 doseek:
1018 if (fd->sc_cylin == bp->b_cylinder)
1019 goto doio;
1020
1021 out_fdc(NE7CMD_SPECIFY);/* specify command */
1022 out_fdc(fd->sc_type->steprate);
1023 out_fdc(0x7); /* XXX head load time == 6ms - non-DMA */
1024
1025 fdc_ienable();
1026
1027 out_fdc(NE7CMD_SEEK); /* seek function */
1028 out_fdc(fd->sc_drive); /* drive number */
1029 out_fdc(bp->b_cylinder * fd->sc_type->step);
1030
1031 fd->sc_cylin = -1;
1032 fdc->sc_state = SEEKWAIT;
1033
1034 iostat_seek(fd->sc_dk.dk_stats);
1035 disk_busy(&fd->sc_dk);
1036
1037 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1038 return 1;
1039
1040 case DOIO:
1041 doio:
1042 if (finfo)
1043 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1044 (char *)finfo;
1045
1046 type = fd->sc_type;
1047 sec = fd->sc_blkno % type->seccyl;
1048 head = sec / type->sectrac;
1049 sec -= head * type->sectrac;
1050 nblks = type->sectrac - sec;
1051 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1052 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1053 fd->sc_nblks = nblks;
1054 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1055 #ifdef DIAGNOSTIC
1056 {
1057 int block;
1058
1059 block = (fd->sc_cylin * type->heads + head)
1060 * type->sectrac + sec;
1061 if (block != fd->sc_blkno) {
1062 printf("fdcintr: block %d != blkno %qd\n",
1063 block, fd->sc_blkno);
1064 #ifdef DDB
1065 Debugger();
1066 #endif
1067 }
1068 }
1069 #endif
1070 read = bp->b_flags & B_READ ? 1 : 0;
1071
1072 /*
1073 * Setup pseudo-DMA address & count
1074 */
1075 fddmaaddr = (char *)bp->b_data + fd->sc_skip;
1076 fddmalen = fd->sc_nbytes;
1077
1078 wrt_fdc_reg(fdctl, type->rate);
1079 #ifdef FD_DEBUG
1080 printf("fdcintr: %s drive %d track %d head %d sec %d"
1081 " nblks %d\n", read ? "read" : "write",
1082 fd->sc_drive, fd->sc_cylin, head, sec, nblks);
1083 #endif
1084 fdc_ienable();
1085
1086 if (finfo) {
1087 /* formatting */
1088 if (out_fdc(NE7CMD_FORMAT) < 0) {
1089 fdc->sc_errors = 4;
1090 fdcretry(fdc);
1091 goto loop;
1092 }
1093 out_fdc((head << 2) | fd->sc_drive);
1094 out_fdc(finfo->fd_formb_secshift);
1095 out_fdc(finfo->fd_formb_nsecs);
1096 out_fdc(finfo->fd_formb_gaplen);
1097 out_fdc(finfo->fd_formb_fillbyte);
1098 } else {
1099 if (read)
1100 out_fdc(NE7CMD_READ); /* READ */
1101 else
1102 out_fdc(NE7CMD_WRITE); /* WRITE */
1103 out_fdc((head << 2) | fd->sc_drive);
1104 out_fdc(fd->sc_cylin); /* track */
1105 out_fdc(head); /* head */
1106 out_fdc(sec + 1); /* sector +1 */
1107 out_fdc(type->secsize); /* sector size */
1108 out_fdc(sec + nblks); /* last sectors */
1109 out_fdc(type->gap1); /* gap1 size */
1110 out_fdc(type->datalen); /* data length */
1111 }
1112 fdc->sc_state = IOCOMPLETE;
1113
1114 disk_busy(&fd->sc_dk);
1115
1116 /* allow 2 seconds for operation */
1117 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1118 return 1; /* will return later */
1119
1120 case SEEKWAIT:
1121 callout_stop(&fdc->sc_timo_ch);
1122 fdc->sc_state = SEEKCOMPLETE;
1123 /* allow 1/50 second for heads to settle */
1124 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1125 return 1;
1126
1127 case SEEKCOMPLETE:
1128 /* no data on seek */
1129 disk_unbusy(&fd->sc_dk, 0, 0);
1130
1131 /* Make sure seek really happened. */
1132 out_fdc(NE7CMD_SENSEI);
1133 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1134 cyl != bp->b_cylinder * fd->sc_type->step) {
1135 #ifdef FD_DEBUG
1136 fdcstatus(&fd->sc_dev, 2, "seek failed");
1137 #endif
1138 fdcretry(fdc);
1139 goto loop;
1140 }
1141 fd->sc_cylin = bp->b_cylinder;
1142 goto doio;
1143
1144 case IOTIMEDOUT:
1145 case SEEKTIMEDOUT:
1146 case RECALTIMEDOUT:
1147 case RESETTIMEDOUT:
1148 fdcretry(fdc);
1149 goto loop;
1150
1151 case IOCOMPLETE: /* IO DONE, post-analyze */
1152 callout_stop(&fdc->sc_timo_ch);
1153
1154 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1155 (bp->b_flags & B_READ));
1156
1157 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
1158 /*
1159 * As the damn chip doesn't seem to have a FIFO,
1160 * accept a few overruns as a fact of life *sigh*
1161 */
1162 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
1163 fdc->sc_state = DOSEEK;
1164 goto loop;
1165 }
1166 #ifdef FD_DEBUG
1167 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1168 "read failed" : "write failed");
1169 printf("blkno %qd nblks %d\n",
1170 fd->sc_blkno, fd->sc_nblks);
1171 #endif
1172 fdcretry(fdc);
1173 goto loop;
1174 }
1175 if (fdc->sc_errors) {
1176 diskerr(bp, "fd", "soft error", LOG_PRINTF,
1177 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1178 printf("\n");
1179 fdc->sc_errors = 0;
1180 }
1181 fdc->sc_overruns = 0;
1182 fd->sc_blkno += fd->sc_nblks;
1183 fd->sc_skip += fd->sc_nbytes;
1184 fd->sc_bcount -= fd->sc_nbytes;
1185 if (!finfo && fd->sc_bcount > 0) {
1186 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1187 goto doseek;
1188 }
1189 fdfinish(fd, bp);
1190 goto loop;
1191
1192 case DORESET:
1193 /* try a reset, keep motor on */
1194 fd_set_motor(fdc, 1);
1195 delay(100);
1196 fd_set_motor(fdc, 0);
1197 fdc->sc_state = RESETCOMPLETE;
1198 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1199 return 1; /* will return later */
1200
1201 case RESETCOMPLETE:
1202 callout_stop(&fdc->sc_timo_ch);
1203 /* clear the controller output buffer */
1204 for (i = 0; i < 4; i++) {
1205 out_fdc(NE7CMD_SENSEI);
1206 (void) fdcresult(fdc);
1207 }
1208
1209 /* fall through */
1210 case DORECAL:
1211 fdc_ienable();
1212
1213 out_fdc(NE7CMD_RECAL); /* recalibrate function */
1214 out_fdc(fd->sc_drive);
1215 fdc->sc_state = RECALWAIT;
1216 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1217 return 1; /* will return later */
1218
1219 case RECALWAIT:
1220 callout_stop(&fdc->sc_timo_ch);
1221 fdc->sc_state = RECALCOMPLETE;
1222 /* allow 1/30 second for heads to settle */
1223 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1224 return 1; /* will return later */
1225
1226 case RECALCOMPLETE:
1227 out_fdc(NE7CMD_SENSEI);
1228 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1229 #ifdef FD_DEBUG
1230 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1231 #endif
1232 fdcretry(fdc);
1233 goto loop;
1234 }
1235 fd->sc_cylin = 0;
1236 goto doseek;
1237
1238 case MOTORWAIT:
1239 if (fd->sc_flags & FD_MOTOR_WAIT)
1240 return 1; /* time's not up yet */
1241 goto doseek;
1242
1243 default:
1244 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1245 return 1;
1246 }
1247 #ifdef DIAGNOSTIC
1248 panic("fdcintr: impossible");
1249 #endif
1250 #undef st0
1251 #undef st1
1252 #undef cyl
1253 }
1254
1255 void
1256 fdcretry(fdc)
1257 struct fdc_softc *fdc;
1258 {
1259 char bits[64];
1260 struct fd_softc *fd;
1261 struct buf *bp;
1262
1263 fd = fdc->sc_drives.tqh_first;
1264 bp = BUFQ_PEEK(fd->sc_q);
1265
1266 if (fd->sc_opts & FDOPT_NORETRY)
1267 goto fail;
1268
1269 switch (fdc->sc_errors) {
1270 case 0:
1271 /* try again */
1272 fdc->sc_state = DOSEEK;
1273 break;
1274
1275 case 1: case 2: case 3:
1276 /* didn't work; try recalibrating */
1277 fdc->sc_state = DORECAL;
1278 break;
1279
1280 case 4:
1281 /* still no go; reset the bastard */
1282 fdc->sc_state = DORESET;
1283 break;
1284
1285 default:
1286 fail:
1287 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1288 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1289 fd->sc_skip / FDC_BSIZE,
1290 (struct disklabel *)NULL);
1291
1292 printf(" (st0 %s",
1293 bitmask_snprintf(fdc->sc_status[0],
1294 NE7_ST0BITS, bits,
1295 sizeof(bits)));
1296 printf(" st1 %s",
1297 bitmask_snprintf(fdc->sc_status[1],
1298 NE7_ST1BITS, bits,
1299 sizeof(bits)));
1300 printf(" st2 %s",
1301 bitmask_snprintf(fdc->sc_status[2],
1302 NE7_ST2BITS, bits,
1303 sizeof(bits)));
1304 printf(" cyl %d head %d sec %d)\n",
1305 fdc->sc_status[3],
1306 fdc->sc_status[4],
1307 fdc->sc_status[5]);
1308 }
1309 bp->b_error = EIO;
1310 fdfinish(fd, bp);
1311 }
1312 fdc->sc_errors++;
1313 }
1314
1315 int
1316 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1317 {
1318 struct fd_softc *fd;
1319 struct disklabel buffer;
1320 int error;
1321 struct fdformat_parms *form_parms;
1322 struct fdformat_cmd *form_cmd;
1323 struct ne7_fd_formb *fd_formb;
1324 unsigned int scratch;
1325 int il[FD_MAX_NSEC + 1];
1326 register int i, j;
1327
1328 fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
1329
1330 switch (cmd) {
1331 case DIOCGDINFO:
1332 fdgetdisklabel(fd, dev);
1333 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1334 return 0;
1335
1336 case DIOCGPART:
1337 fdgetdisklabel(fd, dev);
1338 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1339 ((struct partinfo *)addr)->part =
1340 &fd->sc_dk.dk_label->d_partitions[RAW_PART];
1341 return(0);
1342
1343 case DIOCWLABEL:
1344 if ((flag & FWRITE) == 0)
1345 return EBADF;
1346 /* XXX do something */
1347 return 0;
1348
1349 case DIOCSDINFO:
1350 case DIOCWDINFO:
1351 if ((flag & FWRITE) == 0)
1352 return EBADF;
1353
1354 fd->sc_flags &= ~FD_HAVELAB; /* Invalid */
1355 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
1356 if (error)
1357 return error;
1358
1359 if (cmd == DIOCWDINFO)
1360 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1361 return error;
1362
1363 case FDIOCGETFORMAT:
1364 form_parms = (struct fdformat_parms *)addr;
1365 form_parms->fdformat_version = FDFORMAT_VERSION;
1366 form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1367 form_parms->ncyl = fd->sc_type->tracks;
1368 form_parms->nspt = fd->sc_type->sectrac;
1369 form_parms->ntrk = fd->sc_type->heads;
1370 form_parms->stepspercyl = fd->sc_type->step;
1371 form_parms->gaplen = fd->sc_type->gap2;
1372 form_parms->fillbyte = fd->sc_type->fillbyte;
1373 form_parms->interleave = fd->sc_type->interleave;
1374 switch (fd->sc_type->rate) {
1375 case FDC_500KBPS:
1376 form_parms->xfer_rate = 500 * 1024;
1377 break;
1378 case FDC_300KBPS:
1379 form_parms->xfer_rate = 300 * 1024;
1380 break;
1381 case FDC_250KBPS:
1382 form_parms->xfer_rate = 250 * 1024;
1383 break;
1384 case FDC_125KBPS:
1385 form_parms->xfer_rate = 125 * 1024;
1386 break;
1387 default:
1388 return EINVAL;
1389 }
1390 return 0;
1391
1392 case FDIOCSETFORMAT:
1393 if((flag & FWRITE) == 0)
1394 return EBADF; /* must be opened for writing */
1395 form_parms = (struct fdformat_parms *)addr;
1396 if (form_parms->fdformat_version != FDFORMAT_VERSION)
1397 return EINVAL; /* wrong version of formatting prog */
1398
1399 scratch = form_parms->nbps >> 7;
1400 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1401 scratch & ~(1 << (ffs(scratch)-1)))
1402 /* not a power-of-two multiple of 128 */
1403 return EINVAL;
1404
1405 switch (form_parms->xfer_rate) {
1406 case 500 * 1024:
1407 fd->sc_type->rate = FDC_500KBPS;
1408 break;
1409 case 300 * 1024:
1410 fd->sc_type->rate = FDC_300KBPS;
1411 break;
1412 case 250 * 1024:
1413 fd->sc_type->rate = FDC_250KBPS;
1414 break;
1415 case 125 * 1024:
1416 fd->sc_type->rate = FDC_125KBPS;
1417 break;
1418 default:
1419 return EINVAL;
1420 }
1421
1422 if (form_parms->nspt > FD_MAX_NSEC ||
1423 form_parms->fillbyte > 0xff ||
1424 form_parms->interleave > 0xff)
1425 return EINVAL;
1426 fd->sc_type->sectrac = form_parms->nspt;
1427 if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1428 return EINVAL;
1429 fd->sc_type->heads = form_parms->ntrk;
1430 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1431 fd->sc_type->secsize = ffs(scratch)-1;
1432 fd->sc_type->gap2 = form_parms->gaplen;
1433 fd->sc_type->tracks = form_parms->ncyl;
1434 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1435 form_parms->nbps / DEV_BSIZE;
1436 fd->sc_type->step = form_parms->stepspercyl;
1437 fd->sc_type->fillbyte = form_parms->fillbyte;
1438 fd->sc_type->interleave = form_parms->interleave;
1439 return 0;
1440
1441 case FDIOCFORMAT_TRACK:
1442 if((flag & FWRITE) == 0)
1443 return EBADF; /* must be opened for writing */
1444 form_cmd = (struct fdformat_cmd *)addr;
1445 if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1446 return EINVAL; /* wrong version of formatting prog */
1447
1448 if (form_cmd->head >= fd->sc_type->heads ||
1449 form_cmd->cylinder >= fd->sc_type->tracks) {
1450 return EINVAL;
1451 }
1452
1453 fd_formb = malloc(sizeof(struct ne7_fd_formb),
1454 M_TEMP, M_NOWAIT);
1455 if (fd_formb == 0)
1456 return ENOMEM;
1457
1458 fd_formb->head = form_cmd->head;
1459 fd_formb->cyl = form_cmd->cylinder;
1460 fd_formb->transfer_rate = fd->sc_type->rate;
1461 fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1462 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1463 fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1464 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1465
1466 bzero(il,sizeof il);
1467 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1468 while (il[(j%fd_formb->fd_formb_nsecs)+1])
1469 j++;
1470 il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1471 j += fd->sc_type->interleave;
1472 }
1473 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1474 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1475 fd_formb->fd_formb_headno(i) = form_cmd->head;
1476 fd_formb->fd_formb_secno(i) = il[i+1];
1477 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1478 }
1479
1480 error = fdformat(dev, fd_formb, l->l_proc);
1481 free(fd_formb, M_TEMP);
1482 return error;
1483
1484 case FDIOCGETOPTS: /* get drive options */
1485 *(int *)addr = fd->sc_opts;
1486 return 0;
1487
1488 case FDIOCSETOPTS: /* set drive options */
1489 fd->sc_opts = *(int *)addr;
1490 return 0;
1491
1492
1493 default:
1494 return ENOTTY;
1495 }
1496
1497 #ifdef DIAGNOSTIC
1498 panic("fdioctl: impossible");
1499 #endif
1500 }
1501
1502 int
1503 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct proc *p)
1504 {
1505 int rv = 0;
1506 struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
1507 struct fd_type *type = fd->sc_type;
1508 struct buf *bp;
1509
1510 /* set up a buffer header for fdstrategy() */
1511 bp = getiobuf(NULL, false);
1512 if(bp == 0)
1513 return ENOBUFS;
1514 bzero((void *)bp, sizeof(struct buf));
1515 bp->b_flags = B_PHYS | B_FORMAT;
1516 bp->b_cflags |= BC_BUSY;
1517 bp->b_proc = p;
1518 bp->b_dev = dev;
1519
1520 /*
1521 * calculate a fake blkno, so fdstrategy() would initiate a
1522 * seek to the requested cylinder
1523 */
1524 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1525 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1526
1527 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1528 bp->b_data = (void *)finfo;
1529
1530 #ifdef DEBUG
1531 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
1532 #endif
1533
1534 /* now do the format */
1535 fdstrategy(bp);
1536
1537 /* ...and wait for it to complete */
1538 mutex_enter(bp->b_objlock);
1539 while(!(bp->b_oflags & BO_DONE)) {
1540 rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
1541 if (rv == EWOULDBLOCK)
1542 break;
1543 }
1544 mutex_exit(bp->b_objlock);
1545
1546 if (rv == EWOULDBLOCK) {
1547 /* timed out */
1548 rv = EIO;
1549 biodone(bp);
1550 } else if (bp->b_error != 0) {
1551 rv = bp->b_error;
1552 }
1553 putiobuf(bp);
1554 return rv;
1555 }
1556
1557
1558 /*
1559 * Obtain a disklabel. Either a real one from the disk or, if there
1560 * is none, a fake one.
1561 */
1562 static void
1563 fdgetdisklabel(fd, dev)
1564 struct fd_softc *fd;
1565 dev_t dev;
1566 {
1567 struct disklabel *lp;
1568 struct cpu_disklabel cpulab;
1569
1570 if (fd->sc_flags & FD_HAVELAB)
1571 return; /* Already got one */
1572
1573 lp = fd->sc_dk.dk_label;
1574
1575 bzero(lp, sizeof(*lp));
1576 bzero(&cpulab, sizeof(cpulab));
1577
1578 lp->d_secpercyl = fd->sc_type->seccyl;
1579 lp->d_type = DTYPE_FLOPPY;
1580 lp->d_secsize = FDC_BSIZE;
1581 lp->d_secperunit = fd->sc_type->size;
1582
1583 /*
1584 * If there is no label on the disk: fake one
1585 */
1586 if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL)
1587 fdgetdefaultlabel(fd, lp, RAW_PART);
1588 fd->sc_flags |= FD_HAVELAB;
1589
1590 if ((FDC_BSIZE * fd->sc_type->size)
1591 < (lp->d_secsize * lp->d_secperunit)) {
1592 /*
1593 * XXX: Ignore these fields. If you drop a vnddisk
1594 * on more than one floppy, you'll get disturbing
1595 * sounds!
1596 */
1597 lp->d_secpercyl = fd->sc_type->seccyl;
1598 lp->d_type = DTYPE_FLOPPY;
1599 lp->d_secsize = FDC_BSIZE;
1600 lp->d_secperunit = fd->sc_type->size;
1601 }
1602 }
1603
1604 /*
1605 * Build defaultdisk label. For now we only create a label from what we
1606 * know from 'sc'.
1607 */
1608 static void
1609 fdgetdefaultlabel(fd, lp, part)
1610 struct fd_softc *fd;
1611 struct disklabel *lp;
1612 int part;
1613 {
1614 bzero(lp, sizeof(struct disklabel));
1615
1616 lp->d_secsize = 128 * (1 << fd->sc_type->secsize);
1617 lp->d_ntracks = fd->sc_type->heads;
1618 lp->d_nsectors = fd->sc_type->sectrac;
1619 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1620 lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl;
1621 lp->d_secperunit = fd->sc_type->size;
1622
1623 lp->d_type = DTYPE_FLOPPY;
1624 lp->d_rpm = 300; /* good guess I suppose. */
1625 lp->d_interleave = 1; /* FIXME: is this OK? */
1626 lp->d_bbsize = 0;
1627 lp->d_sbsize = 0;
1628 lp->d_npartitions = part + 1;
1629 lp->d_trkseek = 6000; /* Who cares... */
1630 lp->d_magic = DISKMAGIC;
1631 lp->d_magic2 = DISKMAGIC;
1632 lp->d_checksum = dkcksum(lp);
1633 lp->d_partitions[part].p_size = lp->d_secperunit;
1634 lp->d_partitions[part].p_fstype = FS_UNUSED;
1635 lp->d_partitions[part].p_fsize = 1024;
1636 lp->d_partitions[part].p_frag = 8;
1637 }
1638