fd.c revision 1.5 1 /* $NetBSD: fd.c,v 1.5 2002/07/27 11:09:35 hannken Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*-
40 * Copyright (c) 1990 The Regents of the University of California.
41 * All rights reserved.
42 *
43 * This code is derived from software contributed to Berkeley by
44 * Don Ahn.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 * must display the following acknowledgement:
56 * This product includes software developed by the University of
57 * California, Berkeley and its contributors.
58 * 4. Neither the name of the University nor the names of its contributors
59 * may be used to endorse or promote products derived from this software
60 * without specific prior written permission.
61 *
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE.
73 *
74 * @(#)fd.c 7.4 (Berkeley) 5/25/91
75 * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
76 */
77
78 /*
79 * Floppy formatting facilities merged from FreeBSD fd.c driver:
80 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
81 * which carries the same copyright/redistribution notice as shown above with
82 * the addition of the following statement before the "Redistribution and
83 * use ..." clause:
84 *
85 * Copyright (c) 1993, 1994 by
86 * jc (at) irbs.UUCP (John Capo)
87 * vak (at) zebub.msk.su (Serge Vakulenko)
88 * ache (at) astral.msk.su (Andrew A. Chernov)
89 *
90 * Copyright (c) 1993, 1994, 1995 by
91 * joerg_wunsch (at) uriah.sax.de (Joerg Wunsch)
92 * dufault (at) hda.com (Peter Dufault)
93 */
94
95 #include "opt_ddb.h"
96
97 #include <sys/param.h>
98 #include <sys/systm.h>
99 #include <sys/callout.h>
100 #include <sys/kernel.h>
101 #include <sys/file.h>
102 #include <sys/ioctl.h>
103 #include <sys/device.h>
104 #include <sys/disklabel.h>
105 #include <sys/dkstat.h>
106 #include <sys/disk.h>
107 #include <sys/buf.h>
108 #include <sys/malloc.h>
109 #include <sys/uio.h>
110 #include <sys/syslog.h>
111 #include <sys/queue.h>
112 #include <sys/proc.h>
113 #include <sys/fdio.h>
114
115 #include <uvm/uvm_extern.h>
116
117 #include <arm/fiq.h>
118
119 #include <machine/cpu.h>
120 #include <machine/intr.h>
121 #include <machine/conf.h>
122 #include <machine/io.h>
123 #include <arm/arm32/katelib.h>
124 #include <machine/bus.h>
125
126 #include <arm/iomd/iomdreg.h>
127 #include <arm/iomd/iomdvar.h>
128
129 #include <acorn32/mainbus/piocvar.h>
130 #include <acorn32/mainbus/fdreg.h>
131
132 #include "locators.h"
133
134 #define NE7CMD_CONFIGURE 0x13
135
136 #define FDUNIT(dev) (minor(dev) / 8)
137 #define FDTYPE(dev) (minor(dev) % 8)
138
139 /* XXX misuse a flag to identify format operation */
140 #define B_FORMAT B_XXX
141
142 enum fdc_state {
143 DEVIDLE = 0,
144 MOTORWAIT,
145 DOSEEK,
146 SEEKWAIT,
147 SEEKTIMEDOUT,
148 SEEKCOMPLETE,
149 DOIO,
150 IOCOMPLETE,
151 IOTIMEDOUT,
152 DORESET,
153 RESETCOMPLETE,
154 RESETTIMEDOUT,
155 DORECAL,
156 RECALWAIT,
157 RECALTIMEDOUT,
158 RECALCOMPLETE,
159 };
160
161 /* software state, per controller */
162 struct fdc_softc {
163 struct device sc_dev; /* boilerplate */
164 void *sc_ih;
165
166 bus_space_tag_t sc_iot; /* ISA i/o space identifier */
167 bus_space_handle_t sc_ioh; /* ISA io handle */
168
169 struct callout sc_timo_ch; /* timeout callout */
170 struct callout sc_intr_ch; /* pseudo-intr callout */
171
172 /* ...for pseudo-DMA... */
173 struct fiqhandler sc_fh; /* FIQ handler descriptor */
174 struct fiqregs sc_fr; /* FIQ handler reg context */
175 int sc_drq;
176
177 struct fd_softc *sc_fd[4]; /* pointers to children */
178 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
179 enum fdc_state sc_state;
180 int sc_errors; /* number of retries so far */
181 u_char sc_status[7]; /* copy of registers */
182 };
183
184 /* controller driver configuration */
185 int fdcprobe __P((struct device *, struct cfdata *, void *));
186 int fdprint __P((void *, const char *));
187 void fdcattach __P((struct device *, struct device *, void *));
188
189 struct cfattach fdc_ca = {
190 sizeof(struct fdc_softc), fdcprobe, fdcattach
191 };
192
193 /*
194 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
195 * we tell them apart.
196 */
197 struct fd_type {
198 int sectrac; /* sectors per track */
199 int heads; /* number of heads */
200 int seccyl; /* sectors per cylinder */
201 int secsize; /* size code for sectors */
202 int datalen; /* data len when secsize = 0 */
203 int steprate; /* step rate and head unload time */
204 int gap1; /* gap len between sectors */
205 int gap2; /* formatting gap */
206 int cyls; /* total num of cylinders */
207 int size; /* size of disk in sectors */
208 int step; /* steps per cylinder */
209 int rate; /* transfer speed code */
210 u_char fillbyte; /* format fill byte */
211 u_char interleave; /* interleave factor (formatting) */
212 char *name;
213 };
214
215 /* The order of entries in the following table is important -- BEWARE! */
216 struct fd_type fd_types[] = {
217 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
218 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */
219 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
220 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
221 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */
222 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */
223 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
224 };
225
226 /* software state, per disk (with up to 4 disks per ctlr) */
227 struct fd_softc {
228 struct device sc_dev;
229 struct disk sc_dk;
230
231 struct fd_type *sc_deftype; /* default type descriptor */
232 struct fd_type *sc_type; /* current type descriptor */
233 struct fd_type sc_type_copy; /* copy for fiddling when formatting */
234
235 struct callout sc_motoron_ch;
236 struct callout sc_motoroff_ch;
237
238 daddr_t sc_blkno; /* starting block number */
239 int sc_bcount; /* byte count left */
240 int sc_opts; /* user-set options */
241 int sc_skip; /* bytes already transferred */
242 int sc_nblks; /* number of blocks currently transferring */
243 int sc_nbytes; /* number of bytes currently transferring */
244
245 int sc_drive; /* physical unit number */
246 int sc_flags;
247 #define FD_OPEN 0x01 /* it's open */
248 #define FD_MOTOR 0x02 /* motor should be on */
249 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
250 int sc_cylin; /* where we think the head is */
251
252 void *sc_sdhook; /* saved shutdown hook for drive. */
253
254 TAILQ_ENTRY(fd_softc) sc_drivechain;
255 int sc_ops; /* I/O ops since last switch */
256 struct bufq_state sc_q; /* pending I/O requests */
257 int sc_active; /* number of active I/O operations */
258 };
259
260 /* floppy driver configuration */
261 int fdprobe __P((struct device *, struct cfdata *, void *));
262 void fdattach __P((struct device *, struct device *, void *));
263
264 extern char floppy_read_fiq[], floppy_read_fiq_end[];
265 extern char floppy_write_fiq[], floppy_write_fiq_end[];
266
267 struct cfattach fd_ca = {
268 sizeof(struct fd_softc), fdprobe, fdattach
269 };
270
271 extern struct cfdriver fd_cd;
272
273 void fdgetdisklabel __P((struct fd_softc *));
274 int fd_get_parms __P((struct fd_softc *));
275 void fdstrategy __P((struct buf *));
276 void fdstart __P((struct fd_softc *));
277
278 struct dkdriver fddkdriver = { fdstrategy };
279
280 struct fd_type *fd_nvtotype __P((char *, int, int));
281 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
282 void fd_motor_off __P((void *arg));
283 void fd_motor_on __P((void *arg));
284 int fdcresult __P((struct fdc_softc *fdc));
285 int out_fdc __P((bus_space_tag_t iot, bus_space_handle_t ioh, u_char x));
286 void fdcstart __P((struct fdc_softc *fdc));
287 void fdcstatus __P((struct device *dv, int n, char *s));
288 void fdctimeout __P((void *arg));
289 void fdcpseudointr __P((void *arg));
290 int fdcintr __P((void *));
291 void fdcretry __P((struct fdc_softc *fdc));
292 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
293 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
294 int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
295
296 int
297 fdcprobe(parent, cf, aux)
298 struct device *parent;
299 struct cfdata *cf;
300 void *aux;
301 {
302 struct pioc_attach_args *pa = aux;
303 bus_space_tag_t iot;
304 bus_space_handle_t ioh;
305 int rv;
306
307 if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0)
308 return(0);
309
310 iot = pa->pa_iot;
311 rv = 0;
312
313 /* Map the i/o space. */
314 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
315 return 0;
316
317 /* reset */
318 bus_space_write_2(iot, ioh, fdout, 0);
319 delay(100);
320 bus_space_write_2(iot, ioh, fdout, FDO_FRST);
321
322 /* see if it can handle a command */
323 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
324 goto out;
325 out_fdc(iot, ioh, 0xdf);
326 out_fdc(iot, ioh, 2);
327
328 rv = 1;
329 pa->pa_iosize = FDC_NPORT;
330
331 out:
332 bus_space_unmap(iot, ioh, FDC_NPORT);
333 return rv;
334 }
335
336 /*
337 * Arguments passed between fdcattach and fdprobe.
338 */
339 struct fdc_attach_args {
340 int fa_drive;
341 struct fd_type *fa_deftype;
342 };
343
344 /*
345 * Print the location of a disk drive (called just before attaching the
346 * the drive). If `fdc' is not NULL, the drive was found but was not
347 * in the system config file; print the drive name as well.
348 * Return QUIET (config_find ignores this if the device was configured) to
349 * avoid printing `fdN not configured' messages.
350 */
351 int
352 fdprint(aux, fdc)
353 void *aux;
354 const char *fdc;
355 {
356 register struct fdc_attach_args *fa = aux;
357
358 if (!fdc)
359 printf(" drive %d", fa->fa_drive);
360 return QUIET;
361 }
362
363 void
364 fdcattach(parent, self, aux)
365 struct device *parent, *self;
366 void *aux;
367 {
368 struct fdc_softc *fdc = (void *)self;
369 bus_space_tag_t iot;
370 bus_space_handle_t ioh;
371 struct pioc_attach_args *pa = aux;
372 struct fdc_attach_args fa;
373 int type;
374
375 iot = pa->pa_iot;
376
377 /* Re-map the I/O space. */
378 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
379 panic("fdcattach: couldn't map I/O ports");
380
381 fdc->sc_iot = iot;
382 fdc->sc_ioh = ioh;
383
384 fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq;
385 fdc->sc_state = DEVIDLE;
386 TAILQ_INIT(&fdc->sc_drives);
387
388 printf("\n");
389
390 callout_init(&fdc->sc_timo_ch);
391 callout_init(&fdc->sc_intr_ch);
392
393 fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc",
394 fdcintr, fdc);
395 if (!fdc->sc_ih)
396 panic("%s: Cannot claim IRQ %d\n", self->dv_xname, pa->pa_irq);
397
398 #if 0
399 /*
400 * The NVRAM info only tells us about the first two disks on the
401 * `primary' floppy controller.
402 */
403 if (fdc->sc_dev.dv_unit == 0)
404 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
405 else
406 type = -1;
407 #endif
408 type = 0x10; /* XXX - hardcoded for 1 floppy */
409
410 /* physical limit: four drives per controller. */
411 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
412 if (type >= 0 && fa.fa_drive < 2)
413 fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname,
414 type, fa.fa_drive);
415 else
416 fa.fa_deftype = NULL; /* unknown */
417 (void)config_found(self, (void *)&fa, fdprint);
418 }
419 }
420
421 int
422 fdprobe(parent, cf, aux)
423 struct device *parent;
424 struct cfdata *cf;
425 void *aux;
426 {
427 struct fdc_softc *fdc = (void *)parent;
428 struct fdc_attach_args *fa = aux;
429 int drive = fa->fa_drive;
430 bus_space_tag_t iot = fdc->sc_iot;
431 bus_space_handle_t ioh = fdc->sc_ioh;
432 int n;
433
434 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT
435 && cf->cf_loc[FDCCF_DRIVE] != drive)
436 return 0;
437 /*
438 * XXX
439 * This is to work around some odd interactions between this driver
440 * and SMC Ethernet cards.
441 */
442
443 /* Don't need this for arm32 port but leave for the time being (it won't hurt) */
444
445 if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
446 return 0;
447
448 /* select drive and turn on motor */
449 bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
450 /* wait for motor to spin up */
451 delay(250000);
452 out_fdc(iot, ioh, NE7CMD_RECAL);
453 out_fdc(iot, ioh, drive);
454 /* wait for recalibrate */
455 delay(2000000);
456 out_fdc(iot, ioh, NE7CMD_SENSEI);
457 n = fdcresult(fdc);
458 #ifdef FD_DEBUG
459 {
460 int i;
461 printf("fdprobe: status");
462 for (i = 0; i < n; i++)
463 printf(" %x", fdc->sc_status[i]);
464 printf("\n");
465 }
466 #endif
467 /* turn off motor */
468 bus_space_write_1(iot, ioh, fdout, FDO_FRST);
469
470 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
471 return 0;
472
473 return 1;
474 }
475
476 /*
477 * Controller is working, and drive responded. Attach it.
478 */
479 void
480 fdattach(parent, self, aux)
481 struct device *parent, *self;
482 void *aux;
483 {
484 struct fdc_softc *fdc = (void *)parent;
485 struct fd_softc *fd = (void *)self;
486 struct fdc_attach_args *fa = aux;
487 struct fd_type *type = fa->fa_deftype;
488 int drive = fa->fa_drive;
489
490 callout_init(&fd->sc_motoron_ch);
491 callout_init(&fd->sc_motoroff_ch);
492
493 /* XXX Allow `flags' to override device type? */
494
495 if (type)
496 printf(": %s %d cyl, %d head, %d sec\n", type->name,
497 type->cyls, type->heads, type->sectrac);
498 else
499 printf(": density unknown\n");
500
501 bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
502 fd->sc_cylin = -1;
503 fd->sc_drive = drive;
504 fd->sc_deftype = type;
505 fdc->sc_fd[drive] = fd;
506
507 /*
508 * Initialize and attach the disk structure.
509 */
510 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
511 fd->sc_dk.dk_driver = &fddkdriver;
512 disk_attach(&fd->sc_dk);
513
514 /* Needed to power off if the motor is on when we halt. */
515
516 }
517
518 /*
519 * Translate nvram type into internal data structure. Return NULL for
520 * none/unknown/unusable.
521 */
522 struct fd_type *
523 fd_nvtotype(fdc, nvraminfo, drive)
524 char *fdc;
525 int nvraminfo, drive;
526 {
527 int type;
528
529 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
530 switch (type) {
531 #ifndef RC7500
532 case 0x00 :
533 return NULL;
534 #else
535 case 0x00 :
536 #endif /* !RC7500 */
537 case 0x10 :
538 return &fd_types[0];
539 default:
540 printf("%s: drive %d: unknown device type 0x%x\n",
541 fdc, drive, type);
542 return NULL;
543 }
544 }
545
546 __inline struct fd_type *
547 fd_dev_to_type(fd, dev)
548 struct fd_softc *fd;
549 dev_t dev;
550 {
551 int type = FDTYPE(dev);
552
553 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
554 return NULL;
555 return type ? &fd_types[type - 1] : fd->sc_deftype;
556 }
557
558 void
559 fdstrategy(bp)
560 register struct buf *bp; /* IO operation to perform */
561 {
562 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
563 int sz;
564 int s;
565
566 /* Valid unit, controller, and request? */
567 if (bp->b_blkno < 0 ||
568 ((bp->b_bcount % FDC_BSIZE) != 0 &&
569 (bp->b_flags & B_FORMAT) == 0)) {
570 bp->b_error = EINVAL;
571 goto bad;
572 }
573
574 /* If it's a null transfer, return immediately. */
575 if (bp->b_bcount == 0)
576 goto done;
577
578 sz = howmany(bp->b_bcount, FDC_BSIZE);
579
580 if (bp->b_blkno + sz > fd->sc_type->size) {
581 sz = fd->sc_type->size - bp->b_blkno;
582 if (sz == 0) {
583 /* If exactly at end of disk, return EOF. */
584 goto done;
585 }
586 if (sz < 0) {
587 /* If past end of disk, return EINVAL. */
588 bp->b_error = EINVAL;
589 goto bad;
590 }
591 /* Otherwise, truncate request. */
592 bp->b_bcount = sz << DEV_BSHIFT;
593 }
594
595 bp->b_rawblkno = bp->b_blkno;
596 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
597
598 #ifdef FD_DEBUG
599 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
600 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
601 #endif
602
603 /* Queue transfer on drive, activate drive and controller if idle. */
604 s = splbio();
605 BUFQ_PUT(&fd->sc_q, bp);
606 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
607 if (fd->sc_active == 0)
608 fdstart(fd);
609 #ifdef DIAGNOSTIC
610 else {
611 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
612 if (fdc->sc_state == DEVIDLE) {
613 printf("fdstrategy: controller inactive\n");
614 fdcstart(fdc);
615 }
616 }
617 #endif
618 splx(s);
619 return;
620
621 bad:
622 bp->b_flags |= B_ERROR;
623 done:
624 /* Toss transfer; we're done early. */
625 bp->b_resid = bp->b_bcount;
626 biodone(bp);
627 }
628
629 void
630 fdstart(fd)
631 struct fd_softc *fd;
632 {
633 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
634 int active = fdc->sc_drives.tqh_first != 0;
635
636 /* Link into controller queue. */
637 fd->sc_active = 1;
638 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
639
640 /* If controller not already active, start it. */
641 if (!active)
642 fdcstart(fdc);
643 }
644
645 void
646 fdfinish(fd, bp)
647 struct fd_softc *fd;
648 struct buf *bp;
649 {
650 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
651
652 /*
653 * Move this drive to the end of the queue to give others a `fair'
654 * chance. We only force a switch if N operations are completed while
655 * another drive is waiting to be serviced, since there is a long motor
656 * startup delay whenever we switch.
657 */
658 (void)BUFQ_GET(&fd->sc_q);
659 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
660 fd->sc_ops = 0;
661 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
662 if (BUFQ_PEEK(&fd->sc_q) != NULL)
663 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
664 else
665 fd->sc_active = 0;
666 }
667 bp->b_resid = fd->sc_bcount;
668 fd->sc_skip = 0;
669
670 biodone(bp);
671 /* turn off motor 5s from now */
672 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
673 fdc->sc_state = DEVIDLE;
674 }
675
676 int
677 fdread(dev, uio, flags)
678 dev_t dev;
679 struct uio *uio;
680 int flags;
681 {
682
683 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
684 }
685
686 int
687 fdwrite(dev, uio, flags)
688 dev_t dev;
689 struct uio *uio;
690 int flags;
691 {
692
693 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
694 }
695
696 void
697 fd_set_motor(fdc, reset)
698 struct fdc_softc *fdc;
699 int reset;
700 {
701 struct fd_softc *fd;
702 u_char status;
703 int n;
704
705 if ((fd = fdc->sc_drives.tqh_first) != NULL)
706 status = fd->sc_drive;
707 else
708 status = 0;
709 if (!reset)
710 status |= FDO_FRST | FDO_FDMAEN;
711 for (n = 0; n < 4; n++)
712 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
713 status |= FDO_MOEN(n);
714 bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
715 }
716
717 void
718 fd_motor_off(arg)
719 void *arg;
720 {
721 struct fd_softc *fd = arg;
722 int s;
723
724 s = splbio();
725 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
726 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
727 splx(s);
728 }
729
730 void
731 fd_motor_on(arg)
732 void *arg;
733 {
734 struct fd_softc *fd = arg;
735 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
736 int s;
737
738 s = splbio();
739 fd->sc_flags &= ~FD_MOTOR_WAIT;
740 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
741 (void) fdcintr(fdc);
742 splx(s);
743 }
744
745 int
746 fdcresult(fdc)
747 struct fdc_softc *fdc;
748 {
749 bus_space_tag_t iot = fdc->sc_iot;
750 bus_space_handle_t ioh = fdc->sc_ioh;
751 u_char i;
752 int j = 100000,
753 n = 0;
754
755 for (; j; j--) {
756 i = bus_space_read_1(iot, ioh, fdsts) &
757 (NE7_DIO | NE7_RQM | NE7_CB);
758 if (i == NE7_RQM)
759 return n;
760 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
761 if (n >= sizeof(fdc->sc_status)) {
762 log(LOG_ERR, "fdcresult: overrun\n");
763 return -1;
764 }
765 fdc->sc_status[n++] =
766 bus_space_read_1(iot, ioh, fddata);
767 }
768 delay(10);
769 }
770 log(LOG_ERR, "fdcresult: timeout\n");
771 return -1;
772 }
773
774 int
775 out_fdc(iot, ioh, x)
776 bus_space_tag_t iot;
777 bus_space_handle_t ioh;
778 u_char x;
779 {
780 int i = 100000;
781
782 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
783 if (i <= 0)
784 return -1;
785 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
786 if (i <= 0)
787 return -1;
788 bus_space_write_2(iot, ioh, fddata, x);
789 return 0;
790 }
791
792 int
793 fdopen(dev, flags, mode, p)
794 dev_t dev;
795 int flags;
796 int mode;
797 struct proc *p;
798 {
799 int unit;
800 struct fd_softc *fd;
801 struct fd_type *type;
802
803 unit = FDUNIT(dev);
804 if (unit >= fd_cd.cd_ndevs)
805 return ENXIO;
806 fd = fd_cd.cd_devs[unit];
807 if (fd == 0)
808 return ENXIO;
809 type = fd_dev_to_type(fd, dev);
810 if (type == NULL)
811 return ENXIO;
812
813 if ((fd->sc_flags & FD_OPEN) != 0 &&
814 memcmp(fd->sc_type, type, sizeof(*type)))
815 return EBUSY;
816
817 fd->sc_type_copy = *type;
818 fd->sc_type = &fd->sc_type_copy;
819 fd->sc_cylin = -1;
820 fd->sc_flags |= FD_OPEN;
821
822 return 0;
823 }
824
825 int
826 fdclose(dev, flags, mode, p)
827 dev_t dev;
828 int flags;
829 int mode;
830 struct proc *p;
831 {
832 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
833
834 fd->sc_flags &= ~FD_OPEN;
835 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
836 return 0;
837 }
838
839 void
840 fdcstart(fdc)
841 struct fdc_softc *fdc;
842 {
843
844 #ifdef DIAGNOSTIC
845 /* only got here if controller's drive queue was inactive; should
846 be in idle state */
847 if (fdc->sc_state != DEVIDLE) {
848 printf("fdcstart: not idle\n");
849 return;
850 }
851 #endif
852 (void) fdcintr(fdc);
853 }
854
855 void
856 fdcstatus(dv, n, s)
857 struct device *dv;
858 int n;
859 char *s;
860 {
861 struct fdc_softc *fdc = (void *)dv->dv_parent;
862 char bits[64];
863
864 if (n == 0) {
865 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
866 (void) fdcresult(fdc);
867 n = 2;
868 }
869
870 printf("%s: %s", dv->dv_xname, s);
871
872 switch (n) {
873 case 0:
874 printf("\n");
875 break;
876 case 2:
877 printf(" (st0 %s cyl %d)\n",
878 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
879 bits, sizeof(bits)), fdc->sc_status[1]);
880 break;
881 case 7:
882 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
883 NE7_ST0BITS, bits, sizeof(bits)));
884 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
885 NE7_ST1BITS, bits, sizeof(bits)));
886 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
887 NE7_ST2BITS, bits, sizeof(bits)));
888 printf(" cyl %d head %d sec %d)\n",
889 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
890 break;
891 #ifdef DIAGNOSTIC
892 default:
893 printf("\nfdcstatus: weird size");
894 break;
895 #endif
896 }
897 }
898
899 void
900 fdctimeout(arg)
901 void *arg;
902 {
903 struct fdc_softc *fdc = arg;
904 struct fd_softc *fd = fdc->sc_drives.tqh_first;
905 int s;
906
907 s = splbio();
908 #ifdef DEBUG
909 log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
910 #endif
911 fdcstatus(&fd->sc_dev, 0, "timeout");
912
913 if (BUFQ_PEEK(&fd->sc_q) != NULL)
914 fdc->sc_state++;
915 else
916 fdc->sc_state = DEVIDLE;
917
918 (void) fdcintr(fdc);
919 splx(s);
920 }
921
922 void
923 fdcpseudointr(arg)
924 void *arg;
925 {
926 int s;
927
928 /* Just ensure it has the right spl. */
929 s = splbio();
930 (void) fdcintr(arg);
931 splx(s);
932 }
933
934 int
935 fdcintr(arg)
936 void *arg;
937 {
938 struct fdc_softc *fdc = arg;
939 #define st0 fdc->sc_status[0]
940 #define cyl fdc->sc_status[1]
941 struct fd_softc *fd;
942 struct buf *bp;
943 bus_space_tag_t iot = fdc->sc_iot;
944 bus_space_handle_t ioh = fdc->sc_ioh;
945 int read, head, sec, i, nblks;
946 struct fd_type *type;
947 struct ne7_fd_formb *finfo = NULL;
948
949 loop:
950 /* Is there a drive for the controller to do a transfer with? */
951 fd = fdc->sc_drives.tqh_first;
952 if (fd == NULL) {
953 fdc->sc_state = DEVIDLE;
954 return 1;
955 }
956
957 /* Is there a transfer to this drive? If not, deactivate drive. */
958 bp = BUFQ_PEEK(&fd->sc_q);
959 if (bp == NULL) {
960 fd->sc_ops = 0;
961 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
962 fd->sc_active = 0;
963 goto loop;
964 }
965
966 if (bp->b_flags & B_FORMAT)
967 finfo = (struct ne7_fd_formb *)bp->b_data;
968
969 switch (fdc->sc_state) {
970 case DEVIDLE:
971 fdc->sc_errors = 0;
972 fd->sc_skip = 0;
973 fd->sc_bcount = bp->b_bcount;
974 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
975 callout_stop(&fd->sc_motoroff_ch);
976 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
977 fdc->sc_state = MOTORWAIT;
978 return 1;
979 }
980 if ((fd->sc_flags & FD_MOTOR) == 0) {
981 /* Turn on the motor, being careful about pairing. */
982 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
983 if (ofd && ofd->sc_flags & FD_MOTOR) {
984 callout_stop(&ofd->sc_motoroff_ch);
985 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
986 }
987 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
988 fd_set_motor(fdc, 0);
989 fdc->sc_state = MOTORWAIT;
990 /* Allow .25s for motor to stabilize. */
991 callout_reset(&fd->sc_motoron_ch, hz / 4,
992 fd_motor_on, fd);
993 return 1;
994 }
995 /* Make sure the right drive is selected. */
996 fd_set_motor(fdc, 0);
997
998 /* fall through */
999 case DOSEEK:
1000 doseek:
1001 if (fd->sc_cylin == bp->b_cylinder)
1002 goto doio;
1003
1004 #if 1
1005 out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
1006 out_fdc(iot, ioh, 0);
1007 out_fdc(iot, ioh, 0x18);
1008 out_fdc(iot, ioh, 0);
1009 #endif
1010 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1011 out_fdc(iot, ioh, fd->sc_type->steprate);
1012 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
1013
1014 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1015 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1016 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1017
1018 fd->sc_cylin = -1;
1019 fdc->sc_state = SEEKWAIT;
1020
1021 fd->sc_dk.dk_seek++;
1022 disk_busy(&fd->sc_dk);
1023
1024 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1025 return 1;
1026
1027 case DOIO:
1028 doio:
1029 type = fd->sc_type;
1030 if (finfo)
1031 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1032 (char *)finfo;
1033 sec = fd->sc_blkno % type->seccyl;
1034 nblks = type->seccyl - sec;
1035 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1036 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1037 fd->sc_nblks = nblks;
1038 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1039 head = sec / type->sectrac;
1040 sec -= head * type->sectrac;
1041 #ifdef DIAGNOSTIC
1042 {int block;
1043 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
1044 if (block != fd->sc_blkno) {
1045 printf("fdcintr: block %d != blkno %d\n",
1046 block, fd->sc_blkno);
1047 #ifdef DDB
1048 Debugger();
1049 #endif
1050 }}
1051 #endif
1052 read = bp->b_flags & B_READ;
1053 if (read) {
1054 fdc->sc_fh.fh_func = floppy_read_fiq;
1055 fdc->sc_fh.fh_size = floppy_read_fiq_end -
1056 floppy_read_fiq;
1057 } else {
1058 fdc->sc_fh.fh_func = floppy_write_fiq;
1059 fdc->sc_fh.fh_size = floppy_read_fiq_end -
1060 floppy_read_fiq;
1061 }
1062 fdc->sc_fh.fh_flags = 0;
1063 fdc->sc_fh.fh_regs = &fdc->sc_fr;
1064 fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
1065 fdc->sc_fr.fr_r10 = fd->sc_nbytes;
1066 fdc->sc_fr.fr_r11 = (u_int)(bp->b_data + fd->sc_skip);
1067 fdc->sc_fr.fr_r12 = fdc->sc_drq;
1068 #ifdef FD_DEBUG
1069 printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
1070 fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
1071 fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
1072 #endif
1073 if (fiq_claim(&fdc->sc_fh) == -1)
1074 panic("%s: Cannot claim FIQ vector\n", fdc->sc_dev.dv_xname);
1075 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
1076 bus_space_write_2(iot, ioh, fdctl, type->rate);
1077 #ifdef FD_DEBUG
1078 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1079 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1080 head, sec, nblks);
1081 #endif
1082 if (finfo) {
1083 /* formatting */
1084 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1085 fdc->sc_errors = 4;
1086 fdcretry(fdc);
1087 goto loop;
1088 }
1089 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1090 out_fdc(iot, ioh, finfo->fd_formb_secshift);
1091 out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1092 out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1093 out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1094 } else {
1095 if (read)
1096 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1097 else
1098 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1099 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1100 out_fdc(iot, ioh, fd->sc_cylin); /* track */
1101 out_fdc(iot, ioh, head);
1102 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1103 out_fdc(iot, ioh, type->secsize);/* sector size */
1104 out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1105 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1106 out_fdc(iot, ioh, type->datalen);/* data length */
1107 }
1108 fdc->sc_state = IOCOMPLETE;
1109
1110 disk_busy(&fd->sc_dk);
1111
1112 /* allow 2 seconds for operation */
1113 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1114 return 1; /* will return later */
1115
1116 case SEEKWAIT:
1117 callout_stop(&fdc->sc_timo_ch);
1118 fdc->sc_state = SEEKCOMPLETE;
1119 /* allow 1/50 second for heads to settle */
1120 #if 0
1121 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1122 #endif
1123 return 1;
1124
1125 case SEEKCOMPLETE:
1126 disk_unbusy(&fd->sc_dk, 0); /* no data on seek */
1127
1128 /* Make sure seek really happened. */
1129 out_fdc(iot, ioh, NE7CMD_SENSEI);
1130 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1131 cyl != bp->b_cylinder * fd->sc_type->step) {
1132 #ifdef FD_DEBUG
1133 fdcstatus(&fd->sc_dev, 2, "seek failed");
1134 #endif
1135 fdcretry(fdc);
1136 goto loop;
1137 }
1138 fd->sc_cylin = bp->b_cylinder;
1139 goto doio;
1140
1141 case IOTIMEDOUT:
1142 fiq_release(&fdc->sc_fh);
1143 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1144 case SEEKTIMEDOUT:
1145 case RECALTIMEDOUT:
1146 case RESETTIMEDOUT:
1147 fdcretry(fdc);
1148 goto loop;
1149
1150 case IOCOMPLETE: /* IO DONE, post-analyze */
1151 callout_stop(&fdc->sc_timo_ch);
1152
1153 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1154
1155 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1156 fiq_release(&fdc->sc_fh);
1157 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1158 #ifdef FD_DEBUG
1159 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1160 "read failed" : "write failed");
1161 printf("blkno %d nblks %d\n",
1162 fd->sc_blkno, fd->sc_nblks);
1163 #endif
1164 fdcretry(fdc);
1165 goto loop;
1166 }
1167 fiq_release(&fdc->sc_fh);
1168 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1169 if (fdc->sc_errors) {
1170 #if 0
1171 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1172 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1173 printf("\n");
1174 #endif
1175 fdc->sc_errors = 0;
1176 }
1177 fd->sc_blkno += fd->sc_nblks;
1178 fd->sc_skip += fd->sc_nbytes;
1179 fd->sc_bcount -= fd->sc_nbytes;
1180 if (!finfo && fd->sc_bcount > 0) {
1181 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1182 goto doseek;
1183 }
1184 fdfinish(fd, bp);
1185 goto loop;
1186
1187 case DORESET:
1188 /* try a reset, keep motor on */
1189 fd_set_motor(fdc, 1);
1190 delay(100);
1191 fd_set_motor(fdc, 0);
1192 fdc->sc_state = RESETCOMPLETE;
1193 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1194 return 1; /* will return later */
1195
1196 case RESETCOMPLETE:
1197 callout_stop(&fdc->sc_timo_ch);
1198 /* clear the controller output buffer */
1199 for (i = 0; i < 4; i++) {
1200 out_fdc(iot, ioh, NE7CMD_SENSEI);
1201 (void) fdcresult(fdc);
1202 }
1203
1204 /* fall through */
1205 case DORECAL:
1206 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1207 out_fdc(iot, ioh, 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 #if 0
1217 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1218 #endif
1219 return 1; /* will return later */
1220
1221 case RECALCOMPLETE:
1222 out_fdc(iot, ioh, NE7CMD_SENSEI);
1223 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1224 #ifdef FD_DEBUG
1225 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1226 #endif
1227 fdcretry(fdc);
1228 goto loop;
1229 }
1230 fd->sc_cylin = 0;
1231 goto doseek;
1232
1233 case MOTORWAIT:
1234 if (fd->sc_flags & FD_MOTOR_WAIT)
1235 return 1; /* time's not up yet */
1236 goto doseek;
1237
1238 default:
1239 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1240 return 1;
1241 }
1242 #ifdef DIAGNOSTIC
1243 panic("fdcintr: impossible");
1244 #endif
1245 #undef st0
1246 #undef cyl
1247 }
1248
1249 void
1250 fdcretry(fdc)
1251 struct fdc_softc *fdc;
1252 {
1253 char bits[64];
1254 struct fd_softc *fd;
1255 struct buf *bp;
1256
1257 fd = fdc->sc_drives.tqh_first;
1258 bp = BUFQ_PEEK(&fd->sc_q);
1259
1260 if (fd->sc_opts & FDOPT_NORETRY)
1261 goto fail;
1262 switch (fdc->sc_errors) {
1263 case 0:
1264 /* try again */
1265 fdc->sc_state = DOSEEK;
1266 break;
1267
1268 case 1: case 2: case 3:
1269 /* didn't work; try recalibrating */
1270 fdc->sc_state = DORECAL;
1271 break;
1272
1273 case 4:
1274 /* still no go; reset the bastard */
1275 fdc->sc_state = DORESET;
1276 break;
1277
1278 default:
1279 fail:
1280 if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1281 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1282 fd->sc_skip / FDC_BSIZE,
1283 (struct disklabel *)NULL);
1284
1285 printf(" (st0 %s",
1286 bitmask_snprintf(fdc->sc_status[0],
1287 NE7_ST0BITS, bits,
1288 sizeof(bits)));
1289 printf(" st1 %s",
1290 bitmask_snprintf(fdc->sc_status[1],
1291 NE7_ST1BITS, bits,
1292 sizeof(bits)));
1293 printf(" st2 %s",
1294 bitmask_snprintf(fdc->sc_status[2],
1295 NE7_ST2BITS, bits,
1296 sizeof(bits)));
1297 printf(" cyl %d head %d sec %d)\n",
1298 fdc->sc_status[3],
1299 fdc->sc_status[4],
1300 fdc->sc_status[5]);
1301 }
1302
1303 bp->b_flags |= B_ERROR;
1304 bp->b_error = EIO;
1305 fdfinish(fd, bp);
1306 }
1307 fdc->sc_errors++;
1308 }
1309
1310 int
1311 fdsize(dev)
1312 dev_t dev;
1313 {
1314
1315 /* Swapping to floppies would not make sense. */
1316 return -1;
1317 }
1318
1319 int
1320 fddump(dev, blkno, va, size)
1321 dev_t dev;
1322 daddr_t blkno;
1323 caddr_t va;
1324 size_t size;
1325 {
1326
1327 /* Not implemented. */
1328 return ENXIO;
1329 }
1330
1331 int
1332 fdioctl(dev, cmd, addr, flag, p)
1333 dev_t dev;
1334 u_long cmd;
1335 caddr_t addr;
1336 int flag;
1337 struct proc *p;
1338 {
1339 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1340 struct fdformat_parms *form_parms;
1341 struct fdformat_cmd *form_cmd;
1342 struct ne7_fd_formb *fd_formb;
1343 struct disklabel buffer;
1344 int error;
1345 unsigned int scratch;
1346 int il[FD_MAX_NSEC + 1];
1347 register int i, j;
1348
1349 switch (cmd) {
1350 case DIOCGDINFO:
1351 memset(&buffer, 0, sizeof(buffer));
1352
1353 buffer.d_secpercyl = fd->sc_type->seccyl;
1354 buffer.d_type = DTYPE_FLOPPY;
1355 buffer.d_secsize = FDC_BSIZE;
1356
1357 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1358 return EINVAL;
1359
1360 *(struct disklabel *)addr = buffer;
1361 return 0;
1362
1363 case DIOCWLABEL:
1364 if ((flag & FWRITE) == 0)
1365 return EBADF;
1366 /* XXX do something */
1367 return 0;
1368
1369 case DIOCWDINFO:
1370 if ((flag & FWRITE) == 0)
1371 return EBADF;
1372
1373 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1374 if (error)
1375 return error;
1376
1377 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1378 return error;
1379
1380 case FDIOCGETFORMAT:
1381 form_parms = (struct fdformat_parms *)addr;
1382 form_parms->fdformat_version = FDFORMAT_VERSION;
1383 form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1384 form_parms->ncyl = fd->sc_type->cyls;
1385 form_parms->nspt = fd->sc_type->sectrac;
1386 form_parms->ntrk = fd->sc_type->heads;
1387 form_parms->stepspercyl = fd->sc_type->step;
1388 form_parms->gaplen = fd->sc_type->gap2;
1389 form_parms->fillbyte = fd->sc_type->fillbyte;
1390 form_parms->interleave = fd->sc_type->interleave;
1391 switch (fd->sc_type->rate) {
1392 case FDC_500KBPS:
1393 form_parms->xfer_rate = 500 * 1024;
1394 break;
1395 case FDC_300KBPS:
1396 form_parms->xfer_rate = 300 * 1024;
1397 break;
1398 case FDC_250KBPS:
1399 form_parms->xfer_rate = 250 * 1024;
1400 break;
1401 default:
1402 return EINVAL;
1403 }
1404 return 0;
1405
1406 case FDIOCSETFORMAT:
1407 if((flag & FWRITE) == 0)
1408 return EBADF; /* must be opened for writing */
1409 form_parms = (struct fdformat_parms *)addr;
1410 if (form_parms->fdformat_version != FDFORMAT_VERSION)
1411 return EINVAL; /* wrong version of formatting prog */
1412
1413 scratch = form_parms->nbps >> 7;
1414 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1415 scratch & ~(1 << (ffs(scratch)-1)))
1416 /* not a power-of-two multiple of 128 */
1417 return EINVAL;
1418
1419 switch (form_parms->xfer_rate) {
1420 case 500 * 1024:
1421 fd->sc_type->rate = FDC_500KBPS;
1422 break;
1423 case 300 * 1024:
1424 fd->sc_type->rate = FDC_300KBPS;
1425 break;
1426 case 250 * 1024:
1427 fd->sc_type->rate = FDC_250KBPS;
1428 break;
1429 default:
1430 return EINVAL;
1431 }
1432
1433 if (form_parms->nspt > FD_MAX_NSEC ||
1434 form_parms->fillbyte > 0xff ||
1435 form_parms->interleave > 0xff)
1436 return EINVAL;
1437 fd->sc_type->sectrac = form_parms->nspt;
1438 if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1439 return EINVAL;
1440 fd->sc_type->heads = form_parms->ntrk;
1441 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1442 fd->sc_type->secsize = ffs(scratch)-1;
1443 fd->sc_type->gap2 = form_parms->gaplen;
1444 fd->sc_type->cyls = form_parms->ncyl;
1445 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1446 form_parms->nbps / DEV_BSIZE;
1447 fd->sc_type->step = form_parms->stepspercyl;
1448 fd->sc_type->fillbyte = form_parms->fillbyte;
1449 fd->sc_type->interleave = form_parms->interleave;
1450 return 0;
1451
1452 case FDIOCFORMAT_TRACK:
1453 if((flag & FWRITE) == 0)
1454 return EBADF; /* must be opened for writing */
1455 form_cmd = (struct fdformat_cmd *)addr;
1456 if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1457 return EINVAL; /* wrong version of formatting prog */
1458
1459 if (form_cmd->head >= fd->sc_type->heads ||
1460 form_cmd->cylinder >= fd->sc_type->cyls) {
1461 return EINVAL;
1462 }
1463
1464 fd_formb = malloc(sizeof(struct ne7_fd_formb),
1465 M_TEMP, M_NOWAIT);
1466 if(fd_formb == 0)
1467 return ENOMEM;
1468
1469
1470 fd_formb->head = form_cmd->head;
1471 fd_formb->cyl = form_cmd->cylinder;
1472 fd_formb->transfer_rate = fd->sc_type->rate;
1473 fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1474 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1475 fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1476 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1477
1478 memset(il, 0, sizeof il);
1479 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1480 while (il[(j%fd_formb->fd_formb_nsecs)+1])
1481 j++;
1482 il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1483 j += fd->sc_type->interleave;
1484 }
1485 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1486 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1487 fd_formb->fd_formb_headno(i) = form_cmd->head;
1488 fd_formb->fd_formb_secno(i) = il[i+1];
1489 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1490 }
1491
1492 error = fdformat(dev, fd_formb, p);
1493 free(fd_formb, M_TEMP);
1494 return error;
1495
1496 case FDIOCGETOPTS: /* get drive options */
1497 *(int *)addr = fd->sc_opts;
1498 return 0;
1499
1500 case FDIOCSETOPTS: /* set drive options */
1501 fd->sc_opts = *(int *)addr;
1502 return 0;
1503
1504 default:
1505 return ENOTTY;
1506 }
1507
1508 #ifdef DIAGNOSTIC
1509 panic("fdioctl: impossible");
1510 #endif
1511 }
1512
1513 int
1514 fdformat(dev, finfo, p)
1515 dev_t dev;
1516 struct ne7_fd_formb *finfo;
1517 struct proc *p;
1518 {
1519 int rv = 0, s;
1520 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1521 struct fd_type *type = fd->sc_type;
1522 struct buf *bp;
1523
1524 /* set up a buffer header for fdstrategy() */
1525 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1526 if(bp == 0)
1527 return ENOBUFS;
1528 memset((void *)bp, 0, sizeof(struct buf));
1529 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1530 bp->b_proc = p;
1531 bp->b_dev = dev;
1532
1533 /*
1534 * calculate a fake blkno, so fdstrategy() would initiate a
1535 * seek to the requested cylinder
1536 */
1537 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1538 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1539
1540 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1541 bp->b_data = (caddr_t)finfo;
1542
1543 #ifdef DEBUG
1544 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
1545 #endif
1546
1547 /* now do the format */
1548 fdstrategy(bp);
1549
1550 /* ...and wait for it to complete */
1551 s = splbio();
1552 while(!(bp->b_flags & B_DONE)) {
1553 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1554 if (rv == EWOULDBLOCK)
1555 break;
1556 }
1557 splx(s);
1558
1559 if (rv == EWOULDBLOCK) {
1560 /* timed out */
1561 rv = EIO;
1562 biodone(bp);
1563 }
1564 if(bp->b_flags & B_ERROR) {
1565 rv = bp->b_error;
1566 }
1567 free(bp, M_TEMP);
1568 return rv;
1569 }
1570
1571 #include "md.h"
1572 #if NMD > 0
1573
1574 #include <dev/md.h>
1575
1576 int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev));
1577
1578 int
1579 load_memory_disc_from_floppy(md, dev)
1580 struct md_conf *md;
1581 dev_t dev;
1582 {
1583 struct buf *bp;
1584 int loop;
1585 int s;
1586 int type;
1587 int floppysize;
1588
1589 if (major(dev) != 17) /* XXX - nice if the major was defined elsewhere */
1590 return(EINVAL);
1591
1592 if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
1593 return(EBUSY);
1594
1595 type = FDTYPE(dev) - 1;
1596 if (type < 0) type = 0;
1597 floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
1598
1599 if (md->md_size < floppysize) {
1600 printf("Memory disc is not big enough for floppy image\n");
1601 return(EINVAL);
1602 }
1603
1604 /* We have the memory disk ! */
1605
1606 printf("Loading memory disc : %4dK ", 0);
1607
1608 /* obtain a buffer */
1609
1610 bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
1611
1612 /* request no partition relocation by driver on I/O operations */
1613
1614 bp->b_dev = dev;
1615
1616 s = spl0();
1617
1618 if (fdopen(bp->b_dev, 0, 0, curproc) != 0) {
1619 brelse(bp);
1620 printf("Cannot open floppy device\n");
1621 return(EINVAL);
1622 }
1623
1624 for (loop = 0;
1625 loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
1626 ++loop) {
1627 printf("\x08\x08\x08\x08\x08\x08%4dK ",
1628 loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1629 bp->b_blkno = loop * fd_types[type].sectrac;
1630 bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
1631 bp->b_flags |= B_READ;
1632 bp->b_error = 0;
1633 bp->b_resid = 0;
1634 fdstrategy(bp);
1635
1636 if (biowait(bp))
1637 panic("Cannot load floppy image\n");
1638
1639 memcpy((caddr_t)md->md_addr + loop * fd_types[type].sectrac
1640 * DEV_BSIZE, (caddr_t)bp->b_data,
1641 fd_types[type].sectrac * DEV_BSIZE);
1642 }
1643 printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1644 loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1645
1646 fdclose(bp->b_dev, 0, 0, curproc);
1647
1648 brelse(bp);
1649
1650 splx(s);
1651 return(0);
1652 }
1653
1654 #endif
1655