fd.c revision 1.90 1 /* $NetBSD: fd.c,v 1.90 2009/01/10 06:45:06 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.90 2009/01/10 06:45:06 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 bus_space_tag_t sc_iot; /* intio i/o space identifier */
142 bus_space_handle_t sc_ioh; /* intio io handle */
143
144 struct callout sc_timo_ch; /* timeout callout */
145 struct callout sc_intr_ch; /* pseudo-intr callout */
146
147 bus_dma_tag_t sc_dmat; /* intio DMA tag */
148 bus_dmamap_t sc_dmamap; /* DMA map */
149 u_int8_t *sc_addr; /* physical address */
150 struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
151 struct dmac_dma_xfer *sc_xfer; /* DMA transfer */
152
153 struct fd_softc *sc_fd[4]; /* pointers to children */
154 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
155 enum fdc_state sc_state;
156 int sc_errors; /* number of retries so far */
157 u_char sc_status[7]; /* copy of registers */
158 } fdc_softc;
159
160 int fdcintr(void *);
161 void fdcreset(struct fdc_softc *);
162
163 /* controller driver configuration */
164 int fdcprobe(device_t, cfdata_t, void *);
165 void fdcattach(device_t, device_t, void *);
166 int fdprint(void *, const char *);
167
168 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc),
169 fdcprobe, fdcattach, NULL, NULL);
170
171 extern struct cfdriver fdc_cd;
172
173 /*
174 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
175 * we tell them apart.
176 */
177 struct fd_type {
178 int sectrac; /* sectors per track */
179 int heads; /* number of heads */
180 int seccyl; /* sectors per cylinder */
181 int secsize; /* size code for sectors */
182 int datalen; /* data len when secsize = 0 */
183 int steprate; /* step rate and head unload time */
184 int gap1; /* gap len between sectors */
185 int gap2; /* formatting gap */
186 int cyls; /* total num of cylinders */
187 int size; /* size of disk in sectors */
188 int step; /* steps per cylinder */
189 int rate; /* transfer speed code */
190 const char *name;
191 };
192
193 /* The order of entries in the following table is important -- BEWARE! */
194 struct fd_type fd_types[] = {
195 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
196 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
197 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
198 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
199 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
200 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
201 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
202 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
203 };
204
205 /* software state, per disk (with up to 4 disks per ctlr) */
206 struct fd_softc {
207 device_t sc_dev;
208 struct disk sc_dk;
209
210 struct fd_type *sc_deftype; /* default type descriptor */
211 struct fd_type *sc_type; /* current type descriptor */
212
213 struct callout sc_motoron_ch;
214 struct callout sc_motoroff_ch;
215
216 daddr_t sc_blkno; /* starting block number */
217 int sc_bcount; /* byte count left */
218 int sc_opts; /* user-set options */
219 int sc_skip; /* bytes already transferred */
220 int sc_nblks; /* number of blocks currently transferring */
221 int sc_nbytes; /* number of bytes currently transferring */
222
223 int sc_drive; /* physical unit number */
224 int sc_flags;
225 #define FD_BOPEN 0x01 /* it's open */
226 #define FD_COPEN 0x02 /* it's open */
227 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
228 #define FD_MOTOR 0x04 /* motor should be on */
229 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
230 #define FD_ALIVE 0x10 /* alive */
231 int sc_cylin; /* where we think the head is */
232
233 TAILQ_ENTRY(fd_softc) sc_drivechain;
234 int sc_ops; /* I/O ops since last switch */
235 struct bufq_state *sc_q;/* pending I/O requests */
236 int sc_active; /* number of active I/O operations */
237 u_char *sc_copybuf; /* for secsize >=3 */
238 u_char sc_part; /* for secsize >=3 */
239 #define SEC_P10 0x02 /* first part */
240 #define SEC_P01 0x01 /* second part */
241 #define SEC_P11 0x03 /* both part */
242
243 #if NRND > 0
244 rndsource_element_t rnd_source;
245 #endif
246 };
247
248 /* floppy driver configuration */
249 int fdprobe(device_t, cfdata_t, void *);
250 void fdattach(device_t, device_t, void *);
251
252 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
253 fdprobe, fdattach, NULL, NULL);
254
255 extern struct cfdriver fd_cd;
256
257 dev_type_open(fdopen);
258 dev_type_close(fdclose);
259 dev_type_read(fdread);
260 dev_type_write(fdwrite);
261 dev_type_ioctl(fdioctl);
262 dev_type_strategy(fdstrategy);
263
264 const struct bdevsw fd_bdevsw = {
265 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
266 };
267
268 const struct cdevsw fd_cdevsw = {
269 fdopen, fdclose, fdread, fdwrite, fdioctl,
270 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
271 };
272
273 void fdstart(struct fd_softc *);
274
275 struct dkdriver fddkdriver = { fdstrategy };
276
277 void fd_set_motor(struct fdc_softc *, int);
278 void fd_motor_off(void *);
279 void fd_motor_on(void *);
280 int fdcresult(struct fdc_softc *);
281 int out_fdc(bus_space_tag_t, bus_space_handle_t, u_char);
282 void fdcstart(struct fdc_softc *);
283 void fdcstatus(device_t, int, const char *);
284 void fdctimeout(void *);
285 void fdcpseudointr(void *);
286 void fdcretry(struct fdc_softc *);
287 void fdfinish(struct fd_softc *, struct buf *);
288 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
289 static int fdcpoll(struct fdc_softc *);
290 static int fdgetdisklabel(struct fd_softc *, dev_t);
291 static void fd_do_eject(struct fdc_softc *, int);
292
293 void fd_mountroot_hook(device_t);
294
295 /* DMA transfer routines */
296 inline static void fdc_dmastart(struct fdc_softc *, int, void *, vsize_t);
297 static int fdcdmaintr(void *);
298 static int fdcdmaerrintr(void *);
299
300 inline static void
301 fdc_dmastart(struct fdc_softc *fdc, int read, void *addr, vsize_t count)
302 {
303 int error;
304
305 DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
306 read ? "read" : "write", (void *) addr, count));
307
308 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
309 0, BUS_DMA_NOWAIT);
310 if (error) {
311 panic ("fdc_dmastart: cannot load dmamap");
312 }
313
314 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
315 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
316
317 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
318 fdc->sc_dmamap,
319 (read?
320 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
321 (DMAC_SCR_MAC_COUNT_UP|
322 DMAC_SCR_DAC_NO_COUNT),
323 (u_int8_t*) (fdc->sc_addr +
324 fddata)); /* XXX */
325
326 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
327 }
328
329 static int
330 fdcdmaintr(void *arg)
331 {
332 struct fdc_softc *fdc = arg;
333
334 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
335
336 return 0;
337 }
338
339 static int
340 fdcdmaerrintr(void *dummy)
341 {
342 DPRINTF(("fdcdmaerrintr\n"));
343
344 return 0;
345 }
346
347 /* ARGSUSED */
348 int
349 fdcprobe(device_t parent, cfdata_t cf, void *aux)
350 {
351 struct intio_attach_args *ia = aux;
352
353 if (strcmp(ia->ia_name, "fdc") != 0)
354 return 0;
355
356 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
357 ia->ia_addr = FDC_ADDR;
358 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
359 ia->ia_intr = FDC_INTR;
360 if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
361 ia->ia_dma = FDC_DMA;
362 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
363 ia->ia_dmaintr = FDC_DMAINTR;
364
365 if ((ia->ia_intr & 0x03) != 0)
366 return 0;
367
368 ia->ia_size = 0x2000;
369 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
370 return 0;
371
372 /* builtin device; always there */
373 return 1;
374 }
375
376 /*
377 * Arguments passed between fdcattach and fdprobe.
378 */
379 struct fdc_attach_args {
380 int fa_drive;
381 struct fd_type *fa_deftype;
382 };
383
384 /*
385 * Print the location of a disk drive (called just before attaching the
386 * the drive). If `fdc' is not NULL, the drive was found but was not
387 * in the system config file; print the drive name as well.
388 * Return QUIET (config_find ignores this if the device was configured) to
389 * avoid printing `fdN not configured' messages.
390 */
391 int
392 fdprint(void *aux, const char *fdc)
393 {
394 struct fdc_attach_args *fa = aux;
395
396 if (!fdc)
397 aprint_normal(" drive %d", fa->fa_drive);
398 return QUIET;
399 }
400
401 void
402 fdcattach(device_t parent, device_t self, void *aux)
403 {
404 struct fdc_softc *fdc = device_private(self);
405 bus_space_tag_t iot;
406 bus_space_handle_t ioh;
407 struct intio_attach_args *ia = aux;
408 struct fdc_attach_args fa;
409
410 iot = ia->ia_bst;
411
412 aprint_normal("\n");
413
414 callout_init(&fdc->sc_timo_ch, 0);
415 callout_init(&fdc->sc_intr_ch, 0);
416
417 /* Re-map the I/O space. */
418 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
419
420 fdc->sc_iot = iot;
421 fdc->sc_ioh = ioh;
422 fdc->sc_addr = (void *)ia->ia_addr;
423
424 fdc->sc_dmat = ia->ia_dmat;
425 fdc->sc_state = DEVIDLE;
426 TAILQ_INIT(&fdc->sc_drives);
427
428 /* Initialize DMAC channel */
429 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
430 ia->ia_dmaintr, fdcdmaintr, fdc,
431 ia->ia_dmaintr+1, fdcdmaerrintr,
432 fdc);
433 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
434 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
435 &fdc->sc_dmamap)) {
436 aprint_error_dev(self, "can't set up intio DMA map\n");
437 return;
438 }
439
440 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
441 panic ("Could not establish interrupt (duplicated vector?).");
442 intio_set_ivec(ia->ia_intr);
443
444 /* reset */
445 intio_disable_intr(SICILIAN_INTR_FDD);
446 intio_enable_intr(SICILIAN_INTR_FDC);
447 fdcresult(fdc);
448 fdcreset(fdc);
449
450 aprint_normal_dev(self, "uPD72065 FDC\n");
451 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
452 out_fdc(iot, ioh, 0xd0);
453 out_fdc(iot, ioh, 0x10);
454
455 /* physical limit: four drives per controller. */
456 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
457 (void)config_found(self, (void *)&fa, fdprint);
458 }
459
460 intio_enable_intr(SICILIAN_INTR_FDC);
461 }
462
463 void
464 fdcreset(struct fdc_softc *fdc)
465 {
466 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
467 }
468
469 static int
470 fdcpoll(struct fdc_softc *fdc)
471 {
472 int i = 25000, n;
473 while (--i > 0) {
474 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
475 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
476 n = fdcresult(fdc);
477 break;
478 }
479 DELAY(100);
480 }
481 return i;
482 }
483
484 int
485 fdprobe(device_t parent, cfdata_t cf, void *aux)
486 {
487 struct fdc_softc *fdc = device_private(parent);
488 struct fd_type *type;
489 struct fdc_attach_args *fa = aux;
490 int drive = fa->fa_drive;
491 bus_space_tag_t iot = fdc->sc_iot;
492 bus_space_handle_t ioh = fdc->sc_ioh;
493 int n = 0;
494 int found = 0;
495 int i;
496
497 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
498 cf->cf_loc[FDCCF_UNIT] != drive)
499 return 0;
500
501 type = &fd_types[0]; /* XXX 1.2MB */
502
503 intio_disable_intr(SICILIAN_INTR_FDC);
504
505 /* select drive and turn on motor */
506 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
507 fdc_force_ready(FDCRDY);
508 fdcpoll(fdc);
509
510 retry:
511 out_fdc(iot, ioh, NE7CMD_RECAL);
512 out_fdc(iot, ioh, drive);
513
514 i = 25000;
515 while (--i > 0) {
516 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
517 out_fdc(iot, ioh, NE7CMD_SENSEI);
518 n = fdcresult(fdc);
519 break;
520 }
521 DELAY(100);
522 }
523
524 #ifdef FDDEBUG
525 {
526 int _i;
527 DPRINTF(("fdprobe: status"));
528 for (_i = 0; _i < n; _i++)
529 DPRINTF((" %x", fdc->sc_status[_i]));
530 DPRINTF(("\n"));
531 }
532 #endif
533
534 if (n == 2) {
535 if ((fdc->sc_status[0] & 0xf0) == 0x20)
536 found = 1;
537 else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
538 goto retry;
539 }
540
541 /* turn off motor */
542 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
543 fdctl, (type->rate << 4)| drive);
544 fdc_force_ready(FDCSTBY);
545 if (!found) {
546 intio_enable_intr(SICILIAN_INTR_FDC);
547 return 0;
548 }
549
550 return 1;
551 }
552
553 /*
554 * Controller is working, and drive responded. Attach it.
555 */
556 void
557 fdattach(device_t parent, device_t self, void *aux)
558 {
559 struct fdc_softc *fdc = device_private(parent);
560 struct fd_softc *fd = device_private(self);
561 struct fdc_attach_args *fa = aux;
562 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
563 int drive = fa->fa_drive;
564
565 callout_init(&fd->sc_motoron_ch, 0);
566 callout_init(&fd->sc_motoroff_ch, 0);
567
568 fd->sc_dev = self;
569 fd->sc_flags = 0;
570
571 if (type)
572 aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
573 type->cyls, type->heads, type->sectrac);
574 else
575 aprint_normal(": density unknown\n");
576
577 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
578 fd->sc_cylin = -1;
579 fd->sc_drive = drive;
580 fd->sc_deftype = type;
581 fdc->sc_fd[drive] = fd;
582
583 fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
584 if (fd->sc_copybuf == 0)
585 aprint_error("%s: WARNING!! malloc() failed.\n", __func__);
586 fd->sc_flags |= FD_ALIVE;
587
588 /*
589 * Initialize and attach the disk structure.
590 */
591 disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
592 disk_attach(&fd->sc_dk);
593
594 /*
595 * Establish a mountroot_hook anyway in case we booted
596 * with RB_ASKNAME and get selected as the boot device.
597 */
598 mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
599
600 #if NRND > 0
601 rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
602 RND_TYPE_DISK, 0);
603 #endif
604 }
605
606 inline struct fd_type *
607 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
608 {
609 int type = FDTYPE(dev);
610
611 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
612 return NULL;
613 return &fd_types[type];
614 }
615
616 void
617 fdstrategy(struct buf *bp)
618 {
619 struct fd_softc *fd;
620 int unit;
621 int sz;
622 int s;
623
624 unit = FDUNIT(bp->b_dev);
625 fd = device_lookup_private(&fd_cd, unit);
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 = device_private(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 = device_private(device_parent(fd->sc_dev));
698 int active = !TAILQ_EMPTY(&fdc->sc_drives);
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 = device_private(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 (TAILQ_NEXT(fd, sc_drivechain) && ++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 = device_private(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 = device_private(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 ((TAILQ_FIRST(&fdc->sc_drives) == 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
936 static void
937 fdcpstatus(int n, struct fdc_softc *fdc)
938 {
939 char bits[64];
940
941 switch (n) {
942 case 0:
943 printf("\n");
944 break;
945 case 2:
946 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
947 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
948 break;
949 case 7:
950 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
951 printf(" (st0 %s", bits);
952 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
953 printf(" st1 %s", bits);
954 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
955 printf(" st2 %s", bits);
956 printf(" cyl %d head %d sec %d)\n",
957 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
958 break;
959 #ifdef DIAGNOSTIC
960 default:
961 printf("\nfdcstatus: weird size");
962 break;
963 #endif
964 }
965 }
966
967 void
968 fdcstatus(device_t dv, int n, const char *s)
969 {
970 struct fdc_softc *fdc = device_private(device_parent(dv));
971
972 if (n == 0) {
973 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
974 (void) fdcresult(fdc);
975 n = 2;
976 }
977
978 printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state);
979 fdcpstatus(n, fdc);
980 }
981
982 void
983 fdctimeout(void *arg)
984 {
985 struct fdc_softc *fdc = arg;
986 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
987 int s;
988
989 s = splbio();
990 fdcstatus(fd->sc_dev, 0, "timeout");
991
992 if (BUFQ_PEEK(fd->sc_q) != NULL)
993 fdc->sc_state++;
994 else
995 fdc->sc_state = DEVIDLE;
996
997 (void) fdcintr(fdc);
998 splx(s);
999 }
1000
1001 #if 0
1002 void
1003 fdcpseudointr(void *arg)
1004 {
1005 int s;
1006 struct fdc_softc *fdc = arg;
1007
1008 /* just ensure it has the right spl */
1009 s = splbio();
1010 (void) fdcintr(fdc);
1011 splx(s);
1012 }
1013 #endif
1014
1015 int
1016 fdcintr(void *arg)
1017 {
1018 struct fdc_softc *fdc = arg;
1019 #define st0 fdc->sc_status[0]
1020 #define cyl fdc->sc_status[1]
1021 struct fd_softc *fd;
1022 struct buf *bp;
1023 bus_space_tag_t iot = fdc->sc_iot;
1024 bus_space_handle_t ioh = fdc->sc_ioh;
1025 int read, head, sec, pos, i, sectrac, nblks;
1026 int tmp;
1027 struct fd_type *type;
1028
1029 loop:
1030 fd = TAILQ_FIRST(&fdc->sc_drives);
1031 if (fd == NULL) {
1032 DPRINTF(("fdcintr: set DEVIDLE\n"));
1033 if (fdc->sc_state == DEVIDLE) {
1034 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1035 out_fdc(iot, ioh, NE7CMD_SENSEI);
1036 if ((tmp = fdcresult(fdc)) != 2 ||
1037 (st0 & 0xf8) != 0x20) {
1038 goto loop;
1039 }
1040 }
1041 }
1042 /* no drives waiting; end */
1043 fdc->sc_state = DEVIDLE;
1044 return 1;
1045 }
1046
1047 /* Is there a transfer to this drive? If not, deactivate drive. */
1048 bp = BUFQ_PEEK(fd->sc_q);
1049 if (bp == NULL) {
1050 fd->sc_ops = 0;
1051 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1052 fd->sc_active = 0;
1053 goto loop;
1054 }
1055
1056 switch (fdc->sc_state) {
1057 case DEVIDLE:
1058 DPRINTF(("fdcintr: in DEVIDLE\n"));
1059 fdc->sc_errors = 0;
1060 fd->sc_skip = 0;
1061 fd->sc_bcount = bp->b_bcount;
1062 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1063 callout_stop(&fd->sc_motoroff_ch);
1064 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1065 fdc->sc_state = MOTORWAIT;
1066 return 1;
1067 }
1068 if ((fd->sc_flags & FD_MOTOR) == 0) {
1069 /* Turn on the motor */
1070 /* being careful about other drives. */
1071 for (i = 0; i < 4; i++) {
1072 struct fd_softc *ofd = fdc->sc_fd[i];
1073 if (ofd && ofd->sc_flags & FD_MOTOR) {
1074 callout_stop(&ofd->sc_motoroff_ch);
1075 ofd->sc_flags &=
1076 ~(FD_MOTOR | FD_MOTOR_WAIT);
1077 break;
1078 }
1079 }
1080 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1081 fd_set_motor(fdc, 0);
1082 fdc->sc_state = MOTORWAIT;
1083 /* allow .5s for motor to stabilize */
1084 callout_reset(&fd->sc_motoron_ch, hz / 2,
1085 fd_motor_on, fd);
1086 return 1;
1087 }
1088 /* Make sure the right drive is selected. */
1089 fd_set_motor(fdc, 0);
1090
1091 /* fall through */
1092 case DOSEEK:
1093 doseek:
1094 DPRINTF(("fdcintr: in DOSEEK\n"));
1095 if (fd->sc_cylin == bp->b_cylinder)
1096 goto doio;
1097
1098 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1099 out_fdc(iot, ioh, 0xd0); /* XXX const */
1100 out_fdc(iot, ioh, 0x10);
1101
1102 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1103 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1104 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1105
1106 fd->sc_cylin = -1;
1107 fdc->sc_state = SEEKWAIT;
1108
1109 iostat_seek(fd->sc_dk.dk_stats);
1110 disk_busy(&fd->sc_dk);
1111
1112 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1113 return 1;
1114
1115 case DOIO:
1116 doio:
1117 DPRINTF(("fdcintr: DOIO: "));
1118 type = fd->sc_type;
1119 sectrac = type->sectrac;
1120 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1121 sec = pos / (1 << (type->secsize - 2));
1122 if (type->secsize == 2) {
1123 fd->sc_part = SEC_P11;
1124 nblks = (sectrac - sec) << (type->secsize - 2);
1125 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1126 DPRINTF(("nblks(0)"));
1127 } else if ((fd->sc_blkno % 2) == 0) {
1128 if (fd->sc_bcount & 0x00000200) {
1129 if (fd->sc_bcount == FDC_BSIZE) {
1130 fd->sc_part = SEC_P10;
1131 nblks = 1;
1132 DPRINTF(("nblks(1)"));
1133 } else {
1134 fd->sc_part = SEC_P11;
1135 nblks = (sectrac - sec) * 2;
1136 nblks = min(nblks, fd->sc_bcount
1137 / FDC_BSIZE - 1);
1138 DPRINTF(("nblks(2)"));
1139 }
1140 } else {
1141 fd->sc_part = SEC_P11;
1142 nblks = (sectrac - sec)
1143 << (type->secsize - 2);
1144 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1145 DPRINTF(("nblks(3)"));
1146 }
1147 } else {
1148 fd->sc_part = SEC_P01;
1149 nblks = 1;
1150 DPRINTF(("nblks(4)"));
1151 }
1152 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1153 DPRINTF((" %d\n", nblks));
1154 fd->sc_nblks = nblks;
1155 fd->sc_nbytes = nblks * FDC_BSIZE;
1156 head = (fd->sc_blkno
1157 % (type->seccyl * (1 << (type->secsize - 2))))
1158 / (type->sectrac * (1 << (type->secsize - 2)));
1159
1160 #ifdef DIAGNOSTIC
1161 {int block;
1162 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1163 + sec) * (1 << (type->secsize - 2));
1164 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1165 if (block != fd->sc_blkno) {
1166 printf("C H R N: %d %d %d %d\n",
1167 fd->sc_cylin, head, sec, type->secsize);
1168 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
1169 block, fd->sc_blkno);
1170 #ifdef DDB
1171 Debugger();
1172 #endif
1173 }
1174 }
1175 #endif
1176 read = bp->b_flags & B_READ;
1177 DPRINTF(("fdcintr: %s drive %d track %d "
1178 "head %d sec %d nblks %d, skip %d\n",
1179 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1180 head, sec, nblks, fd->sc_skip));
1181 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1182 type->secsize));
1183
1184 if (fd->sc_part != SEC_P11)
1185 goto docopy;
1186
1187 fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
1188 fd->sc_nbytes);
1189 if (read)
1190 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1191 else
1192 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1193 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1194 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1195 out_fdc(iot, ioh, head);
1196 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1197 out_fdc(iot, ioh, type->secsize); /* sector size */
1198 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1199 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1200 out_fdc(iot, ioh, type->datalen); /* data length */
1201 fdc->sc_state = IOCOMPLETE;
1202
1203 disk_busy(&fd->sc_dk);
1204
1205 /* allow 2 seconds for operation */
1206 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1207 return 1; /* will return later */
1208
1209 case DOCOPY:
1210 docopy:
1211 DPRINTF(("fdcintr: DOCOPY:\n"));
1212 type = fd->sc_type;
1213 head = (fd->sc_blkno
1214 % (type->seccyl * (1 << (type->secsize - 2))))
1215 / (type->sectrac * (1 << (type->secsize - 2)));
1216 pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
1217 sec = pos / (1 << (type->secsize - 2));
1218 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1219 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1220 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1221 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1222 out_fdc(iot, ioh, head);
1223 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1224 out_fdc(iot, ioh, type->secsize); /* sector size */
1225 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1226 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1227 out_fdc(iot, ioh, type->datalen); /* data length */
1228 fdc->sc_state = COPYCOMPLETE;
1229 /* allow 2 seconds for operation */
1230 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1231 return 1; /* will return later */
1232
1233 case DOIOHALF:
1234 doiohalf:
1235 DPRINTF((" DOIOHALF:\n"));
1236
1237 type = fd->sc_type;
1238 sectrac = type->sectrac;
1239 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1240 sec = pos / (1 << (type->secsize - 2));
1241 head = (fd->sc_blkno
1242 % (type->seccyl * (1 << (type->secsize - 2))))
1243 / (type->sectrac * (1 << (type->secsize - 2)));
1244 #ifdef DIAGNOSTIC
1245 {int block;
1246 block = ((fd->sc_cylin * type->heads + head) *
1247 type->sectrac + sec)
1248 * (1 << (type->secsize - 2));
1249 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1250 if (block != fd->sc_blkno) {
1251 printf("fdcintr: block %d != blkno %" PRId64 "\n",
1252 block, fd->sc_blkno);
1253 #ifdef DDB
1254 Debugger();
1255 #endif
1256 }
1257 }
1258 #endif
1259 if ((read = bp->b_flags & B_READ)) {
1260 memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
1261 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1262 FDC_BSIZE);
1263 fdc->sc_state = IOCOMPLETE;
1264 goto iocomplete2;
1265 } else {
1266 memcpy((char *)fd->sc_copybuf
1267 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1268 (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
1269 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1270 }
1271 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1272 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1273 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1274 out_fdc(iot, ioh, head);
1275 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1276 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1277 out_fdc(iot, ioh, sectrac); /* sectors/track */
1278 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1279 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1280 fdc->sc_state = IOCOMPLETE;
1281 /* allow 2 seconds for operation */
1282 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1283 return 1; /* will return later */
1284
1285 case SEEKWAIT:
1286 callout_stop(&fdc->sc_timo_ch);
1287 fdc->sc_state = SEEKCOMPLETE;
1288 /* allow 1/50 second for heads to settle */
1289 #if 0
1290 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1291 #endif
1292 return 1;
1293
1294 case SEEKCOMPLETE:
1295 /* Make sure seek really happened */
1296 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1297 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1298 out_fdc(iot, ioh, NE7CMD_SENSEI);
1299 tmp = fdcresult(fdc);
1300 if ((st0 & 0xf8) == 0xc0) {
1301 DPRINTF(("fdcintr: first seek!\n"));
1302 fdc->sc_state = DORECAL;
1303 goto loop;
1304 } else if (tmp != 2 ||
1305 (st0 & 0xf8) != 0x20 ||
1306 cyl != bp->b_cylinder) {
1307 #ifdef FDDEBUG
1308 fdcstatus(fd->sc_dev, 2, "seek failed");
1309 #endif
1310 fdcretry(fdc);
1311 goto loop;
1312 }
1313 fd->sc_cylin = bp->b_cylinder;
1314 goto doio;
1315
1316 case IOTIMEDOUT:
1317 #if 0
1318 isa_dmaabort(fdc->sc_drq);
1319 #endif
1320 case SEEKTIMEDOUT:
1321 case RECALTIMEDOUT:
1322 case RESETTIMEDOUT:
1323 fdcretry(fdc);
1324 goto loop;
1325
1326 case IOCOMPLETE: /* IO DONE, post-analyze */
1327 callout_stop(&fdc->sc_timo_ch);
1328 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1329 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1330 #if 0
1331 isa_dmaabort(fdc->sc_drq);
1332 #endif
1333 fdcstatus(fd->sc_dev, tmp, bp->b_flags & B_READ ?
1334 "read failed" : "write failed");
1335 printf("blkno %" PRId64 " nblks %d\n",
1336 fd->sc_blkno, fd->sc_nblks);
1337 fdcretry(fdc);
1338 goto loop;
1339 }
1340 #if 0
1341 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1342 nblks * FDC_BSIZE, fdc->sc_drq);
1343 #endif
1344 iocomplete2:
1345 if (fdc->sc_errors) {
1346 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1347 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1348 printf("\n");
1349 fdc->sc_errors = 0;
1350 }
1351 fd->sc_blkno += fd->sc_nblks;
1352 fd->sc_skip += fd->sc_nbytes;
1353 fd->sc_bcount -= fd->sc_nbytes;
1354 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1355 if (fd->sc_bcount > 0) {
1356 bp->b_cylinder = fd->sc_blkno
1357 / (fd->sc_type->seccyl
1358 * (1 << (fd->sc_type->secsize - 2)));
1359 goto doseek;
1360 }
1361 fdfinish(fd, bp);
1362 goto loop;
1363
1364 case COPYCOMPLETE: /* IO DONE, post-analyze */
1365 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1366 callout_stop(&fdc->sc_timo_ch);
1367 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1368 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1369 #if 0
1370 isa_dmaabort(fdc->sc_drq);
1371 #endif
1372 fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
1373 "read failed" : "write failed");
1374 printf("blkno %" PRId64 " nblks %d\n",
1375 fd->sc_blkno, fd->sc_nblks);
1376 fdcretry(fdc);
1377 goto loop;
1378 }
1379 goto doiohalf;
1380
1381 case DORESET:
1382 DPRINTF(("fdcintr: in DORESET\n"));
1383 /* try a reset, keep motor on */
1384 fd_set_motor(fdc, 1);
1385 DELAY(100);
1386 fd_set_motor(fdc, 0);
1387 fdc->sc_state = RESETCOMPLETE;
1388 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1389 return 1; /* will return later */
1390
1391 case RESETCOMPLETE:
1392 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1393 callout_stop(&fdc->sc_timo_ch);
1394 /* clear the controller output buffer */
1395 for (i = 0; i < 4; i++) {
1396 out_fdc(iot, ioh, NE7CMD_SENSEI);
1397 (void) fdcresult(fdc);
1398 }
1399
1400 /* fall through */
1401 case DORECAL:
1402 DPRINTF(("fdcintr: in DORECAL\n"));
1403 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1404 out_fdc(iot, ioh, fd->sc_drive);
1405 fdc->sc_state = RECALWAIT;
1406 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1407 return 1; /* will return later */
1408
1409 case RECALWAIT:
1410 DPRINTF(("fdcintr: in RECALWAIT\n"));
1411 callout_stop(&fdc->sc_timo_ch);
1412 fdc->sc_state = RECALCOMPLETE;
1413 /* allow 1/30 second for heads to settle */
1414 #if 0
1415 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1416 #endif
1417 return 1; /* will return later */
1418
1419 case RECALCOMPLETE:
1420 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1421 out_fdc(iot, ioh, NE7CMD_SENSEI);
1422 tmp = fdcresult(fdc);
1423 if ((st0 & 0xf8) == 0xc0) {
1424 DPRINTF(("fdcintr: first seek!\n"));
1425 fdc->sc_state = DORECAL;
1426 goto loop;
1427 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1428 #ifdef FDDEBUG
1429 fdcstatus(fd->sc_dev, 2, "recalibrate failed");
1430 #endif
1431 fdcretry(fdc);
1432 goto loop;
1433 }
1434 fd->sc_cylin = 0;
1435 goto doseek;
1436
1437 case MOTORWAIT:
1438 if (fd->sc_flags & FD_MOTOR_WAIT)
1439 return 1; /* time's not up yet */
1440 goto doseek;
1441
1442 default:
1443 fdcstatus(fd->sc_dev, 0, "stray interrupt");
1444 return 1;
1445 }
1446 #ifdef DIAGNOSTIC
1447 panic("fdcintr: impossible");
1448 #endif
1449 #undef st0
1450 #undef cyl
1451 }
1452
1453 void
1454 fdcretry(struct fdc_softc *fdc)
1455 {
1456 struct fd_softc *fd;
1457 struct buf *bp;
1458
1459 DPRINTF(("fdcretry:\n"));
1460 fd = TAILQ_FIRST(&fdc->sc_drives);
1461 bp = BUFQ_PEEK(fd->sc_q);
1462
1463 switch (fdc->sc_errors) {
1464 case 0:
1465 /* try again */
1466 fdc->sc_state = SEEKCOMPLETE;
1467 break;
1468
1469 case 1: case 2: case 3:
1470 /* didn't work; try recalibrating */
1471 fdc->sc_state = DORECAL;
1472 break;
1473
1474 case 4:
1475 /* still no go; reset the bastard */
1476 fdc->sc_state = DORESET;
1477 break;
1478
1479 default:
1480 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1481 fd->sc_skip, (struct disklabel *)NULL);
1482 fdcpstatus(7, fdc);
1483
1484 bp->b_error = EIO;
1485 fdfinish(fd, bp);
1486 }
1487 fdc->sc_errors++;
1488 }
1489
1490 int
1491 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1492 {
1493 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1494 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1495 int part = DISKPART(dev);
1496 struct disklabel buffer;
1497 int error;
1498
1499 DPRINTF(("fdioctl:"));
1500 switch (cmd) {
1501 case DIOCGDINFO:
1502 DPRINTF(("DIOCGDINFO\n"));
1503 #if 1
1504 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1505 return(0);
1506 #else
1507 memset(&buffer, 0, sizeof(buffer));
1508
1509 buffer.d_secpercyl = fd->sc_type->seccyl;
1510 buffer.d_type = DTYPE_FLOPPY;
1511 buffer.d_secsize = 128 << fd->sc_type->secsize;
1512
1513 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1514 return EINVAL;
1515
1516 *(struct disklabel *)addr = buffer;
1517 return 0;
1518 #endif
1519
1520 case DIOCGPART:
1521 DPRINTF(("DIOCGPART\n"));
1522 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1523 ((struct partinfo *)addr)->part =
1524 &fd->sc_dk.dk_label->d_partitions[part];
1525 return(0);
1526
1527 case DIOCWLABEL:
1528 DPRINTF(("DIOCWLABEL\n"));
1529 if ((flag & FWRITE) == 0)
1530 return EBADF;
1531 /* XXX do something */
1532 return 0;
1533
1534 case DIOCWDINFO:
1535 DPRINTF(("DIOCWDINFO\n"));
1536 if ((flag & FWRITE) == 0)
1537 return EBADF;
1538
1539 error = setdisklabel(&buffer, (struct disklabel *)addr,
1540 0, NULL);
1541 if (error)
1542 return error;
1543
1544 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1545 return error;
1546
1547 case DIOCLOCK:
1548 /*
1549 * Nothing to do here, really.
1550 */
1551 return 0; /* XXX */
1552
1553 case DIOCEJECT:
1554 DPRINTF(("DIOCEJECT\n"));
1555 if (*(int *)addr == 0) {
1556 /*
1557 * Don't force eject: check that we are the only
1558 * partition open. If so, unlock it.
1559 */
1560 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1561 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1562 fd->sc_dk.dk_openmask) {
1563 return (EBUSY);
1564 }
1565 }
1566 /* FALLTHROUGH */
1567 case ODIOCEJECT:
1568 DPRINTF(("ODIOCEJECT\n"));
1569 fd_do_eject(fdc, FDUNIT(dev));
1570 return 0;
1571
1572 default:
1573 return ENOTTY;
1574 }
1575
1576 #ifdef DIAGNOSTIC
1577 panic("fdioctl: impossible");
1578 #endif
1579 }
1580
1581 void
1582 fd_do_eject(struct fdc_softc *fdc, int unit)
1583 {
1584 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1585 0x20 | ( 1 << unit));
1586 DELAY(1); /* XXX */
1587 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1588 }
1589
1590 /*
1591 * Build disk label. For now we only create a label from what we know
1592 * from 'sc'.
1593 */
1594 static int
1595 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
1596 {
1597 struct disklabel *lp;
1598 int part;
1599
1600 DPRINTF(("fdgetdisklabel()\n"));
1601
1602 part = DISKPART(dev);
1603 lp = sc->sc_dk.dk_label;
1604 memset(lp, 0, sizeof(struct disklabel));
1605
1606 lp->d_secsize = 128 << sc->sc_type->secsize;
1607 lp->d_ntracks = sc->sc_type->heads;
1608 lp->d_nsectors = sc->sc_type->sectrac;
1609 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1610 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1611 lp->d_secperunit = sc->sc_type->size;
1612
1613 lp->d_type = DTYPE_FLOPPY;
1614 lp->d_rpm = 300; /* XXX */
1615 lp->d_interleave = 1; /* FIXME: is this OK? */
1616 lp->d_bbsize = 0;
1617 lp->d_sbsize = 0;
1618 lp->d_npartitions = part + 1;
1619 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1620 lp->d_trkseek = STEP_DELAY; /* XXX */
1621 lp->d_magic = DISKMAGIC;
1622 lp->d_magic2 = DISKMAGIC;
1623 lp->d_checksum = dkcksum(lp);
1624 lp->d_partitions[part].p_size = lp->d_secperunit;
1625 lp->d_partitions[part].p_fstype = FS_UNUSED;
1626 lp->d_partitions[part].p_fsize = 1024;
1627 lp->d_partitions[part].p_frag = 8;
1628
1629 return(0);
1630 }
1631
1632 #include <dev/cons.h>
1633
1634 /*
1635 * Mountroot hook: prompt the user to enter the root file system
1636 * floppy.
1637 */
1638 void
1639 fd_mountroot_hook(device_t dev)
1640 {
1641 struct fd_softc *fd = device_private(dev);
1642 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
1643 int c;
1644
1645 /* XXX device_unit() abuse */
1646 fd_do_eject(fdc, device_unit(dev));
1647 printf("Insert filesystem floppy and press return.");
1648 for (;;) {
1649 c = cngetc();
1650 if ((c == '\r') || (c == '\n')) {
1651 printf("\n");
1652 break;
1653 }
1654 }
1655 }
1656