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