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