fd.c revision 1.82 1 /* $NetBSD: fd.c,v 1.82 2008/06/14 13:36:24 isaki 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.82 2008/06/14 13:36:24 isaki 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 sz;
623 int s;
624
625 fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev));
626 if (fd == NULL) {
627 bp->b_error = EINVAL;
628 goto done;
629 }
630
631 if (bp->b_blkno < 0 ||
632 (bp->b_bcount % FDC_BSIZE) != 0) {
633 DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
634 "bcount=%d\n", unit,
635 bp->b_blkno, bp->b_bcount));
636 bp->b_error = EINVAL;
637 goto done;
638 }
639
640 /* If it's a null transfer, return immediately. */
641 if (bp->b_bcount == 0)
642 goto done;
643
644 sz = howmany(bp->b_bcount, FDC_BSIZE);
645
646 if (bp->b_blkno + sz >
647 (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
648 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
649 - bp->b_blkno;
650 if (sz == 0) {
651 /* If exactly at end of disk, return EOF. */
652 bp->b_resid = bp->b_bcount;
653 goto done;
654 }
655 if (sz < 0) {
656 /* If past end of disk, return EINVAL. */
657 bp->b_error = EINVAL;
658 goto done;
659 }
660 /* Otherwise, truncate request. */
661 bp->b_bcount = sz << DEV_BSHIFT;
662 }
663
664 bp->b_rawblkno = bp->b_blkno;
665 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
666 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
667
668 DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
669 bp->b_flags & B_READ ? "read" : "write",
670 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
671 /* Queue transfer on drive, activate drive and controller if idle. */
672 s = splbio();
673 BUFQ_PUT(fd->sc_q, bp);
674 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
675 if (fd->sc_active == 0)
676 fdstart(fd);
677 #ifdef DIAGNOSTIC
678 else {
679 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
680 if (fdc->sc_state == DEVIDLE) {
681 printf("fdstrategy: controller inactive\n");
682 fdcstart(fdc);
683 }
684 }
685 #endif
686 splx(s);
687 return;
688
689 done:
690 /* Toss transfer; we're done early. */
691 biodone(bp);
692 }
693
694 void
695 fdstart(struct fd_softc *fd)
696 {
697 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
698 int active = fdc->sc_drives.tqh_first != 0;
699
700 /* Link into controller queue. */
701 fd->sc_active = 1;
702 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
703
704 /* If controller not already active, start it. */
705 if (!active)
706 fdcstart(fdc);
707 }
708
709 void
710 fdfinish(struct fd_softc *fd, struct buf *bp)
711 {
712 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
713
714 /*
715 * Move this drive to the end of the queue to give others a `fair'
716 * chance. We only force a switch if N operations are completed while
717 * another drive is waiting to be serviced, since there is a long motor
718 * startup delay whenever we switch.
719 */
720 (void)BUFQ_GET(fd->sc_q);
721 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
722 fd->sc_ops = 0;
723 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
724 if (BUFQ_PEEK(fd->sc_q) != NULL) {
725 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
726 } else
727 fd->sc_active = 0;
728 }
729 bp->b_resid = fd->sc_bcount;
730 fd->sc_skip = 0;
731
732 #if NRND > 0
733 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
734 #endif
735
736 biodone(bp);
737 /* turn off motor 5s from now */
738 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
739 fdc->sc_state = DEVIDLE;
740 }
741
742 int
743 fdread(dev_t dev, struct uio *uio, int flags)
744 {
745
746 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
747 }
748
749 int
750 fdwrite(dev_t dev, struct uio *uio, int flags)
751 {
752
753 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
754 }
755
756 void
757 fd_set_motor(struct fdc_softc *fdc, int reset)
758 {
759 struct fd_softc *fd;
760 int n;
761
762 DPRINTF(("fd_set_motor:\n"));
763 for (n = 0; n < 4; n++)
764 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
765 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
766 0x80 | (fd->sc_type->rate << 4)| n);
767 }
768 }
769
770 void
771 fd_motor_off(void *arg)
772 {
773 struct fd_softc *fd = arg;
774 struct fdc_softc *fdc = (struct fdc_softc*) device_parent(&fd->sc_dev);
775 int s;
776
777 DPRINTF(("fd_motor_off:\n"));
778
779 s = splbio();
780 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
781 bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
782 (fd->sc_type->rate << 4) | fd->sc_drive);
783 #if 0
784 fd_set_motor(fdc, 0); /* XXX */
785 #endif
786 splx(s);
787 }
788
789 void
790 fd_motor_on(void *arg)
791 {
792 struct fd_softc *fd = arg;
793 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
794 int s;
795
796 DPRINTF(("fd_motor_on:\n"));
797
798 s = splbio();
799 fd->sc_flags &= ~FD_MOTOR_WAIT;
800 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
801 (void) fdcintr(fdc);
802 splx(s);
803 }
804
805 int
806 fdcresult(struct fdc_softc *fdc)
807 {
808 bus_space_tag_t iot = fdc->sc_iot;
809 bus_space_handle_t ioh = fdc->sc_ioh;
810 u_char i;
811 int j = 100000,
812 n = 0;
813
814 for (; j; j--) {
815 i = bus_space_read_1(iot, ioh, fdsts) &
816 (NE7_DIO | NE7_RQM | NE7_CB);
817
818 if (i == NE7_RQM)
819 return n;
820 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
821 if (n >= sizeof(fdc->sc_status)) {
822 log(LOG_ERR, "fdcresult: overrun\n");
823 return -1;
824 }
825 fdc->sc_status[n++] =
826 bus_space_read_1(iot, ioh, fddata);
827 }
828 delay(10);
829 }
830 log(LOG_ERR, "fdcresult: timeout\n");
831 return -1;
832 }
833
834 int
835 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
836 {
837 int i = 100000;
838
839 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
840 if (i <= 0)
841 return -1;
842 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
843 if (i <= 0)
844 return -1;
845 bus_space_write_1(iot, ioh, fddata, x);
846 return 0;
847 }
848
849 int
850 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
851 {
852 int unit;
853 struct fd_softc *fd;
854 struct fd_type *type;
855 struct fdc_softc *fdc;
856
857 unit = FDUNIT(dev);
858 fd = device_lookup_private(&fd_cd, unit);
859 if (fd == NULL)
860 return ENXIO;
861 type = fd_dev_to_type(fd, dev);
862 if (type == NULL)
863 return ENXIO;
864
865 if ((fd->sc_flags & FD_OPEN) != 0 &&
866 fd->sc_type != type)
867 return EBUSY;
868
869 fdc = device_private(device_parent(&fd->sc_dev));
870 if ((fd->sc_flags & FD_OPEN) == 0) {
871 /* Lock eject button */
872 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
873 0x40 | ( 1 << unit));
874 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
875 }
876
877 fd->sc_type = type;
878 fd->sc_cylin = -1;
879
880 switch (mode) {
881 case S_IFCHR:
882 fd->sc_flags |= FD_COPEN;
883 break;
884 case S_IFBLK:
885 fd->sc_flags |= FD_BOPEN;
886 break;
887 }
888
889 fdgetdisklabel(fd, dev);
890
891 return 0;
892 }
893
894 int
895 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
896 {
897 int unit = FDUNIT(dev);
898 struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
899 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
900
901 DPRINTF(("fdclose %d\n", unit));
902
903 switch (mode) {
904 case S_IFCHR:
905 fd->sc_flags &= ~FD_COPEN;
906 break;
907 case S_IFBLK:
908 fd->sc_flags &= ~FD_BOPEN;
909 break;
910 }
911
912 if ((fd->sc_flags & FD_OPEN) == 0) {
913 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
914 ( 1 << unit));
915 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
916 }
917 return 0;
918 }
919
920 void
921 fdcstart(struct fdc_softc *fdc)
922 {
923
924 #ifdef DIAGNOSTIC
925 /* only got here if controller's drive queue was inactive; should
926 be in idle state */
927 if (fdc->sc_state != DEVIDLE) {
928 printf("fdcstart: not idle\n");
929 return;
930 }
931 #endif
932 (void) fdcintr(fdc);
933 }
934
935 void
936 fdcstatus(struct device *dv, int n, const char *s)
937 {
938 struct fdc_softc *fdc = (void *)device_parent(dv);
939 char bits[64];
940
941 if (n == 0) {
942 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
943 (void) fdcresult(fdc);
944 n = 2;
945 }
946
947 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
948
949 switch (n) {
950 case 0:
951 printf("\n");
952 break;
953 case 2:
954 printf(" (st0 %s cyl %d)\n",
955 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
956 bits, sizeof(bits)), fdc->sc_status[1]);
957 break;
958 case 7:
959 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
960 NE7_ST0BITS, bits, sizeof(bits)));
961 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
962 NE7_ST1BITS, bits, sizeof(bits)));
963 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
964 NE7_ST2BITS, bits, sizeof(bits)));
965 printf(" cyl %d head %d sec %d)\n",
966 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
967 break;
968 #ifdef DIAGNOSTIC
969 default:
970 printf(" fdcstatus: weird size: %d\n", n);
971 break;
972 #endif
973 }
974 }
975
976 void
977 fdctimeout(void *arg)
978 {
979 struct fdc_softc *fdc = arg;
980 struct fd_softc *fd = fdc->sc_drives.tqh_first;
981 int s;
982
983 s = splbio();
984 fdcstatus(&fd->sc_dev, 0, "timeout");
985
986 if (BUFQ_PEEK(fd->sc_q) != NULL)
987 fdc->sc_state++;
988 else
989 fdc->sc_state = DEVIDLE;
990
991 (void) fdcintr(fdc);
992 splx(s);
993 }
994
995 #if 0
996 void
997 fdcpseudointr(void *arg)
998 {
999 int s;
1000 struct fdc_softc *fdc = arg;
1001
1002 /* just ensure it has the right spl */
1003 s = splbio();
1004 (void) fdcintr(fdc);
1005 splx(s);
1006 }
1007 #endif
1008
1009 int
1010 fdcintr(void *arg)
1011 {
1012 struct fdc_softc *fdc = arg;
1013 #define st0 fdc->sc_status[0]
1014 #define cyl fdc->sc_status[1]
1015 struct fd_softc *fd;
1016 struct buf *bp;
1017 bus_space_tag_t iot = fdc->sc_iot;
1018 bus_space_handle_t ioh = fdc->sc_ioh;
1019 int read, head, sec, pos, i, sectrac, nblks;
1020 int tmp;
1021 struct fd_type *type;
1022
1023 loop:
1024 fd = fdc->sc_drives.tqh_first;
1025 if (fd == NULL) {
1026 DPRINTF(("fdcintr: set DEVIDLE\n"));
1027 if (fdc->sc_state == DEVIDLE) {
1028 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1029 out_fdc(iot, ioh, NE7CMD_SENSEI);
1030 if ((tmp = fdcresult(fdc)) != 2 ||
1031 (st0 & 0xf8) != 0x20) {
1032 goto loop;
1033 }
1034 }
1035 }
1036 /* no drives waiting; end */
1037 fdc->sc_state = DEVIDLE;
1038 return 1;
1039 }
1040
1041 /* Is there a transfer to this drive? If not, deactivate drive. */
1042 bp = BUFQ_PEEK(fd->sc_q);
1043 if (bp == NULL) {
1044 fd->sc_ops = 0;
1045 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1046 fd->sc_active = 0;
1047 goto loop;
1048 }
1049
1050 switch (fdc->sc_state) {
1051 case DEVIDLE:
1052 DPRINTF(("fdcintr: in DEVIDLE\n"));
1053 fdc->sc_errors = 0;
1054 fd->sc_skip = 0;
1055 fd->sc_bcount = bp->b_bcount;
1056 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1057 callout_stop(&fd->sc_motoroff_ch);
1058 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1059 fdc->sc_state = MOTORWAIT;
1060 return 1;
1061 }
1062 if ((fd->sc_flags & FD_MOTOR) == 0) {
1063 /* Turn on the motor */
1064 /* being careful about other drives. */
1065 for (i = 0; i < 4; i++) {
1066 struct fd_softc *ofd = fdc->sc_fd[i];
1067 if (ofd && ofd->sc_flags & FD_MOTOR) {
1068 callout_stop(&ofd->sc_motoroff_ch);
1069 ofd->sc_flags &=
1070 ~(FD_MOTOR | FD_MOTOR_WAIT);
1071 break;
1072 }
1073 }
1074 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1075 fd_set_motor(fdc, 0);
1076 fdc->sc_state = MOTORWAIT;
1077 /* allow .5s for motor to stabilize */
1078 callout_reset(&fd->sc_motoron_ch, hz / 2,
1079 fd_motor_on, fd);
1080 return 1;
1081 }
1082 /* Make sure the right drive is selected. */
1083 fd_set_motor(fdc, 0);
1084
1085 /* fall through */
1086 case DOSEEK:
1087 doseek:
1088 DPRINTF(("fdcintr: in DOSEEK\n"));
1089 if (fd->sc_cylin == bp->b_cylinder)
1090 goto doio;
1091
1092 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1093 out_fdc(iot, ioh, 0xd0); /* XXX const */
1094 out_fdc(iot, ioh, 0x10);
1095
1096 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1097 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1098 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1099
1100 fd->sc_cylin = -1;
1101 fdc->sc_state = SEEKWAIT;
1102
1103 iostat_seek(fd->sc_dk.dk_stats);
1104 disk_busy(&fd->sc_dk);
1105
1106 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1107 return 1;
1108
1109 case DOIO:
1110 doio:
1111 DPRINTF(("fdcintr: DOIO: "));
1112 type = fd->sc_type;
1113 sectrac = type->sectrac;
1114 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1115 sec = pos / (1 << (type->secsize - 2));
1116 if (type->secsize == 2) {
1117 fd->sc_part = SEC_P11;
1118 nblks = (sectrac - sec) << (type->secsize - 2);
1119 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1120 DPRINTF(("nblks(0)"));
1121 } else if ((fd->sc_blkno % 2) == 0) {
1122 if (fd->sc_bcount & 0x00000200) {
1123 if (fd->sc_bcount == FDC_BSIZE) {
1124 fd->sc_part = SEC_P10;
1125 nblks = 1;
1126 DPRINTF(("nblks(1)"));
1127 } else {
1128 fd->sc_part = SEC_P11;
1129 nblks = (sectrac - sec) * 2;
1130 nblks = min(nblks, fd->sc_bcount
1131 / FDC_BSIZE - 1);
1132 DPRINTF(("nblks(2)"));
1133 }
1134 } else {
1135 fd->sc_part = SEC_P11;
1136 nblks = (sectrac - sec)
1137 << (type->secsize - 2);
1138 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1139 DPRINTF(("nblks(3)"));
1140 }
1141 } else {
1142 fd->sc_part = SEC_P01;
1143 nblks = 1;
1144 DPRINTF(("nblks(4)"));
1145 }
1146 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1147 DPRINTF((" %d\n", nblks));
1148 fd->sc_nblks = nblks;
1149 fd->sc_nbytes = nblks * FDC_BSIZE;
1150 head = (fd->sc_blkno
1151 % (type->seccyl * (1 << (type->secsize - 2))))
1152 / (type->sectrac * (1 << (type->secsize - 2)));
1153
1154 #ifdef DIAGNOSTIC
1155 {int block;
1156 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1157 + sec) * (1 << (type->secsize - 2));
1158 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1159 if (block != fd->sc_blkno) {
1160 printf("C H R N: %d %d %d %d\n",
1161 fd->sc_cylin, head, sec, type->secsize);
1162 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
1163 block, fd->sc_blkno);
1164 #ifdef DDB
1165 Debugger();
1166 #endif
1167 }
1168 }
1169 #endif
1170 read = bp->b_flags & B_READ;
1171 DPRINTF(("fdcintr: %s drive %d track %d "
1172 "head %d sec %d nblks %d, skip %d\n",
1173 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1174 head, sec, nblks, fd->sc_skip));
1175 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1176 type->secsize));
1177
1178 if (fd->sc_part != SEC_P11)
1179 goto docopy;
1180
1181 fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
1182 fd->sc_nbytes);
1183 if (read)
1184 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1185 else
1186 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1187 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1188 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1189 out_fdc(iot, ioh, head);
1190 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1191 out_fdc(iot, ioh, type->secsize); /* sector size */
1192 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1193 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1194 out_fdc(iot, ioh, type->datalen); /* data length */
1195 fdc->sc_state = IOCOMPLETE;
1196
1197 disk_busy(&fd->sc_dk);
1198
1199 /* allow 2 seconds for operation */
1200 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1201 return 1; /* will return later */
1202
1203 case DOCOPY:
1204 docopy:
1205 DPRINTF(("fdcintr: DOCOPY:\n"));
1206 type = fd->sc_type;
1207 head = (fd->sc_blkno
1208 % (type->seccyl * (1 << (type->secsize - 2))))
1209 / (type->sectrac * (1 << (type->secsize - 2)));
1210 pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
1211 sec = pos / (1 << (type->secsize - 2));
1212 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1213 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1214 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1215 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1216 out_fdc(iot, ioh, head);
1217 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1218 out_fdc(iot, ioh, type->secsize); /* sector size */
1219 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1220 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1221 out_fdc(iot, ioh, type->datalen); /* data length */
1222 fdc->sc_state = COPYCOMPLETE;
1223 /* allow 2 seconds for operation */
1224 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1225 return 1; /* will return later */
1226
1227 case DOIOHALF:
1228 doiohalf:
1229 DPRINTF((" DOIOHALF:\n"));
1230
1231 type = fd->sc_type;
1232 sectrac = type->sectrac;
1233 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1234 sec = pos / (1 << (type->secsize - 2));
1235 head = (fd->sc_blkno
1236 % (type->seccyl * (1 << (type->secsize - 2))))
1237 / (type->sectrac * (1 << (type->secsize - 2)));
1238 #ifdef DIAGNOSTIC
1239 {int block;
1240 block = ((fd->sc_cylin * type->heads + head) *
1241 type->sectrac + sec)
1242 * (1 << (type->secsize - 2));
1243 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1244 if (block != fd->sc_blkno) {
1245 printf("fdcintr: block %d != blkno %" PRId64 "\n",
1246 block, fd->sc_blkno);
1247 #ifdef DDB
1248 Debugger();
1249 #endif
1250 }
1251 }
1252 #endif
1253 if ((read = bp->b_flags & B_READ)) {
1254 memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
1255 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1256 FDC_BSIZE);
1257 fdc->sc_state = IOCOMPLETE;
1258 goto iocomplete2;
1259 } else {
1260 memcpy((char *)fd->sc_copybuf
1261 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1262 (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
1263 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1264 }
1265 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1266 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1267 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1268 out_fdc(iot, ioh, head);
1269 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1270 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1271 out_fdc(iot, ioh, sectrac); /* sectors/track */
1272 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1273 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1274 fdc->sc_state = IOCOMPLETE;
1275 /* allow 2 seconds for operation */
1276 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1277 return 1; /* will return later */
1278
1279 case SEEKWAIT:
1280 callout_stop(&fdc->sc_timo_ch);
1281 fdc->sc_state = SEEKCOMPLETE;
1282 /* allow 1/50 second for heads to settle */
1283 #if 0
1284 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1285 #endif
1286 return 1;
1287
1288 case SEEKCOMPLETE:
1289 /* Make sure seek really happened */
1290 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1291 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1292 out_fdc(iot, ioh, NE7CMD_SENSEI);
1293 tmp = fdcresult(fdc);
1294 if ((st0 & 0xf8) == 0xc0) {
1295 DPRINTF(("fdcintr: first seek!\n"));
1296 fdc->sc_state = DORECAL;
1297 goto loop;
1298 } else if (tmp != 2 ||
1299 (st0 & 0xf8) != 0x20 ||
1300 cyl != bp->b_cylinder) {
1301 #ifdef FDDEBUG
1302 fdcstatus(&fd->sc_dev, 2, "seek failed");
1303 #endif
1304 fdcretry(fdc);
1305 goto loop;
1306 }
1307 fd->sc_cylin = bp->b_cylinder;
1308 goto doio;
1309
1310 case IOTIMEDOUT:
1311 #if 0
1312 isa_dmaabort(fdc->sc_drq);
1313 #endif
1314 case SEEKTIMEDOUT:
1315 case RECALTIMEDOUT:
1316 case RESETTIMEDOUT:
1317 fdcretry(fdc);
1318 goto loop;
1319
1320 case IOCOMPLETE: /* IO DONE, post-analyze */
1321 callout_stop(&fdc->sc_timo_ch);
1322 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1323 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1324 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1325 #if 0
1326 isa_dmaabort(fdc->sc_drq);
1327 #endif
1328 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1329 "read failed" : "write failed");
1330 printf("blkno %" PRId64 " nblks %d\n",
1331 fd->sc_blkno, fd->sc_nblks);
1332 fdcretry(fdc);
1333 goto loop;
1334 }
1335 #if 0
1336 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1337 nblks * FDC_BSIZE, fdc->sc_drq);
1338 #endif
1339 iocomplete2:
1340 if (fdc->sc_errors) {
1341 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1342 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1343 printf("\n");
1344 fdc->sc_errors = 0;
1345 }
1346 fd->sc_blkno += fd->sc_nblks;
1347 fd->sc_skip += fd->sc_nbytes;
1348 fd->sc_bcount -= fd->sc_nbytes;
1349 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1350 if (fd->sc_bcount > 0) {
1351 bp->b_cylinder = fd->sc_blkno
1352 / (fd->sc_type->seccyl
1353 * (1 << (fd->sc_type->secsize - 2)));
1354 goto doseek;
1355 }
1356 fdfinish(fd, bp);
1357 goto loop;
1358
1359 case COPYCOMPLETE: /* IO DONE, post-analyze */
1360 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1361 callout_stop(&fdc->sc_timo_ch);
1362 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1363 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1364 #if 0
1365 isa_dmaabort(fdc->sc_drq);
1366 #endif
1367 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1368 "read failed" : "write failed");
1369 printf("blkno %" PRId64 " nblks %d\n",
1370 fd->sc_blkno, fd->sc_nblks);
1371 fdcretry(fdc);
1372 goto loop;
1373 }
1374 goto doiohalf;
1375
1376 case DORESET:
1377 DPRINTF(("fdcintr: in DORESET\n"));
1378 /* try a reset, keep motor on */
1379 fd_set_motor(fdc, 1);
1380 DELAY(100);
1381 fd_set_motor(fdc, 0);
1382 fdc->sc_state = RESETCOMPLETE;
1383 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1384 return 1; /* will return later */
1385
1386 case RESETCOMPLETE:
1387 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1388 callout_stop(&fdc->sc_timo_ch);
1389 /* clear the controller output buffer */
1390 for (i = 0; i < 4; i++) {
1391 out_fdc(iot, ioh, NE7CMD_SENSEI);
1392 (void) fdcresult(fdc);
1393 }
1394
1395 /* fall through */
1396 case DORECAL:
1397 DPRINTF(("fdcintr: in DORECAL\n"));
1398 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1399 out_fdc(iot, ioh, fd->sc_drive);
1400 fdc->sc_state = RECALWAIT;
1401 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1402 return 1; /* will return later */
1403
1404 case RECALWAIT:
1405 DPRINTF(("fdcintr: in RECALWAIT\n"));
1406 callout_stop(&fdc->sc_timo_ch);
1407 fdc->sc_state = RECALCOMPLETE;
1408 /* allow 1/30 second for heads to settle */
1409 #if 0
1410 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1411 #endif
1412 return 1; /* will return later */
1413
1414 case RECALCOMPLETE:
1415 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1416 out_fdc(iot, ioh, NE7CMD_SENSEI);
1417 tmp = fdcresult(fdc);
1418 if ((st0 & 0xf8) == 0xc0) {
1419 DPRINTF(("fdcintr: first seek!\n"));
1420 fdc->sc_state = DORECAL;
1421 goto loop;
1422 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1423 #ifdef FDDEBUG
1424 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1425 #endif
1426 fdcretry(fdc);
1427 goto loop;
1428 }
1429 fd->sc_cylin = 0;
1430 goto doseek;
1431
1432 case MOTORWAIT:
1433 if (fd->sc_flags & FD_MOTOR_WAIT)
1434 return 1; /* time's not up yet */
1435 goto doseek;
1436
1437 default:
1438 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1439 return 1;
1440 }
1441 #ifdef DIAGNOSTIC
1442 panic("fdcintr: impossible");
1443 #endif
1444 #undef st0
1445 #undef cyl
1446 }
1447
1448 void
1449 fdcretry(struct fdc_softc *fdc)
1450 {
1451 struct fd_softc *fd;
1452 struct buf *bp;
1453 char bits[64];
1454
1455 DPRINTF(("fdcretry:\n"));
1456 fd = fdc->sc_drives.tqh_first;
1457 bp = BUFQ_PEEK(fd->sc_q);
1458
1459 switch (fdc->sc_errors) {
1460 case 0:
1461 /* try again */
1462 fdc->sc_state = SEEKCOMPLETE;
1463 break;
1464
1465 case 1: case 2: case 3:
1466 /* didn't work; try recalibrating */
1467 fdc->sc_state = DORECAL;
1468 break;
1469
1470 case 4:
1471 /* still no go; reset the bastard */
1472 fdc->sc_state = DORESET;
1473 break;
1474
1475 default:
1476 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1477 fd->sc_skip, (struct disklabel *)NULL);
1478 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1479 NE7_ST0BITS, bits,
1480 sizeof(bits)));
1481 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1482 NE7_ST1BITS, bits,
1483 sizeof(bits)));
1484 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1485 NE7_ST2BITS, bits,
1486 sizeof(bits)));
1487 printf(" cyl %d head %d sec %d)\n",
1488 fdc->sc_status[3],
1489 fdc->sc_status[4],
1490 fdc->sc_status[5]);
1491
1492 bp->b_error = EIO;
1493 fdfinish(fd, bp);
1494 }
1495 fdc->sc_errors++;
1496 }
1497
1498 int
1499 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1500 {
1501 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1502 struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
1503 int part = DISKPART(dev);
1504 struct disklabel buffer;
1505 int error;
1506
1507 DPRINTF(("fdioctl:\n"));
1508 switch (cmd) {
1509 case DIOCGDINFO:
1510 #if 1
1511 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1512 return(0);
1513 #else
1514 memset(&buffer, 0, sizeof(buffer));
1515
1516 buffer.d_secpercyl = fd->sc_type->seccyl;
1517 buffer.d_type = DTYPE_FLOPPY;
1518 buffer.d_secsize = 128 << fd->sc_type->secsize;
1519
1520 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1521 return EINVAL;
1522
1523 *(struct disklabel *)addr = buffer;
1524 return 0;
1525 #endif
1526
1527 case DIOCGPART:
1528 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1529 ((struct partinfo *)addr)->part =
1530 &fd->sc_dk.dk_label->d_partitions[part];
1531 return(0);
1532
1533 case DIOCWLABEL:
1534 if ((flag & FWRITE) == 0)
1535 return EBADF;
1536 /* XXX do something */
1537 return 0;
1538
1539 case DIOCWDINFO:
1540 if ((flag & FWRITE) == 0)
1541 return EBADF;
1542
1543 error = setdisklabel(&buffer, (struct disklabel *)addr,
1544 0, NULL);
1545 if (error)
1546 return error;
1547
1548 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1549 return error;
1550
1551 case DIOCLOCK:
1552 /*
1553 * Nothing to do here, really.
1554 */
1555 return 0; /* XXX */
1556
1557 case DIOCEJECT:
1558 if (*(int *)addr == 0) {
1559 /*
1560 * Don't force eject: check that we are the only
1561 * partition open. If so, unlock it.
1562 */
1563 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1564 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1565 fd->sc_dk.dk_openmask) {
1566 return (EBUSY);
1567 }
1568 }
1569 /* FALLTHROUGH */
1570 case ODIOCEJECT:
1571 fd_do_eject(fdc, FDUNIT(dev));
1572 return 0;
1573
1574 default:
1575 return ENOTTY;
1576 }
1577
1578 #ifdef DIAGNOSTIC
1579 panic("fdioctl: impossible");
1580 #endif
1581 }
1582
1583 void
1584 fd_do_eject(struct fdc_softc *fdc, int unit)
1585 {
1586 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1587 0x20 | ( 1 << unit));
1588 DELAY(1); /* XXX */
1589 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1590 }
1591
1592 /*
1593 * Build disk label. For now we only create a label from what we know
1594 * from 'sc'.
1595 */
1596 static int
1597 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
1598 {
1599 struct disklabel *lp;
1600 int part;
1601
1602 DPRINTF(("fdgetdisklabel()\n"));
1603
1604 part = DISKPART(dev);
1605 lp = sc->sc_dk.dk_label;
1606 memset(lp, 0, sizeof(struct disklabel));
1607
1608 lp->d_secsize = 128 << sc->sc_type->secsize;
1609 lp->d_ntracks = sc->sc_type->heads;
1610 lp->d_nsectors = sc->sc_type->sectrac;
1611 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1612 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1613 lp->d_secperunit = sc->sc_type->size;
1614
1615 lp->d_type = DTYPE_FLOPPY;
1616 lp->d_rpm = 300; /* XXX */
1617 lp->d_interleave = 1; /* FIXME: is this OK? */
1618 lp->d_bbsize = 0;
1619 lp->d_sbsize = 0;
1620 lp->d_npartitions = part + 1;
1621 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1622 lp->d_trkseek = STEP_DELAY; /* XXX */
1623 lp->d_magic = DISKMAGIC;
1624 lp->d_magic2 = DISKMAGIC;
1625 lp->d_checksum = dkcksum(lp);
1626 lp->d_partitions[part].p_size = lp->d_secperunit;
1627 lp->d_partitions[part].p_fstype = FS_UNUSED;
1628 lp->d_partitions[part].p_fsize = 1024;
1629 lp->d_partitions[part].p_frag = 8;
1630
1631 return(0);
1632 }
1633
1634 #include <dev/cons.h>
1635
1636 /*
1637 * Mountroot hook: prompt the user to enter the root file system
1638 * floppy.
1639 */
1640 void
1641 fd_mountroot_hook(struct device *dev)
1642 {
1643 struct fd_softc *fd = (void *)dev;
1644 struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
1645 int c;
1646
1647 /* XXX device_unit() abuse */
1648 fd_do_eject(fdc, device_unit(dev));
1649 printf("Insert filesystem floppy and press return.");
1650 for (;;) {
1651 c = cngetc();
1652 if ((c == '\r') || (c == '\n')) {
1653 printf("\n");
1654 break;
1655 }
1656 }
1657 }
1658