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