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