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