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