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