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