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