fd.c revision 1.81 1 /* $NetBSD: fd.c,v 1.81 2008/06/13 13:57:58 cegger 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 and Minoura Makoto.
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 */
65
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.81 2008/06/13 13:57:58 cegger Exp $");
68
69 #include "rnd.h"
70 #include "opt_ddb.h"
71 #include "opt_m680x0.h"
72
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/callout.h>
76 #include <sys/kernel.h>
77 #include <sys/conf.h>
78 #include <sys/file.h>
79 #include <sys/stat.h>
80 #include <sys/ioctl.h>
81 #include <sys/malloc.h>
82 #include <sys/device.h>
83 #include <sys/disklabel.h>
84 #include <sys/disk.h>
85 #include <sys/buf.h>
86 #include <sys/bufq.h>
87 #include <sys/uio.h>
88 #include <sys/syslog.h>
89 #include <sys/queue.h>
90 #include <sys/fdio.h>
91 #if NRND > 0
92 #include <sys/rnd.h>
93 #endif
94
95 #include <uvm/uvm_extern.h>
96
97 #include <machine/bus.h>
98 #include <machine/cpu.h>
99
100 #include <arch/x68k/dev/intiovar.h>
101 #include <arch/x68k/dev/dmacvar.h>
102 #include <arch/x68k/dev/fdreg.h>
103 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
104
105 #include "locators.h"
106
107 #ifdef FDDEBUG
108 #define DPRINTF(x) if (fddebug) printf x
109 int fddebug = 0;
110 #else
111 #define DPRINTF(x)
112 #endif
113
114 #define FDUNIT(dev) (minor(dev) / 8)
115 #define FDTYPE(dev) (minor(dev) % 8)
116
117 enum fdc_state {
118 DEVIDLE = 0,
119 MOTORWAIT,
120 DOSEEK,
121 SEEKWAIT,
122 SEEKTIMEDOUT,
123 SEEKCOMPLETE,
124 DOIO,
125 IOCOMPLETE,
126 IOTIMEDOUT,
127 DORESET,
128 RESETCOMPLETE,
129 RESETTIMEDOUT,
130 DORECAL,
131 RECALWAIT,
132 RECALTIMEDOUT,
133 RECALCOMPLETE,
134 DOCOPY,
135 DOIOHALF,
136 COPYCOMPLETE,
137 };
138
139 /* software state, per controller */
140 struct fdc_softc {
141 struct device sc_dev; /* boilerplate */
142
143 bus_space_tag_t sc_iot; /* intio i/o space identifier */
144 bus_space_handle_t sc_ioh; /* intio io handle */
145
146 struct callout sc_timo_ch; /* timeout callout */
147 struct callout sc_intr_ch; /* pseudo-intr callout */
148
149 bus_dma_tag_t sc_dmat; /* intio DMA tag */
150 bus_dmamap_t sc_dmamap; /* DMA map */
151 u_int8_t *sc_addr; /* physical address */
152 struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
153 struct dmac_dma_xfer *sc_xfer; /* DMA transfer */
154
155 struct fd_softc *sc_fd[4]; /* pointers to children */
156 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
157 enum fdc_state sc_state;
158 int sc_errors; /* number of retries so far */
159 u_char sc_status[7]; /* copy of registers */
160 } fdc_softc;
161
162 int fdcintr(void *);
163 void fdcreset(struct fdc_softc *);
164
165 /* controller driver configuration */
166 int fdcprobe(struct device *, struct cfdata *, void *);
167 void fdcattach(struct device *, struct device *, void *);
168 int fdprint(void *, const char *);
169
170 CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
171 fdcprobe, fdcattach, NULL, NULL);
172
173 extern struct cfdriver fdc_cd;
174
175 /*
176 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
177 * we tell them apart.
178 */
179 struct fd_type {
180 int sectrac; /* sectors per track */
181 int heads; /* number of heads */
182 int seccyl; /* sectors per cylinder */
183 int secsize; /* size code for sectors */
184 int datalen; /* data len when secsize = 0 */
185 int steprate; /* step rate and head unload time */
186 int gap1; /* gap len between sectors */
187 int gap2; /* formatting gap */
188 int cyls; /* total num of cylinders */
189 int size; /* size of disk in sectors */
190 int step; /* steps per cylinder */
191 int rate; /* transfer speed code */
192 const char *name;
193 };
194
195 /* The order of entries in the following table is important -- BEWARE! */
196 struct fd_type fd_types[] = {
197 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
198 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
199 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
200 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
201 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
202 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
203 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
204 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
205 };
206
207 /* software state, per disk (with up to 4 disks per ctlr) */
208 struct fd_softc {
209 struct device sc_dev;
210 struct disk sc_dk;
211
212 struct fd_type *sc_deftype; /* default type descriptor */
213 struct fd_type *sc_type; /* current type descriptor */
214
215 struct callout sc_motoron_ch;
216 struct callout sc_motoroff_ch;
217
218 daddr_t sc_blkno; /* starting block number */
219 int sc_bcount; /* byte count left */
220 int sc_opts; /* user-set options */
221 int sc_skip; /* bytes already transferred */
222 int sc_nblks; /* number of blocks currently transferring */
223 int sc_nbytes; /* number of bytes currently transferring */
224
225 int sc_drive; /* physical unit number */
226 int sc_flags;
227 #define FD_BOPEN 0x01 /* it's open */
228 #define FD_COPEN 0x02 /* it's open */
229 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
230 #define FD_MOTOR 0x04 /* motor should be on */
231 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
232 #define FD_ALIVE 0x10 /* alive */
233 int sc_cylin; /* where we think the head is */
234
235 TAILQ_ENTRY(fd_softc) sc_drivechain;
236 int sc_ops; /* I/O ops since last switch */
237 struct bufq_state *sc_q;/* pending I/O requests */
238 int sc_active; /* number of active I/O operations */
239 u_char *sc_copybuf; /* for secsize >=3 */
240 u_char sc_part; /* for secsize >=3 */
241 #define SEC_P10 0x02 /* first part */
242 #define SEC_P01 0x01 /* second part */
243 #define SEC_P11 0x03 /* both part */
244
245 #if NRND > 0
246 rndsource_element_t rnd_source;
247 #endif
248 };
249
250 /* floppy driver configuration */
251 int fdprobe(struct device *, struct cfdata *, void *);
252 void fdattach(struct device *, struct device *, void *);
253
254 CFATTACH_DECL(fd, sizeof(struct fd_softc),
255 fdprobe, fdattach, NULL, NULL);
256
257 extern struct cfdriver fd_cd;
258
259 dev_type_open(fdopen);
260 dev_type_close(fdclose);
261 dev_type_read(fdread);
262 dev_type_write(fdwrite);
263 dev_type_ioctl(fdioctl);
264 dev_type_strategy(fdstrategy);
265
266 const struct bdevsw fd_bdevsw = {
267 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
268 };
269
270 const struct cdevsw fd_cdevsw = {
271 fdopen, fdclose, fdread, fdwrite, fdioctl,
272 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
273 };
274
275 void fdstart(struct fd_softc *);
276
277 struct dkdriver fddkdriver = { fdstrategy };
278
279 void fd_set_motor(struct fdc_softc *, int);
280 void fd_motor_off(void *);
281 void fd_motor_on(void *);
282 int fdcresult(struct fdc_softc *);
283 int out_fdc(bus_space_tag_t, bus_space_handle_t, u_char);
284 void fdcstart(struct fdc_softc *);
285 void fdcstatus(struct device *, int, const char *);
286 void fdctimeout(void *);
287 void fdcpseudointr(void *);
288 void fdcretry(struct fdc_softc *);
289 void fdfinish(struct fd_softc *, struct buf *);
290 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
291 static int fdcpoll(struct fdc_softc *);
292 static int fdgetdisklabel(struct fd_softc *, dev_t);
293 static void fd_do_eject(struct fdc_softc *, int);
294
295 void fd_mountroot_hook(struct device *);
296
297 /* DMA transfer routines */
298 inline static void fdc_dmastart(struct fdc_softc *, int, void *, vsize_t);
299 static int fdcdmaintr(void *);
300 static int fdcdmaerrintr(void *);
301
302 inline static void
303 fdc_dmastart(struct fdc_softc *fdc, int read, void *addr, vsize_t count)
304 {
305 int error;
306
307 DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
308 read ? "read" : "write", (void *) addr, count));
309
310 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
311 0, BUS_DMA_NOWAIT);
312 if (error) {
313 panic ("fdc_dmastart: cannot load dmamap");
314 }
315
316 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
317 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
318
319 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
320 fdc->sc_dmamap,
321 (read?
322 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
323 (DMAC_SCR_MAC_COUNT_UP|
324 DMAC_SCR_DAC_NO_COUNT),
325 (u_int8_t*) (fdc->sc_addr +
326 fddata)); /* XXX */
327
328 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
329 }
330
331 static int
332 fdcdmaintr(void *arg)
333 {
334 struct fdc_softc *fdc = arg;
335
336 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
337
338 return 0;
339 }
340
341 static int
342 fdcdmaerrintr(void *dummy)
343 {
344 DPRINTF(("fdcdmaerrintr\n"));
345
346 return 0;
347 }
348
349 /* ARGSUSED */
350 int
351 fdcprobe(struct device *parent, struct cfdata *cf, void *aux)
352 {
353 struct intio_attach_args *ia = aux;
354
355 if (strcmp(ia->ia_name, "fdc") != 0)
356 return 0;
357
358 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
359 ia->ia_addr = FDC_ADDR;
360 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
361 ia->ia_intr = FDC_INTR;
362 if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
363 ia->ia_dma = FDC_DMA;
364 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
365 ia->ia_dmaintr = FDC_DMAINTR;
366
367 if ((ia->ia_intr & 0x03) != 0)
368 return 0;
369
370 ia->ia_size = 0x2000;
371 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
372 return 0;
373
374 /* builtin device; always there */
375 return 1;
376 }
377
378 /*
379 * Arguments passed between fdcattach and fdprobe.
380 */
381 struct fdc_attach_args {
382 int fa_drive;
383 struct fd_type *fa_deftype;
384 };
385
386 /*
387 * Print the location of a disk drive (called just before attaching the
388 * the drive). If `fdc' is not NULL, the drive was found but was not
389 * in the system config file; print the drive name as well.
390 * Return QUIET (config_find ignores this if the device was configured) to
391 * avoid printing `fdN not configured' messages.
392 */
393 int
394 fdprint(void *aux, const char *fdc)
395 {
396 struct fdc_attach_args *fa = aux;
397
398 if (!fdc)
399 aprint_normal(" drive %d", fa->fa_drive);
400 return QUIET;
401 }
402
403 void
404 fdcattach(struct device *parent, struct device *self, void *aux)
405 {
406 struct fdc_softc *fdc = (void *)self;
407 bus_space_tag_t iot;
408 bus_space_handle_t ioh;
409 struct intio_attach_args *ia = aux;
410 struct fdc_attach_args fa;
411
412 iot = ia->ia_bst;
413
414 printf("\n");
415
416 callout_init(&fdc->sc_timo_ch, 0);
417 callout_init(&fdc->sc_intr_ch, 0);
418
419 /* Re-map the I/O space. */
420 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
421
422 fdc->sc_iot = iot;
423 fdc->sc_ioh = ioh;
424 fdc->sc_addr = (void *)ia->ia_addr;
425
426 fdc->sc_dmat = ia->ia_dmat;
427 fdc->sc_state = DEVIDLE;
428 TAILQ_INIT(&fdc->sc_drives);
429
430 /* Initialize DMAC channel */
431 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
432 ia->ia_dmaintr, fdcdmaintr, fdc,
433 ia->ia_dmaintr+1, fdcdmaerrintr,
434 fdc);
435 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
436 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
437 &fdc->sc_dmamap)) {
438 printf("%s: can't set up intio DMA map\n",
439 fdc->sc_dev.dv_xname);
440 return;
441 }
442
443 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
444 panic ("Could not establish interrupt (duplicated vector?).");
445 intio_set_ivec(ia->ia_intr);
446
447 /* reset */
448 intio_disable_intr(SICILIAN_INTR_FDD);
449 intio_enable_intr(SICILIAN_INTR_FDC);
450 fdcresult(fdc);
451 fdcreset(fdc);
452
453 printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
454 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
455 out_fdc(iot, ioh, 0xd0);
456 out_fdc(iot, ioh, 0x10);
457
458 /* physical limit: four drives per controller. */
459 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
460 (void)config_found(self, (void *)&fa, fdprint);
461 }
462
463 intio_enable_intr(SICILIAN_INTR_FDC);
464 }
465
466 void
467 fdcreset(struct fdc_softc *fdc)
468 {
469 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
470 }
471
472 static int
473 fdcpoll(struct fdc_softc *fdc)
474 {
475 int i = 25000, n;
476 while (--i > 0) {
477 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
478 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
479 n = fdcresult(fdc);
480 break;
481 }
482 DELAY(100);
483 }
484 return i;
485 }
486
487 int
488 fdprobe(struct device *parent, struct cfdata *cf, void *aux)
489 {
490 struct fdc_softc *fdc = (void *)parent;
491 struct fd_type *type;
492 struct fdc_attach_args *fa = aux;
493 int drive = fa->fa_drive;
494 bus_space_tag_t iot = fdc->sc_iot;
495 bus_space_handle_t ioh = fdc->sc_ioh;
496 int n = 0;
497 int found = 0;
498 int i;
499
500 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
501 cf->cf_loc[FDCCF_UNIT] != drive)
502 return 0;
503
504 type = &fd_types[0]; /* XXX 1.2MB */
505
506 intio_disable_intr(SICILIAN_INTR_FDC);
507
508 /* select drive and turn on motor */
509 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
510 fdc_force_ready(FDCRDY);
511 fdcpoll(fdc);
512
513 retry:
514 out_fdc(iot, ioh, NE7CMD_RECAL);
515 out_fdc(iot, ioh, drive);
516
517 i = 25000;
518 while (--i > 0) {
519 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
520 out_fdc(iot, ioh, NE7CMD_SENSEI);
521 n = fdcresult(fdc);
522 break;
523 }
524 DELAY(100);
525 }
526
527 #ifdef FDDEBUG
528 {
529 int _i;
530 DPRINTF(("fdprobe: status"));
531 for (_i = 0; _i < n; _i++)
532 DPRINTF((" %x", fdc->sc_status[_i]));
533 DPRINTF(("\n"));
534 }
535 #endif
536
537 if (n == 2) {
538 if ((fdc->sc_status[0] & 0xf0) == 0x20)
539 found = 1;
540 else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
541 goto retry;
542 }
543
544 /* turn off motor */
545 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
546 fdctl, (type->rate << 4)| drive);
547 fdc_force_ready(FDCSTBY);
548 if (!found) {
549 intio_enable_intr(SICILIAN_INTR_FDC);
550 return 0;
551 }
552
553 return 1;
554 }
555
556 /*
557 * Controller is working, and drive responded. Attach it.
558 */
559 void
560 fdattach(struct device *parent, struct device *self, void *aux)
561 {
562 struct fdc_softc *fdc = (void *)parent;
563 struct fd_softc *fd = (void *)self;
564 struct fdc_attach_args *fa = aux;
565 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
566 int drive = fa->fa_drive;
567
568 callout_init(&fd->sc_motoron_ch, 0);
569 callout_init(&fd->sc_motoroff_ch, 0);
570
571 fd->sc_flags = 0;
572
573 if (type)
574 printf(": %s, %d cyl, %d head, %d sec\n", type->name,
575 type->cyls, type->heads, type->sectrac);
576 else
577 printf(": density unknown\n");
578
579 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
580 fd->sc_cylin = -1;
581 fd->sc_drive = drive;
582 fd->sc_deftype = type;
583 fdc->sc_fd[drive] = fd;
584
585 fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
586 if (fd->sc_copybuf == 0)
587 printf("fdprobe: WARNING!! malloc() failed.\n");
588 fd->sc_flags |= FD_ALIVE;
589
590 /*
591 * Initialize and attach the disk structure.
592 */
593 disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &fddkdriver);
594 disk_attach(&fd->sc_dk);
595
596 /*
597 * Establish a mountroot_hook anyway in case we booted
598 * with RB_ASKNAME and get selected as the boot device.
599 */
600 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
601
602 #if NRND > 0
603 rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
604 RND_TYPE_DISK, 0);
605 #endif
606 }
607
608 inline struct fd_type *
609 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
610 {
611 int type = FDTYPE(dev);
612
613 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
614 return NULL;
615 return &fd_types[type];
616 }
617
618 void
619 fdstrategy(struct buf *bp)
620 {
621 struct fd_softc *fd;
622 int unit = FDUNIT(bp->b_dev);
623 int sz;
624 int s;
625
626 fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev));
627 if (fd == NULL) {
628 bp->b_error = EINVAL;
629 goto done;
630 }
631
632 if (bp->b_blkno < 0 ||
633 (bp->b_bcount % FDC_BSIZE) != 0) {
634 DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
635 "bcount=%d\n", unit,
636 bp->b_blkno, bp->b_bcount));
637 bp->b_error = EINVAL;
638 goto done;
639 }
640
641 /* If it's a null transfer, return immediately. */
642 if (bp->b_bcount == 0)
643 goto done;
644
645 sz = howmany(bp->b_bcount, FDC_BSIZE);
646
647 if (bp->b_blkno + sz >
648 (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
649 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
650 - bp->b_blkno;
651 if (sz == 0) {
652 /* If exactly at end of disk, return EOF. */
653 bp->b_resid = bp->b_bcount;
654 goto done;
655 }
656 if (sz < 0) {
657 /* If past end of disk, return EINVAL. */
658 bp->b_error = EINVAL;
659 goto done;
660 }
661 /* Otherwise, truncate request. */
662 bp->b_bcount = sz << DEV_BSHIFT;
663 }
664
665 bp->b_rawblkno = bp->b_blkno;
666 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
667 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
668
669 DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
670 bp->b_flags & B_READ ? "read" : "write",
671 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
672 /* Queue transfer on drive, activate drive and controller if idle. */
673 s = splbio();
674 BUFQ_PUT(fd->sc_q, bp);
675 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
676 if (fd->sc_active == 0)
677 fdstart(fd);
678 #ifdef DIAGNOSTIC
679 else {
680 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
681 if (fdc->sc_state == DEVIDLE) {
682 printf("fdstrategy: controller inactive\n");
683 fdcstart(fdc);
684 }
685 }
686 #endif
687 splx(s);
688 return;
689
690 done:
691 /* Toss transfer; we're done early. */
692 biodone(bp);
693 }
694
695 void
696 fdstart(struct fd_softc *fd)
697 {
698 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
699 int active = fdc->sc_drives.tqh_first != 0;
700
701 /* Link into controller queue. */
702 fd->sc_active = 1;
703 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
704
705 /* If controller not already active, start it. */
706 if (!active)
707 fdcstart(fdc);
708 }
709
710 void
711 fdfinish(struct fd_softc *fd, struct buf *bp)
712 {
713 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
714
715 /*
716 * Move this drive to the end of the queue to give others a `fair'
717 * chance. We only force a switch if N operations are completed while
718 * another drive is waiting to be serviced, since there is a long motor
719 * startup delay whenever we switch.
720 */
721 (void)BUFQ_GET(fd->sc_q);
722 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
723 fd->sc_ops = 0;
724 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
725 if (BUFQ_PEEK(fd->sc_q) != NULL) {
726 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
727 } else
728 fd->sc_active = 0;
729 }
730 bp->b_resid = fd->sc_bcount;
731 fd->sc_skip = 0;
732
733 #if NRND > 0
734 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
735 #endif
736
737 biodone(bp);
738 /* turn off motor 5s from now */
739 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
740 fdc->sc_state = DEVIDLE;
741 }
742
743 int
744 fdread(dev_t dev, struct uio *uio, int flags)
745 {
746
747 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
748 }
749
750 int
751 fdwrite(dev_t dev, struct uio *uio, int flags)
752 {
753
754 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
755 }
756
757 void
758 fd_set_motor(struct fdc_softc *fdc, int reset)
759 {
760 struct fd_softc *fd;
761 int n;
762
763 DPRINTF(("fd_set_motor:\n"));
764 for (n = 0; n < 4; n++)
765 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
766 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
767 0x80 | (fd->sc_type->rate << 4)| n);
768 }
769 }
770
771 void
772 fd_motor_off(void *arg)
773 {
774 struct fd_softc *fd = arg;
775 struct fdc_softc *fdc = (struct fdc_softc*) device_parent(&fd->sc_dev);
776 int s;
777
778 DPRINTF(("fd_motor_off:\n"));
779
780 s = splbio();
781 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
782 bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
783 (fd->sc_type->rate << 4) | fd->sc_drive);
784 #if 0
785 fd_set_motor(fdc, 0); /* XXX */
786 #endif
787 splx(s);
788 }
789
790 void
791 fd_motor_on(void *arg)
792 {
793 struct fd_softc *fd = arg;
794 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
795 int s;
796
797 DPRINTF(("fd_motor_on:\n"));
798
799 s = splbio();
800 fd->sc_flags &= ~FD_MOTOR_WAIT;
801 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
802 (void) fdcintr(fdc);
803 splx(s);
804 }
805
806 int
807 fdcresult(struct fdc_softc *fdc)
808 {
809 bus_space_tag_t iot = fdc->sc_iot;
810 bus_space_handle_t ioh = fdc->sc_ioh;
811 u_char i;
812 int j = 100000,
813 n = 0;
814
815 for (; j; j--) {
816 i = bus_space_read_1(iot, ioh, fdsts) &
817 (NE7_DIO | NE7_RQM | NE7_CB);
818
819 if (i == NE7_RQM)
820 return n;
821 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
822 if (n >= sizeof(fdc->sc_status)) {
823 log(LOG_ERR, "fdcresult: overrun\n");
824 return -1;
825 }
826 fdc->sc_status[n++] =
827 bus_space_read_1(iot, ioh, fddata);
828 }
829 delay(10);
830 }
831 log(LOG_ERR, "fdcresult: timeout\n");
832 return -1;
833 }
834
835 int
836 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
837 {
838 int i = 100000;
839
840 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
841 if (i <= 0)
842 return -1;
843 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
844 if (i <= 0)
845 return -1;
846 bus_space_write_1(iot, ioh, fddata, x);
847 return 0;
848 }
849
850 int
851 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
852 {
853 struct fd_softc *fd;
854 struct fd_type *type;
855 struct fdc_softc *fdc;
856
857 fd = device_lookup_private(&fd_cd, FDUNIT(dev));;
858 if (fd == NULL)
859 return ENXIO;
860 type = fd_dev_to_type(fd, dev);
861 if (type == NULL)
862 return ENXIO;
863
864 if ((fd->sc_flags & FD_OPEN) != 0 &&
865 fd->sc_type != type)
866 return EBUSY;
867
868 fdc = device_private(device_parent(&fd->sc_dev));
869 if ((fd->sc_flags & FD_OPEN) == 0) {
870 /* Lock eject button */
871 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
872 0x40 | ( 1 << unit));
873 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
874 }
875
876 fd->sc_type = type;
877 fd->sc_cylin = -1;
878
879 switch (mode) {
880 case S_IFCHR:
881 fd->sc_flags |= FD_COPEN;
882 break;
883 case S_IFBLK:
884 fd->sc_flags |= FD_BOPEN;
885 break;
886 }
887
888 fdgetdisklabel(fd, dev);
889
890 return 0;
891 }
892
893 int
894 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
895 {
896 int unit = FDUNIT(dev);
897 struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
898 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
899
900 DPRINTF(("fdclose %d\n", unit));
901
902 switch (mode) {
903 case S_IFCHR:
904 fd->sc_flags &= ~FD_COPEN;
905 break;
906 case S_IFBLK:
907 fd->sc_flags &= ~FD_BOPEN;
908 break;
909 }
910
911 if ((fd->sc_flags & FD_OPEN) == 0) {
912 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
913 ( 1 << unit));
914 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
915 }
916 return 0;
917 }
918
919 void
920 fdcstart(struct fdc_softc *fdc)
921 {
922
923 #ifdef DIAGNOSTIC
924 /* only got here if controller's drive queue was inactive; should
925 be in idle state */
926 if (fdc->sc_state != DEVIDLE) {
927 printf("fdcstart: not idle\n");
928 return;
929 }
930 #endif
931 (void) fdcintr(fdc);
932 }
933
934 void
935 fdcstatus(struct device *dv, int n, const char *s)
936 {
937 struct fdc_softc *fdc = (void *)device_parent(dv);
938 char bits[64];
939
940 if (n == 0) {
941 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
942 (void) fdcresult(fdc);
943 n = 2;
944 }
945
946 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
947
948 switch (n) {
949 case 0:
950 printf("\n");
951 break;
952 case 2:
953 printf(" (st0 %s cyl %d)\n",
954 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
955 bits, sizeof(bits)), fdc->sc_status[1]);
956 break;
957 case 7:
958 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
959 NE7_ST0BITS, bits, sizeof(bits)));
960 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
961 NE7_ST1BITS, bits, sizeof(bits)));
962 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
963 NE7_ST2BITS, bits, sizeof(bits)));
964 printf(" cyl %d head %d sec %d)\n",
965 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
966 break;
967 #ifdef DIAGNOSTIC
968 default:
969 printf(" fdcstatus: weird size: %d\n", n);
970 break;
971 #endif
972 }
973 }
974
975 void
976 fdctimeout(void *arg)
977 {
978 struct fdc_softc *fdc = arg;
979 struct fd_softc *fd = fdc->sc_drives.tqh_first;
980 int s;
981
982 s = splbio();
983 fdcstatus(&fd->sc_dev, 0, "timeout");
984
985 if (BUFQ_PEEK(fd->sc_q) != NULL)
986 fdc->sc_state++;
987 else
988 fdc->sc_state = DEVIDLE;
989
990 (void) fdcintr(fdc);
991 splx(s);
992 }
993
994 #if 0
995 void
996 fdcpseudointr(void *arg)
997 {
998 int s;
999 struct fdc_softc *fdc = arg;
1000
1001 /* just ensure it has the right spl */
1002 s = splbio();
1003 (void) fdcintr(fdc);
1004 splx(s);
1005 }
1006 #endif
1007
1008 int
1009 fdcintr(void *arg)
1010 {
1011 struct fdc_softc *fdc = arg;
1012 #define st0 fdc->sc_status[0]
1013 #define cyl fdc->sc_status[1]
1014 struct fd_softc *fd;
1015 struct buf *bp;
1016 bus_space_tag_t iot = fdc->sc_iot;
1017 bus_space_handle_t ioh = fdc->sc_ioh;
1018 int read, head, sec, pos, i, sectrac, nblks;
1019 int tmp;
1020 struct fd_type *type;
1021
1022 loop:
1023 fd = fdc->sc_drives.tqh_first;
1024 if (fd == NULL) {
1025 DPRINTF(("fdcintr: set DEVIDLE\n"));
1026 if (fdc->sc_state == DEVIDLE) {
1027 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1028 out_fdc(iot, ioh, NE7CMD_SENSEI);
1029 if ((tmp = fdcresult(fdc)) != 2 ||
1030 (st0 & 0xf8) != 0x20) {
1031 goto loop;
1032 }
1033 }
1034 }
1035 /* no drives waiting; end */
1036 fdc->sc_state = DEVIDLE;
1037 return 1;
1038 }
1039
1040 /* Is there a transfer to this drive? If not, deactivate drive. */
1041 bp = BUFQ_PEEK(fd->sc_q);
1042 if (bp == NULL) {
1043 fd->sc_ops = 0;
1044 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1045 fd->sc_active = 0;
1046 goto loop;
1047 }
1048
1049 switch (fdc->sc_state) {
1050 case DEVIDLE:
1051 DPRINTF(("fdcintr: in DEVIDLE\n"));
1052 fdc->sc_errors = 0;
1053 fd->sc_skip = 0;
1054 fd->sc_bcount = bp->b_bcount;
1055 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1056 callout_stop(&fd->sc_motoroff_ch);
1057 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1058 fdc->sc_state = MOTORWAIT;
1059 return 1;
1060 }
1061 if ((fd->sc_flags & FD_MOTOR) == 0) {
1062 /* Turn on the motor */
1063 /* being careful about other drives. */
1064 for (i = 0; i < 4; i++) {
1065 struct fd_softc *ofd = fdc->sc_fd[i];
1066 if (ofd && ofd->sc_flags & FD_MOTOR) {
1067 callout_stop(&ofd->sc_motoroff_ch);
1068 ofd->sc_flags &=
1069 ~(FD_MOTOR | FD_MOTOR_WAIT);
1070 break;
1071 }
1072 }
1073 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1074 fd_set_motor(fdc, 0);
1075 fdc->sc_state = MOTORWAIT;
1076 /* allow .5s for motor to stabilize */
1077 callout_reset(&fd->sc_motoron_ch, hz / 2,
1078 fd_motor_on, fd);
1079 return 1;
1080 }
1081 /* Make sure the right drive is selected. */
1082 fd_set_motor(fdc, 0);
1083
1084 /* fall through */
1085 case DOSEEK:
1086 doseek:
1087 DPRINTF(("fdcintr: in DOSEEK\n"));
1088 if (fd->sc_cylin == bp->b_cylinder)
1089 goto doio;
1090
1091 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1092 out_fdc(iot, ioh, 0xd0); /* XXX const */
1093 out_fdc(iot, ioh, 0x10);
1094
1095 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1096 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1097 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1098
1099 fd->sc_cylin = -1;
1100 fdc->sc_state = SEEKWAIT;
1101
1102 iostat_seek(fd->sc_dk.dk_stats);
1103 disk_busy(&fd->sc_dk);
1104
1105 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1106 return 1;
1107
1108 case DOIO:
1109 doio:
1110 DPRINTF(("fdcintr: DOIO: "));
1111 type = fd->sc_type;
1112 sectrac = type->sectrac;
1113 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1114 sec = pos / (1 << (type->secsize - 2));
1115 if (type->secsize == 2) {
1116 fd->sc_part = SEC_P11;
1117 nblks = (sectrac - sec) << (type->secsize - 2);
1118 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1119 DPRINTF(("nblks(0)"));
1120 } else if ((fd->sc_blkno % 2) == 0) {
1121 if (fd->sc_bcount & 0x00000200) {
1122 if (fd->sc_bcount == FDC_BSIZE) {
1123 fd->sc_part = SEC_P10;
1124 nblks = 1;
1125 DPRINTF(("nblks(1)"));
1126 } else {
1127 fd->sc_part = SEC_P11;
1128 nblks = (sectrac - sec) * 2;
1129 nblks = min(nblks, fd->sc_bcount
1130 / FDC_BSIZE - 1);
1131 DPRINTF(("nblks(2)"));
1132 }
1133 } else {
1134 fd->sc_part = SEC_P11;
1135 nblks = (sectrac - sec)
1136 << (type->secsize - 2);
1137 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1138 DPRINTF(("nblks(3)"));
1139 }
1140 } else {
1141 fd->sc_part = SEC_P01;
1142 nblks = 1;
1143 DPRINTF(("nblks(4)"));
1144 }
1145 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1146 DPRINTF((" %d\n", nblks));
1147 fd->sc_nblks = nblks;
1148 fd->sc_nbytes = nblks * FDC_BSIZE;
1149 head = (fd->sc_blkno
1150 % (type->seccyl * (1 << (type->secsize - 2))))
1151 / (type->sectrac * (1 << (type->secsize - 2)));
1152
1153 #ifdef DIAGNOSTIC
1154 {int block;
1155 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1156 + sec) * (1 << (type->secsize - 2));
1157 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1158 if (block != fd->sc_blkno) {
1159 printf("C H R N: %d %d %d %d\n",
1160 fd->sc_cylin, head, sec, type->secsize);
1161 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
1162 block, fd->sc_blkno);
1163 #ifdef DDB
1164 Debugger();
1165 #endif
1166 }
1167 }
1168 #endif
1169 read = bp->b_flags & B_READ;
1170 DPRINTF(("fdcintr: %s drive %d track %d "
1171 "head %d sec %d nblks %d, skip %d\n",
1172 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1173 head, sec, nblks, fd->sc_skip));
1174 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1175 type->secsize));
1176
1177 if (fd->sc_part != SEC_P11)
1178 goto docopy;
1179
1180 fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
1181 fd->sc_nbytes);
1182 if (read)
1183 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1184 else
1185 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1186 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1187 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1188 out_fdc(iot, ioh, head);
1189 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1190 out_fdc(iot, ioh, type->secsize); /* sector size */
1191 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1192 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1193 out_fdc(iot, ioh, type->datalen); /* data length */
1194 fdc->sc_state = IOCOMPLETE;
1195
1196 disk_busy(&fd->sc_dk);
1197
1198 /* allow 2 seconds for operation */
1199 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1200 return 1; /* will return later */
1201
1202 case DOCOPY:
1203 docopy:
1204 DPRINTF(("fdcintr: DOCOPY:\n"));
1205 type = fd->sc_type;
1206 head = (fd->sc_blkno
1207 % (type->seccyl * (1 << (type->secsize - 2))))
1208 / (type->sectrac * (1 << (type->secsize - 2)));
1209 pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
1210 sec = pos / (1 << (type->secsize - 2));
1211 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1212 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1213 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1214 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1215 out_fdc(iot, ioh, head);
1216 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1217 out_fdc(iot, ioh, type->secsize); /* sector size */
1218 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1219 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1220 out_fdc(iot, ioh, type->datalen); /* data length */
1221 fdc->sc_state = COPYCOMPLETE;
1222 /* allow 2 seconds for operation */
1223 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1224 return 1; /* will return later */
1225
1226 case DOIOHALF:
1227 doiohalf:
1228 DPRINTF((" DOIOHALF:\n"));
1229
1230 type = fd->sc_type;
1231 sectrac = type->sectrac;
1232 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1233 sec = pos / (1 << (type->secsize - 2));
1234 head = (fd->sc_blkno
1235 % (type->seccyl * (1 << (type->secsize - 2))))
1236 / (type->sectrac * (1 << (type->secsize - 2)));
1237 #ifdef DIAGNOSTIC
1238 {int block;
1239 block = ((fd->sc_cylin * type->heads + head) *
1240 type->sectrac + sec)
1241 * (1 << (type->secsize - 2));
1242 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1243 if (block != fd->sc_blkno) {
1244 printf("fdcintr: block %d != blkno %" PRId64 "\n",
1245 block, fd->sc_blkno);
1246 #ifdef DDB
1247 Debugger();
1248 #endif
1249 }
1250 }
1251 #endif
1252 if ((read = bp->b_flags & B_READ)) {
1253 memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
1254 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1255 FDC_BSIZE);
1256 fdc->sc_state = IOCOMPLETE;
1257 goto iocomplete2;
1258 } else {
1259 memcpy((char *)fd->sc_copybuf
1260 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1261 (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
1262 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1263 }
1264 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1265 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1266 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1267 out_fdc(iot, ioh, head);
1268 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1269 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1270 out_fdc(iot, ioh, sectrac); /* sectors/track */
1271 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1272 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1273 fdc->sc_state = IOCOMPLETE;
1274 /* allow 2 seconds for operation */
1275 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1276 return 1; /* will return later */
1277
1278 case SEEKWAIT:
1279 callout_stop(&fdc->sc_timo_ch);
1280 fdc->sc_state = SEEKCOMPLETE;
1281 /* allow 1/50 second for heads to settle */
1282 #if 0
1283 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1284 #endif
1285 return 1;
1286
1287 case SEEKCOMPLETE:
1288 /* Make sure seek really happened */
1289 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1290 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1291 out_fdc(iot, ioh, NE7CMD_SENSEI);
1292 tmp = fdcresult(fdc);
1293 if ((st0 & 0xf8) == 0xc0) {
1294 DPRINTF(("fdcintr: first seek!\n"));
1295 fdc->sc_state = DORECAL;
1296 goto loop;
1297 } else if (tmp != 2 ||
1298 (st0 & 0xf8) != 0x20 ||
1299 cyl != bp->b_cylinder) {
1300 #ifdef FDDEBUG
1301 fdcstatus(&fd->sc_dev, 2, "seek failed");
1302 #endif
1303 fdcretry(fdc);
1304 goto loop;
1305 }
1306 fd->sc_cylin = bp->b_cylinder;
1307 goto doio;
1308
1309 case IOTIMEDOUT:
1310 #if 0
1311 isa_dmaabort(fdc->sc_drq);
1312 #endif
1313 case SEEKTIMEDOUT:
1314 case RECALTIMEDOUT:
1315 case RESETTIMEDOUT:
1316 fdcretry(fdc);
1317 goto loop;
1318
1319 case IOCOMPLETE: /* IO DONE, post-analyze */
1320 callout_stop(&fdc->sc_timo_ch);
1321 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1322 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1323 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1324 #if 0
1325 isa_dmaabort(fdc->sc_drq);
1326 #endif
1327 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1328 "read failed" : "write failed");
1329 printf("blkno %" PRId64 " nblks %d\n",
1330 fd->sc_blkno, fd->sc_nblks);
1331 fdcretry(fdc);
1332 goto loop;
1333 }
1334 #if 0
1335 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1336 nblks * FDC_BSIZE, fdc->sc_drq);
1337 #endif
1338 iocomplete2:
1339 if (fdc->sc_errors) {
1340 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1341 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1342 printf("\n");
1343 fdc->sc_errors = 0;
1344 }
1345 fd->sc_blkno += fd->sc_nblks;
1346 fd->sc_skip += fd->sc_nbytes;
1347 fd->sc_bcount -= fd->sc_nbytes;
1348 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1349 if (fd->sc_bcount > 0) {
1350 bp->b_cylinder = fd->sc_blkno
1351 / (fd->sc_type->seccyl
1352 * (1 << (fd->sc_type->secsize - 2)));
1353 goto doseek;
1354 }
1355 fdfinish(fd, bp);
1356 goto loop;
1357
1358 case COPYCOMPLETE: /* IO DONE, post-analyze */
1359 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1360 callout_stop(&fdc->sc_timo_ch);
1361 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1362 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1363 #if 0
1364 isa_dmaabort(fdc->sc_drq);
1365 #endif
1366 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1367 "read failed" : "write failed");
1368 printf("blkno %" PRId64 " nblks %d\n",
1369 fd->sc_blkno, fd->sc_nblks);
1370 fdcretry(fdc);
1371 goto loop;
1372 }
1373 goto doiohalf;
1374
1375 case DORESET:
1376 DPRINTF(("fdcintr: in DORESET\n"));
1377 /* try a reset, keep motor on */
1378 fd_set_motor(fdc, 1);
1379 DELAY(100);
1380 fd_set_motor(fdc, 0);
1381 fdc->sc_state = RESETCOMPLETE;
1382 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1383 return 1; /* will return later */
1384
1385 case RESETCOMPLETE:
1386 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1387 callout_stop(&fdc->sc_timo_ch);
1388 /* clear the controller output buffer */
1389 for (i = 0; i < 4; i++) {
1390 out_fdc(iot, ioh, NE7CMD_SENSEI);
1391 (void) fdcresult(fdc);
1392 }
1393
1394 /* fall through */
1395 case DORECAL:
1396 DPRINTF(("fdcintr: in DORECAL\n"));
1397 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1398 out_fdc(iot, ioh, fd->sc_drive);
1399 fdc->sc_state = RECALWAIT;
1400 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1401 return 1; /* will return later */
1402
1403 case RECALWAIT:
1404 DPRINTF(("fdcintr: in RECALWAIT\n"));
1405 callout_stop(&fdc->sc_timo_ch);
1406 fdc->sc_state = RECALCOMPLETE;
1407 /* allow 1/30 second for heads to settle */
1408 #if 0
1409 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1410 #endif
1411 return 1; /* will return later */
1412
1413 case RECALCOMPLETE:
1414 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1415 out_fdc(iot, ioh, NE7CMD_SENSEI);
1416 tmp = fdcresult(fdc);
1417 if ((st0 & 0xf8) == 0xc0) {
1418 DPRINTF(("fdcintr: first seek!\n"));
1419 fdc->sc_state = DORECAL;
1420 goto loop;
1421 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1422 #ifdef FDDEBUG
1423 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1424 #endif
1425 fdcretry(fdc);
1426 goto loop;
1427 }
1428 fd->sc_cylin = 0;
1429 goto doseek;
1430
1431 case MOTORWAIT:
1432 if (fd->sc_flags & FD_MOTOR_WAIT)
1433 return 1; /* time's not up yet */
1434 goto doseek;
1435
1436 default:
1437 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1438 return 1;
1439 }
1440 #ifdef DIAGNOSTIC
1441 panic("fdcintr: impossible");
1442 #endif
1443 #undef st0
1444 #undef cyl
1445 }
1446
1447 void
1448 fdcretry(struct fdc_softc *fdc)
1449 {
1450 struct fd_softc *fd;
1451 struct buf *bp;
1452 char bits[64];
1453
1454 DPRINTF(("fdcretry:\n"));
1455 fd = fdc->sc_drives.tqh_first;
1456 bp = BUFQ_PEEK(fd->sc_q);
1457
1458 switch (fdc->sc_errors) {
1459 case 0:
1460 /* try again */
1461 fdc->sc_state = SEEKCOMPLETE;
1462 break;
1463
1464 case 1: case 2: case 3:
1465 /* didn't work; try recalibrating */
1466 fdc->sc_state = DORECAL;
1467 break;
1468
1469 case 4:
1470 /* still no go; reset the bastard */
1471 fdc->sc_state = DORESET;
1472 break;
1473
1474 default:
1475 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1476 fd->sc_skip, (struct disklabel *)NULL);
1477 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1478 NE7_ST0BITS, bits,
1479 sizeof(bits)));
1480 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1481 NE7_ST1BITS, bits,
1482 sizeof(bits)));
1483 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1484 NE7_ST2BITS, bits,
1485 sizeof(bits)));
1486 printf(" cyl %d head %d sec %d)\n",
1487 fdc->sc_status[3],
1488 fdc->sc_status[4],
1489 fdc->sc_status[5]);
1490
1491 bp->b_error = EIO;
1492 fdfinish(fd, bp);
1493 }
1494 fdc->sc_errors++;
1495 }
1496
1497 int
1498 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1499 {
1500 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1501 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
1502 int part = DISKPART(dev);
1503 struct disklabel buffer;
1504 int error;
1505
1506 DPRINTF(("fdioctl:\n"));
1507 switch (cmd) {
1508 case DIOCGDINFO:
1509 #if 1
1510 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1511 return(0);
1512 #else
1513 memset(&buffer, 0, sizeof(buffer));
1514
1515 buffer.d_secpercyl = fd->sc_type->seccyl;
1516 buffer.d_type = DTYPE_FLOPPY;
1517 buffer.d_secsize = 128 << fd->sc_type->secsize;
1518
1519 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1520 return EINVAL;
1521
1522 *(struct disklabel *)addr = buffer;
1523 return 0;
1524 #endif
1525
1526 case DIOCGPART:
1527 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1528 ((struct partinfo *)addr)->part =
1529 &fd->sc_dk.dk_label->d_partitions[part];
1530 return(0);
1531
1532 case DIOCWLABEL:
1533 if ((flag & FWRITE) == 0)
1534 return EBADF;
1535 /* XXX do something */
1536 return 0;
1537
1538 case DIOCWDINFO:
1539 if ((flag & FWRITE) == 0)
1540 return EBADF;
1541
1542 error = setdisklabel(&buffer, (struct disklabel *)addr,
1543 0, NULL);
1544 if (error)
1545 return error;
1546
1547 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1548 return error;
1549
1550 case DIOCLOCK:
1551 /*
1552 * Nothing to do here, really.
1553 */
1554 return 0; /* XXX */
1555
1556 case DIOCEJECT:
1557 if (*(int *)addr == 0) {
1558 /*
1559 * Don't force eject: check that we are the only
1560 * partition open. If so, unlock it.
1561 */
1562 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1563 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1564 fd->sc_dk.dk_openmask) {
1565 return (EBUSY);
1566 }
1567 }
1568 /* FALLTHROUGH */
1569 case ODIOCEJECT:
1570 fd_do_eject(fdc, FDUNIT(dev));
1571 return 0;
1572
1573 default:
1574 return ENOTTY;
1575 }
1576
1577 #ifdef DIAGNOSTIC
1578 panic("fdioctl: impossible");
1579 #endif
1580 }
1581
1582 void
1583 fd_do_eject(struct fdc_softc *fdc, int unit)
1584 {
1585 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1586 0x20 | ( 1 << unit));
1587 DELAY(1); /* XXX */
1588 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1589 }
1590
1591 /*
1592 * Build disk label. For now we only create a label from what we know
1593 * from 'sc'.
1594 */
1595 static int
1596 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
1597 {
1598 struct disklabel *lp;
1599 int part;
1600
1601 DPRINTF(("fdgetdisklabel()\n"));
1602
1603 part = DISKPART(dev);
1604 lp = sc->sc_dk.dk_label;
1605 memset(lp, 0, sizeof(struct disklabel));
1606
1607 lp->d_secsize = 128 << sc->sc_type->secsize;
1608 lp->d_ntracks = sc->sc_type->heads;
1609 lp->d_nsectors = sc->sc_type->sectrac;
1610 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1611 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1612 lp->d_secperunit = sc->sc_type->size;
1613
1614 lp->d_type = DTYPE_FLOPPY;
1615 lp->d_rpm = 300; /* XXX */
1616 lp->d_interleave = 1; /* FIXME: is this OK? */
1617 lp->d_bbsize = 0;
1618 lp->d_sbsize = 0;
1619 lp->d_npartitions = part + 1;
1620 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1621 lp->d_trkseek = STEP_DELAY; /* XXX */
1622 lp->d_magic = DISKMAGIC;
1623 lp->d_magic2 = DISKMAGIC;
1624 lp->d_checksum = dkcksum(lp);
1625 lp->d_partitions[part].p_size = lp->d_secperunit;
1626 lp->d_partitions[part].p_fstype = FS_UNUSED;
1627 lp->d_partitions[part].p_fsize = 1024;
1628 lp->d_partitions[part].p_frag = 8;
1629
1630 return(0);
1631 }
1632
1633 #include <dev/cons.h>
1634
1635 /*
1636 * Mountroot hook: prompt the user to enter the root file system
1637 * floppy.
1638 */
1639 void
1640 fd_mountroot_hook(struct device *dev)
1641 {
1642 struct fd_softc *fd = (void *)dev;
1643 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
1644 int c;
1645
1646 /* XXX device_unit() abuse */
1647 fd_do_eject(fdc, device_unit(dev));
1648 printf("Insert filesystem floppy and press return.");
1649 for (;;) {
1650 c = cngetc();
1651 if ((c == '\r') || (c == '\n')) {
1652 printf("\n");
1653 break;
1654 }
1655 }
1656 }
1657