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