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