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