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