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