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