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