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