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