1 1.65 andvar /* $NetBSD: fd.c,v 1.65 2023/08/28 17:53:46 andvar Exp $ */ 2 1.1 reinoud 3 1.1 reinoud /*- 4 1.1 reinoud * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 1.1 reinoud * All rights reserved. 6 1.1 reinoud * 7 1.1 reinoud * This code is derived from software contributed to The NetBSD Foundation 8 1.1 reinoud * by Charles M. Hannum. 9 1.1 reinoud * 10 1.1 reinoud * Redistribution and use in source and binary forms, with or without 11 1.1 reinoud * modification, are permitted provided that the following conditions 12 1.1 reinoud * are met: 13 1.1 reinoud * 1. Redistributions of source code must retain the above copyright 14 1.1 reinoud * notice, this list of conditions and the following disclaimer. 15 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 reinoud * notice, this list of conditions and the following disclaimer in the 17 1.1 reinoud * documentation and/or other materials provided with the distribution. 18 1.1 reinoud * 19 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 reinoud * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 reinoud * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 reinoud * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 reinoud * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 reinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 reinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 reinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 reinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 reinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 reinoud * POSSIBILITY OF SUCH DAMAGE. 30 1.1 reinoud */ 31 1.1 reinoud 32 1.1 reinoud /*- 33 1.1 reinoud * Copyright (c) 1990 The Regents of the University of California. 34 1.1 reinoud * All rights reserved. 35 1.1 reinoud * 36 1.1 reinoud * This code is derived from software contributed to Berkeley by 37 1.1 reinoud * Don Ahn. 38 1.1 reinoud * 39 1.1 reinoud * Redistribution and use in source and binary forms, with or without 40 1.1 reinoud * modification, are permitted provided that the following conditions 41 1.1 reinoud * are met: 42 1.1 reinoud * 1. Redistributions of source code must retain the above copyright 43 1.1 reinoud * notice, this list of conditions and the following disclaimer. 44 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 reinoud * notice, this list of conditions and the following disclaimer in the 46 1.1 reinoud * documentation and/or other materials provided with the distribution. 47 1.18 agc * 3. Neither the name of the University nor the names of its contributors 48 1.1 reinoud * may be used to endorse or promote products derived from this software 49 1.1 reinoud * without specific prior written permission. 50 1.1 reinoud * 51 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 1.1 reinoud * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 1.1 reinoud * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 1.1 reinoud * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 1.1 reinoud * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 1.1 reinoud * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 1.1 reinoud * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 1.1 reinoud * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 1.1 reinoud * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 1.1 reinoud * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 1.1 reinoud * SUCH DAMAGE. 62 1.1 reinoud * 63 1.1 reinoud * @(#)fd.c 7.4 (Berkeley) 5/25/91 64 1.1 reinoud * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp 65 1.1 reinoud */ 66 1.1 reinoud 67 1.1 reinoud /* 68 1.1 reinoud * Floppy formatting facilities merged from FreeBSD fd.c driver: 69 1.1 reinoud * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp 70 1.1 reinoud * which carries the same copyright/redistribution notice as shown above with 71 1.1 reinoud * the addition of the following statement before the "Redistribution and 72 1.1 reinoud * use ..." clause: 73 1.1 reinoud * 74 1.1 reinoud * Copyright (c) 1993, 1994 by 75 1.1 reinoud * jc (at) irbs.UUCP (John Capo) 76 1.1 reinoud * vak (at) zebub.msk.su (Serge Vakulenko) 77 1.1 reinoud * ache (at) astral.msk.su (Andrew A. Chernov) 78 1.1 reinoud * 79 1.1 reinoud * Copyright (c) 1993, 1994, 1995 by 80 1.1 reinoud * joerg_wunsch (at) uriah.sax.de (Joerg Wunsch) 81 1.1 reinoud * dufault (at) hda.com (Peter Dufault) 82 1.1 reinoud */ 83 1.17 lukem 84 1.17 lukem #include <sys/cdefs.h> 85 1.65 andvar __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.65 2023/08/28 17:53:46 andvar Exp $"); 86 1.1 reinoud 87 1.1 reinoud #include "opt_ddb.h" 88 1.1 reinoud 89 1.1 reinoud #include <sys/param.h> 90 1.1 reinoud #include <sys/systm.h> 91 1.1 reinoud #include <sys/callout.h> 92 1.1 reinoud #include <sys/kernel.h> 93 1.1 reinoud #include <sys/file.h> 94 1.1 reinoud #include <sys/ioctl.h> 95 1.1 reinoud #include <sys/device.h> 96 1.1 reinoud #include <sys/disklabel.h> 97 1.1 reinoud #include <sys/disk.h> 98 1.1 reinoud #include <sys/buf.h> 99 1.19 yamt #include <sys/bufq.h> 100 1.62 thorpej #include <sys/kmem.h> 101 1.1 reinoud #include <sys/uio.h> 102 1.1 reinoud #include <sys/syslog.h> 103 1.1 reinoud #include <sys/queue.h> 104 1.1 reinoud #include <sys/proc.h> 105 1.1 reinoud #include <sys/fdio.h> 106 1.6 gehenna #include <sys/conf.h> 107 1.51 dyoung #include <sys/bus.h> 108 1.1 reinoud 109 1.1 reinoud #include <uvm/uvm_extern.h> 110 1.1 reinoud 111 1.4 thorpej #include <arm/fiq.h> 112 1.4 thorpej 113 1.1 reinoud #include <machine/cpu.h> 114 1.3 thorpej #include <machine/intr.h> 115 1.1 reinoud #include <machine/io.h> 116 1.4 thorpej 117 1.1 reinoud #include <arm/iomd/iomdreg.h> 118 1.4 thorpej #include <arm/iomd/iomdvar.h> 119 1.4 thorpej 120 1.1 reinoud #include <acorn32/mainbus/piocvar.h> 121 1.1 reinoud #include <acorn32/mainbus/fdreg.h> 122 1.1 reinoud 123 1.1 reinoud #include "locators.h" 124 1.1 reinoud 125 1.1 reinoud #define NE7CMD_CONFIGURE 0x13 126 1.1 reinoud 127 1.1 reinoud #define FDUNIT(dev) (minor(dev) / 8) 128 1.1 reinoud #define FDTYPE(dev) (minor(dev) % 8) 129 1.1 reinoud 130 1.27 reinoud /* (mis)use device use flag to identify format operation */ 131 1.27 reinoud #define B_FORMAT B_DEVPRIVATE 132 1.1 reinoud 133 1.1 reinoud enum fdc_state { 134 1.1 reinoud DEVIDLE = 0, 135 1.1 reinoud MOTORWAIT, 136 1.1 reinoud DOSEEK, 137 1.1 reinoud SEEKWAIT, 138 1.1 reinoud SEEKTIMEDOUT, 139 1.1 reinoud SEEKCOMPLETE, 140 1.1 reinoud DOIO, 141 1.1 reinoud IOCOMPLETE, 142 1.1 reinoud IOTIMEDOUT, 143 1.1 reinoud DORESET, 144 1.1 reinoud RESETCOMPLETE, 145 1.1 reinoud RESETTIMEDOUT, 146 1.1 reinoud DORECAL, 147 1.1 reinoud RECALWAIT, 148 1.1 reinoud RECALTIMEDOUT, 149 1.1 reinoud RECALCOMPLETE, 150 1.1 reinoud }; 151 1.1 reinoud 152 1.1 reinoud /* software state, per controller */ 153 1.1 reinoud struct fdc_softc { 154 1.52 chs device_t sc_dev; /* boilerplate */ 155 1.1 reinoud void *sc_ih; 156 1.1 reinoud 157 1.1 reinoud bus_space_tag_t sc_iot; /* ISA i/o space identifier */ 158 1.1 reinoud bus_space_handle_t sc_ioh; /* ISA io handle */ 159 1.1 reinoud 160 1.1 reinoud struct callout sc_timo_ch; /* timeout callout */ 161 1.1 reinoud struct callout sc_intr_ch; /* pseudo-intr callout */ 162 1.1 reinoud 163 1.4 thorpej /* ...for pseudo-DMA... */ 164 1.4 thorpej struct fiqhandler sc_fh; /* FIQ handler descriptor */ 165 1.4 thorpej struct fiqregs sc_fr; /* FIQ handler reg context */ 166 1.1 reinoud int sc_drq; 167 1.1 reinoud 168 1.1 reinoud struct fd_softc *sc_fd[4]; /* pointers to children */ 169 1.1 reinoud TAILQ_HEAD(drivehead, fd_softc) sc_drives; 170 1.1 reinoud enum fdc_state sc_state; 171 1.1 reinoud int sc_errors; /* number of retries so far */ 172 1.1 reinoud u_char sc_status[7]; /* copy of registers */ 173 1.1 reinoud }; 174 1.1 reinoud 175 1.1 reinoud /* controller driver configuration */ 176 1.50 matt int fdcprobe(device_t, cfdata_t, void *); 177 1.43 dsl int fdprint(void *, const char *); 178 1.50 matt void fdcattach(device_t, device_t, void *); 179 1.1 reinoud 180 1.52 chs CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc), 181 1.10 thorpej fdcprobe, fdcattach, NULL, NULL); 182 1.1 reinoud 183 1.1 reinoud /* 184 1.1 reinoud * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 185 1.1 reinoud * we tell them apart. 186 1.1 reinoud */ 187 1.1 reinoud struct fd_type { 188 1.1 reinoud int sectrac; /* sectors per track */ 189 1.1 reinoud int heads; /* number of heads */ 190 1.1 reinoud int seccyl; /* sectors per cylinder */ 191 1.1 reinoud int secsize; /* size code for sectors */ 192 1.1 reinoud int datalen; /* data len when secsize = 0 */ 193 1.1 reinoud int steprate; /* step rate and head unload time */ 194 1.1 reinoud int gap1; /* gap len between sectors */ 195 1.1 reinoud int gap2; /* formatting gap */ 196 1.1 reinoud int cyls; /* total num of cylinders */ 197 1.1 reinoud int size; /* size of disk in sectors */ 198 1.1 reinoud int step; /* steps per cylinder */ 199 1.1 reinoud int rate; /* transfer speed code */ 200 1.1 reinoud u_char fillbyte; /* format fill byte */ 201 1.1 reinoud u_char interleave; /* interleave factor (formatting) */ 202 1.20 he const char *name; 203 1.1 reinoud }; 204 1.1 reinoud 205 1.1 reinoud /* The order of entries in the following table is important -- BEWARE! */ 206 1.1 reinoud struct fd_type fd_types[] = { 207 1.1 reinoud { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */ 208 1.1 reinoud { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */ 209 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */ 210 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */ 211 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */ 212 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */ 213 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */ 214 1.1 reinoud }; 215 1.1 reinoud 216 1.1 reinoud /* software state, per disk (with up to 4 disks per ctlr) */ 217 1.1 reinoud struct fd_softc { 218 1.52 chs device_t sc_dev; 219 1.1 reinoud struct disk sc_dk; 220 1.1 reinoud 221 1.1 reinoud struct fd_type *sc_deftype; /* default type descriptor */ 222 1.1 reinoud struct fd_type *sc_type; /* current type descriptor */ 223 1.1 reinoud struct fd_type sc_type_copy; /* copy for fiddling when formatting */ 224 1.1 reinoud 225 1.1 reinoud struct callout sc_motoron_ch; 226 1.1 reinoud struct callout sc_motoroff_ch; 227 1.1 reinoud 228 1.1 reinoud daddr_t sc_blkno; /* starting block number */ 229 1.1 reinoud int sc_bcount; /* byte count left */ 230 1.1 reinoud int sc_opts; /* user-set options */ 231 1.1 reinoud int sc_skip; /* bytes already transferred */ 232 1.1 reinoud int sc_nblks; /* number of blocks currently transferring */ 233 1.1 reinoud int sc_nbytes; /* number of bytes currently transferring */ 234 1.1 reinoud 235 1.1 reinoud int sc_drive; /* physical unit number */ 236 1.1 reinoud int sc_flags; 237 1.1 reinoud #define FD_OPEN 0x01 /* it's open */ 238 1.1 reinoud #define FD_MOTOR 0x02 /* motor should be on */ 239 1.1 reinoud #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 240 1.1 reinoud int sc_cylin; /* where we think the head is */ 241 1.1 reinoud 242 1.1 reinoud void *sc_sdhook; /* saved shutdown hook for drive. */ 243 1.1 reinoud 244 1.1 reinoud TAILQ_ENTRY(fd_softc) sc_drivechain; 245 1.1 reinoud int sc_ops; /* I/O ops since last switch */ 246 1.21 yamt struct bufq_state *sc_q;/* pending I/O requests */ 247 1.1 reinoud int sc_active; /* number of active I/O operations */ 248 1.1 reinoud }; 249 1.1 reinoud 250 1.1 reinoud /* floppy driver configuration */ 251 1.50 matt int fdprobe(device_t, cfdata_t, void *); 252 1.50 matt void fdattach(device_t, device_t, void *); 253 1.1 reinoud 254 1.4 thorpej extern char floppy_read_fiq[], floppy_read_fiq_end[]; 255 1.4 thorpej extern char floppy_write_fiq[], floppy_write_fiq_end[]; 256 1.1 reinoud 257 1.52 chs CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc), 258 1.10 thorpej fdprobe, fdattach, NULL, NULL); 259 1.1 reinoud 260 1.1 reinoud extern struct cfdriver fd_cd; 261 1.1 reinoud 262 1.6 gehenna dev_type_open(fdopen); 263 1.6 gehenna dev_type_close(fdclose); 264 1.6 gehenna dev_type_read(fdread); 265 1.6 gehenna dev_type_write(fdwrite); 266 1.6 gehenna dev_type_ioctl(fdioctl); 267 1.6 gehenna dev_type_strategy(fdstrategy); 268 1.6 gehenna 269 1.6 gehenna const struct bdevsw fd_bdevsw = { 270 1.53 dholland .d_open = fdopen, 271 1.53 dholland .d_close = fdclose, 272 1.53 dholland .d_strategy = fdstrategy, 273 1.53 dholland .d_ioctl = fdioctl, 274 1.53 dholland .d_dump = nodump, 275 1.53 dholland .d_psize = nosize, 276 1.54 dholland .d_discard = nodiscard, 277 1.53 dholland .d_flag = D_DISK 278 1.6 gehenna }; 279 1.6 gehenna 280 1.6 gehenna const struct cdevsw fd_cdevsw = { 281 1.53 dholland .d_open = fdopen, 282 1.53 dholland .d_close = fdclose, 283 1.53 dholland .d_read = fdread, 284 1.53 dholland .d_write = fdwrite, 285 1.53 dholland .d_ioctl = fdioctl, 286 1.53 dholland .d_stop = nostop, 287 1.53 dholland .d_tty = notty, 288 1.53 dholland .d_poll = nopoll, 289 1.53 dholland .d_mmap = nommap, 290 1.53 dholland .d_kqfilter = nokqfilter, 291 1.55 dholland .d_discard = nodiscard, 292 1.53 dholland .d_flag = D_DISK 293 1.6 gehenna }; 294 1.6 gehenna 295 1.43 dsl void fdgetdisklabel(struct fd_softc *); 296 1.43 dsl int fd_get_parms(struct fd_softc *); 297 1.43 dsl void fdstart(struct fd_softc *); 298 1.1 reinoud 299 1.58 mlelstv struct dkdriver fddkdriver = { 300 1.58 mlelstv .d_strategy = fdstrategy 301 1.58 mlelstv }; 302 1.1 reinoud 303 1.46 cegger struct fd_type *fd_nvtotype(const char *, int, int); 304 1.43 dsl void fd_set_motor(struct fdc_softc *fdc, int reset); 305 1.43 dsl void fd_motor_off(void *arg); 306 1.43 dsl void fd_motor_on(void *arg); 307 1.43 dsl int fdcresult(struct fdc_softc *fdc); 308 1.43 dsl int out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x); 309 1.43 dsl void fdcstart(struct fdc_softc *fdc); 310 1.50 matt void fdcstatus(device_t dv, int n, const char *s); 311 1.43 dsl void fdctimeout(void *arg); 312 1.43 dsl void fdcpseudointr(void *arg); 313 1.43 dsl int fdcintr(void *); 314 1.43 dsl void fdcretry(struct fdc_softc *fdc); 315 1.43 dsl void fdfinish(struct fd_softc *fd, struct buf *bp); 316 1.60 mrg static struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t); 317 1.43 dsl int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *); 318 1.1 reinoud 319 1.1 reinoud int 320 1.50 matt fdcprobe(device_t parent, cfdata_t cf, void *aux) 321 1.1 reinoud { 322 1.1 reinoud struct pioc_attach_args *pa = aux; 323 1.1 reinoud bus_space_tag_t iot; 324 1.1 reinoud bus_space_handle_t ioh; 325 1.1 reinoud int rv; 326 1.1 reinoud 327 1.1 reinoud if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0) 328 1.1 reinoud return(0); 329 1.1 reinoud 330 1.1 reinoud iot = pa->pa_iot; 331 1.1 reinoud rv = 0; 332 1.1 reinoud 333 1.1 reinoud /* Map the i/o space. */ 334 1.1 reinoud if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 335 1.1 reinoud return 0; 336 1.1 reinoud 337 1.1 reinoud /* reset */ 338 1.1 reinoud bus_space_write_2(iot, ioh, fdout, 0); 339 1.1 reinoud delay(100); 340 1.1 reinoud bus_space_write_2(iot, ioh, fdout, FDO_FRST); 341 1.1 reinoud 342 1.1 reinoud /* see if it can handle a command */ 343 1.1 reinoud if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) 344 1.1 reinoud goto out; 345 1.1 reinoud out_fdc(iot, ioh, 0xdf); 346 1.1 reinoud out_fdc(iot, ioh, 2); 347 1.1 reinoud 348 1.1 reinoud rv = 1; 349 1.1 reinoud pa->pa_iosize = FDC_NPORT; 350 1.1 reinoud 351 1.1 reinoud out: 352 1.1 reinoud bus_space_unmap(iot, ioh, FDC_NPORT); 353 1.1 reinoud return rv; 354 1.1 reinoud } 355 1.1 reinoud 356 1.1 reinoud /* 357 1.1 reinoud * Arguments passed between fdcattach and fdprobe. 358 1.1 reinoud */ 359 1.1 reinoud struct fdc_attach_args { 360 1.1 reinoud int fa_drive; 361 1.1 reinoud struct fd_type *fa_deftype; 362 1.1 reinoud }; 363 1.1 reinoud 364 1.1 reinoud /* 365 1.1 reinoud * Print the location of a disk drive (called just before attaching the 366 1.1 reinoud * the drive). If `fdc' is not NULL, the drive was found but was not 367 1.1 reinoud * in the system config file; print the drive name as well. 368 1.1 reinoud * Return QUIET (config_find ignores this if the device was configured) to 369 1.1 reinoud * avoid printing `fdN not configured' messages. 370 1.1 reinoud */ 371 1.1 reinoud int 372 1.44 dsl fdprint(void *aux, const char *fdc) 373 1.1 reinoud { 374 1.1 reinoud register struct fdc_attach_args *fa = aux; 375 1.1 reinoud 376 1.1 reinoud if (!fdc) 377 1.13 thorpej aprint_normal(" drive %d", fa->fa_drive); 378 1.1 reinoud return QUIET; 379 1.1 reinoud } 380 1.1 reinoud 381 1.1 reinoud void 382 1.50 matt fdcattach(device_t parent, device_t self, void *aux) 383 1.1 reinoud { 384 1.50 matt struct fdc_softc *fdc = device_private(self); 385 1.1 reinoud bus_space_tag_t iot; 386 1.1 reinoud bus_space_handle_t ioh; 387 1.1 reinoud struct pioc_attach_args *pa = aux; 388 1.1 reinoud struct fdc_attach_args fa; 389 1.1 reinoud int type; 390 1.1 reinoud 391 1.1 reinoud iot = pa->pa_iot; 392 1.1 reinoud 393 1.1 reinoud /* Re-map the I/O space. */ 394 1.1 reinoud if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 395 1.1 reinoud panic("fdcattach: couldn't map I/O ports"); 396 1.1 reinoud 397 1.52 chs fdc->sc_dev = self; 398 1.1 reinoud fdc->sc_iot = iot; 399 1.1 reinoud fdc->sc_ioh = ioh; 400 1.1 reinoud 401 1.1 reinoud fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq; 402 1.1 reinoud fdc->sc_state = DEVIDLE; 403 1.1 reinoud TAILQ_INIT(&fdc->sc_drives); 404 1.1 reinoud 405 1.1 reinoud printf("\n"); 406 1.1 reinoud 407 1.29 ad callout_init(&fdc->sc_timo_ch, 0); 408 1.29 ad callout_init(&fdc->sc_intr_ch, 0); 409 1.1 reinoud 410 1.50 matt fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc", fdcintr, fdc); 411 1.1 reinoud if (!fdc->sc_ih) 412 1.50 matt panic("%s: Cannot claim IRQ %d", 413 1.50 matt device_xname(self), pa->pa_irq); 414 1.1 reinoud 415 1.1 reinoud #if 0 416 1.1 reinoud /* 417 1.1 reinoud * The NVRAM info only tells us about the first two disks on the 418 1.1 reinoud * `primary' floppy controller. 419 1.1 reinoud */ 420 1.52 chs if (device_unit(fdc->sc_dev) == 0) 421 1.1 reinoud type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */ 422 1.1 reinoud else 423 1.1 reinoud type = -1; 424 1.1 reinoud #endif 425 1.1 reinoud type = 0x10; /* XXX - hardcoded for 1 floppy */ 426 1.1 reinoud 427 1.1 reinoud /* physical limit: four drives per controller. */ 428 1.1 reinoud for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 429 1.1 reinoud if (type >= 0 && fa.fa_drive < 2) 430 1.52 chs fa.fa_deftype = fd_nvtotype(device_xname(fdc->sc_dev), 431 1.1 reinoud type, fa.fa_drive); 432 1.1 reinoud else 433 1.1 reinoud fa.fa_deftype = NULL; /* unknown */ 434 1.64 thorpej (void)config_found(self, (void *)&fa, fdprint, CFARGS_NONE); 435 1.1 reinoud } 436 1.1 reinoud } 437 1.1 reinoud 438 1.1 reinoud int 439 1.50 matt fdprobe(device_t parent, cfdata_t cf, void *aux) 440 1.1 reinoud { 441 1.50 matt struct fdc_softc *fdc = device_private(parent); 442 1.1 reinoud struct fdc_attach_args *fa = aux; 443 1.1 reinoud int drive = fa->fa_drive; 444 1.1 reinoud bus_space_tag_t iot = fdc->sc_iot; 445 1.1 reinoud bus_space_handle_t ioh = fdc->sc_ioh; 446 1.1 reinoud int n; 447 1.1 reinoud 448 1.1 reinoud if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT 449 1.1 reinoud && cf->cf_loc[FDCCF_DRIVE] != drive) 450 1.1 reinoud return 0; 451 1.1 reinoud /* 452 1.1 reinoud * XXX 453 1.1 reinoud * This is to work around some odd interactions between this driver 454 1.1 reinoud * and SMC Ethernet cards. 455 1.1 reinoud */ 456 1.1 reinoud 457 1.1 reinoud /* Don't need this for arm32 port but leave for the time being (it won't hurt) */ 458 1.1 reinoud 459 1.1 reinoud if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2) 460 1.1 reinoud return 0; 461 1.1 reinoud 462 1.1 reinoud /* select drive and turn on motor */ 463 1.1 reinoud bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive)); 464 1.1 reinoud /* wait for motor to spin up */ 465 1.1 reinoud delay(250000); 466 1.1 reinoud out_fdc(iot, ioh, NE7CMD_RECAL); 467 1.1 reinoud out_fdc(iot, ioh, drive); 468 1.1 reinoud /* wait for recalibrate */ 469 1.1 reinoud delay(2000000); 470 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI); 471 1.1 reinoud n = fdcresult(fdc); 472 1.1 reinoud #ifdef FD_DEBUG 473 1.1 reinoud { 474 1.1 reinoud int i; 475 1.1 reinoud printf("fdprobe: status"); 476 1.1 reinoud for (i = 0; i < n; i++) 477 1.1 reinoud printf(" %x", fdc->sc_status[i]); 478 1.1 reinoud printf("\n"); 479 1.1 reinoud } 480 1.1 reinoud #endif 481 1.1 reinoud /* turn off motor */ 482 1.1 reinoud bus_space_write_1(iot, ioh, fdout, FDO_FRST); 483 1.1 reinoud 484 1.1 reinoud if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 485 1.1 reinoud return 0; 486 1.1 reinoud 487 1.1 reinoud return 1; 488 1.1 reinoud } 489 1.1 reinoud 490 1.1 reinoud /* 491 1.1 reinoud * Controller is working, and drive responded. Attach it. 492 1.1 reinoud */ 493 1.1 reinoud void 494 1.50 matt fdattach(device_t parent, device_t self, void *aux) 495 1.1 reinoud { 496 1.50 matt struct fdc_softc *fdc = device_private(parent); 497 1.50 matt struct fd_softc *fd = device_private(self); 498 1.1 reinoud struct fdc_attach_args *fa = aux; 499 1.1 reinoud struct fd_type *type = fa->fa_deftype; 500 1.1 reinoud int drive = fa->fa_drive; 501 1.1 reinoud 502 1.52 chs fd->sc_dev = self; 503 1.52 chs 504 1.29 ad callout_init(&fd->sc_motoron_ch, 0); 505 1.29 ad callout_init(&fd->sc_motoroff_ch, 0); 506 1.1 reinoud 507 1.1 reinoud /* XXX Allow `flags' to override device type? */ 508 1.1 reinoud 509 1.1 reinoud if (type) 510 1.1 reinoud printf(": %s %d cyl, %d head, %d sec\n", type->name, 511 1.1 reinoud type->cyls, type->heads, type->sectrac); 512 1.1 reinoud else 513 1.1 reinoud printf(": density unknown\n"); 514 1.1 reinoud 515 1.21 yamt bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 516 1.1 reinoud fd->sc_cylin = -1; 517 1.1 reinoud fd->sc_drive = drive; 518 1.1 reinoud fd->sc_deftype = type; 519 1.1 reinoud fdc->sc_fd[drive] = fd; 520 1.1 reinoud 521 1.1 reinoud /* 522 1.1 reinoud * Initialize and attach the disk structure. 523 1.1 reinoud */ 524 1.52 chs disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver); 525 1.1 reinoud disk_attach(&fd->sc_dk); 526 1.1 reinoud 527 1.1 reinoud /* Needed to power off if the motor is on when we halt. */ 528 1.1 reinoud 529 1.1 reinoud } 530 1.1 reinoud 531 1.1 reinoud /* 532 1.1 reinoud * Translate nvram type into internal data structure. Return NULL for 533 1.1 reinoud * none/unknown/unusable. 534 1.1 reinoud */ 535 1.1 reinoud struct fd_type * 536 1.46 cegger fd_nvtotype(const char *fdc, int nvraminfo, int drive) 537 1.1 reinoud { 538 1.1 reinoud int type; 539 1.1 reinoud 540 1.1 reinoud type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 541 1.1 reinoud switch (type) { 542 1.1 reinoud #ifndef RC7500 543 1.1 reinoud case 0x00 : 544 1.1 reinoud return NULL; 545 1.1 reinoud #else 546 1.1 reinoud case 0x00 : 547 1.1 reinoud #endif /* !RC7500 */ 548 1.1 reinoud case 0x10 : 549 1.1 reinoud return &fd_types[0]; 550 1.1 reinoud default: 551 1.1 reinoud printf("%s: drive %d: unknown device type 0x%x\n", 552 1.1 reinoud fdc, drive, type); 553 1.1 reinoud return NULL; 554 1.1 reinoud } 555 1.1 reinoud } 556 1.1 reinoud 557 1.60 mrg static struct fd_type * 558 1.44 dsl fd_dev_to_type(struct fd_softc *fd, dev_t dev) 559 1.1 reinoud { 560 1.1 reinoud int type = FDTYPE(dev); 561 1.1 reinoud 562 1.1 reinoud if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 563 1.1 reinoud return NULL; 564 1.1 reinoud return type ? &fd_types[type - 1] : fd->sc_deftype; 565 1.1 reinoud } 566 1.1 reinoud 567 1.1 reinoud void 568 1.39 cegger fdstrategy(struct buf *bp) 569 1.1 reinoud { 570 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(bp->b_dev)); 571 1.1 reinoud int sz; 572 1.1 reinoud int s; 573 1.1 reinoud 574 1.1 reinoud /* Valid unit, controller, and request? */ 575 1.1 reinoud if (bp->b_blkno < 0 || 576 1.1 reinoud ((bp->b_bcount % FDC_BSIZE) != 0 && 577 1.1 reinoud (bp->b_flags & B_FORMAT) == 0)) { 578 1.1 reinoud bp->b_error = EINVAL; 579 1.30 ad goto done; 580 1.1 reinoud } 581 1.1 reinoud 582 1.1 reinoud /* If it's a null transfer, return immediately. */ 583 1.1 reinoud if (bp->b_bcount == 0) 584 1.1 reinoud goto done; 585 1.1 reinoud 586 1.1 reinoud sz = howmany(bp->b_bcount, FDC_BSIZE); 587 1.1 reinoud 588 1.1 reinoud if (bp->b_blkno + sz > fd->sc_type->size) { 589 1.1 reinoud sz = fd->sc_type->size - bp->b_blkno; 590 1.1 reinoud if (sz == 0) { 591 1.1 reinoud /* If exactly at end of disk, return EOF. */ 592 1.1 reinoud goto done; 593 1.1 reinoud } 594 1.1 reinoud if (sz < 0) { 595 1.1 reinoud /* If past end of disk, return EINVAL. */ 596 1.1 reinoud bp->b_error = EINVAL; 597 1.30 ad goto done; 598 1.1 reinoud } 599 1.1 reinoud /* Otherwise, truncate request. */ 600 1.1 reinoud bp->b_bcount = sz << DEV_BSHIFT; 601 1.1 reinoud } 602 1.1 reinoud 603 1.1 reinoud bp->b_rawblkno = bp->b_blkno; 604 1.1 reinoud bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 605 1.1 reinoud 606 1.1 reinoud #ifdef FD_DEBUG 607 1.65 andvar printf("fdstrategy: b_blkno %lld b_bcount %d blkno %lld cylin %d sz %d\n", 608 1.1 reinoud bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz); 609 1.1 reinoud #endif 610 1.1 reinoud 611 1.1 reinoud /* Queue transfer on drive, activate drive and controller if idle. */ 612 1.1 reinoud s = splbio(); 613 1.41 yamt bufq_put(fd->sc_q, bp); 614 1.1 reinoud callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 615 1.1 reinoud if (fd->sc_active == 0) 616 1.1 reinoud fdstart(fd); 617 1.1 reinoud #ifdef DIAGNOSTIC 618 1.1 reinoud else { 619 1.47 dyoung struct fdc_softc *fdc = 620 1.52 chs device_private(device_parent(fd->sc_dev)); 621 1.1 reinoud if (fdc->sc_state == DEVIDLE) { 622 1.1 reinoud printf("fdstrategy: controller inactive\n"); 623 1.1 reinoud fdcstart(fdc); 624 1.1 reinoud } 625 1.1 reinoud } 626 1.1 reinoud #endif 627 1.1 reinoud splx(s); 628 1.1 reinoud return; 629 1.1 reinoud 630 1.1 reinoud done: 631 1.1 reinoud /* Toss transfer; we're done early. */ 632 1.1 reinoud bp->b_resid = bp->b_bcount; 633 1.1 reinoud biodone(bp); 634 1.1 reinoud } 635 1.1 reinoud 636 1.1 reinoud void 637 1.44 dsl fdstart(struct fd_softc *fd) 638 1.1 reinoud { 639 1.52 chs struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 640 1.1 reinoud int active = fdc->sc_drives.tqh_first != 0; 641 1.1 reinoud 642 1.1 reinoud /* Link into controller queue. */ 643 1.1 reinoud fd->sc_active = 1; 644 1.1 reinoud TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 645 1.1 reinoud 646 1.1 reinoud /* If controller not already active, start it. */ 647 1.1 reinoud if (!active) 648 1.1 reinoud fdcstart(fdc); 649 1.1 reinoud } 650 1.1 reinoud 651 1.1 reinoud void 652 1.44 dsl fdfinish(struct fd_softc *fd, struct buf *bp) 653 1.1 reinoud { 654 1.52 chs struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 655 1.1 reinoud 656 1.1 reinoud /* 657 1.1 reinoud * Move this drive to the end of the queue to give others a `fair' 658 1.1 reinoud * chance. We only force a switch if N operations are completed while 659 1.1 reinoud * another drive is waiting to be serviced, since there is a long motor 660 1.1 reinoud * startup delay whenever we switch. 661 1.1 reinoud */ 662 1.41 yamt (void)bufq_get(fd->sc_q); 663 1.1 reinoud if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 664 1.1 reinoud fd->sc_ops = 0; 665 1.1 reinoud TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 666 1.41 yamt if (bufq_peek(fd->sc_q) != NULL) 667 1.1 reinoud TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 668 1.1 reinoud else 669 1.1 reinoud fd->sc_active = 0; 670 1.1 reinoud } 671 1.1 reinoud bp->b_resid = fd->sc_bcount; 672 1.1 reinoud fd->sc_skip = 0; 673 1.1 reinoud 674 1.1 reinoud biodone(bp); 675 1.1 reinoud /* turn off motor 5s from now */ 676 1.1 reinoud callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 677 1.1 reinoud fdc->sc_state = DEVIDLE; 678 1.1 reinoud } 679 1.1 reinoud 680 1.1 reinoud int 681 1.44 dsl fdread(dev_t dev, struct uio *uio, int flags) 682 1.1 reinoud { 683 1.1 reinoud 684 1.1 reinoud return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 685 1.1 reinoud } 686 1.1 reinoud 687 1.1 reinoud int 688 1.44 dsl fdwrite(dev_t dev, struct uio *uio, int flags) 689 1.1 reinoud { 690 1.1 reinoud 691 1.1 reinoud return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 692 1.1 reinoud } 693 1.1 reinoud 694 1.1 reinoud void 695 1.44 dsl fd_set_motor(struct fdc_softc *fdc, int reset) 696 1.1 reinoud { 697 1.1 reinoud struct fd_softc *fd; 698 1.1 reinoud u_char status; 699 1.1 reinoud int n; 700 1.1 reinoud 701 1.1 reinoud if ((fd = fdc->sc_drives.tqh_first) != NULL) 702 1.1 reinoud status = fd->sc_drive; 703 1.1 reinoud else 704 1.1 reinoud status = 0; 705 1.1 reinoud if (!reset) 706 1.1 reinoud status |= FDO_FRST | FDO_FDMAEN; 707 1.1 reinoud for (n = 0; n < 4; n++) 708 1.1 reinoud if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 709 1.1 reinoud status |= FDO_MOEN(n); 710 1.1 reinoud bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status); 711 1.1 reinoud } 712 1.1 reinoud 713 1.1 reinoud void 714 1.44 dsl fd_motor_off(void *arg) 715 1.1 reinoud { 716 1.1 reinoud struct fd_softc *fd = arg; 717 1.1 reinoud int s; 718 1.1 reinoud 719 1.1 reinoud s = splbio(); 720 1.1 reinoud fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 721 1.52 chs fd_set_motor(device_private(device_parent(fd->sc_dev)), 0); 722 1.1 reinoud splx(s); 723 1.1 reinoud } 724 1.1 reinoud 725 1.1 reinoud void 726 1.44 dsl fd_motor_on(void *arg) 727 1.1 reinoud { 728 1.1 reinoud struct fd_softc *fd = arg; 729 1.52 chs struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 730 1.1 reinoud int s; 731 1.1 reinoud 732 1.1 reinoud s = splbio(); 733 1.1 reinoud fd->sc_flags &= ~FD_MOTOR_WAIT; 734 1.1 reinoud if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 735 1.1 reinoud (void) fdcintr(fdc); 736 1.1 reinoud splx(s); 737 1.1 reinoud } 738 1.1 reinoud 739 1.1 reinoud int 740 1.44 dsl fdcresult(struct fdc_softc *fdc) 741 1.1 reinoud { 742 1.1 reinoud bus_space_tag_t iot = fdc->sc_iot; 743 1.1 reinoud bus_space_handle_t ioh = fdc->sc_ioh; 744 1.1 reinoud u_char i; 745 1.1 reinoud int j = 100000, 746 1.1 reinoud n = 0; 747 1.1 reinoud 748 1.1 reinoud for (; j; j--) { 749 1.1 reinoud i = bus_space_read_1(iot, ioh, fdsts) & 750 1.1 reinoud (NE7_DIO | NE7_RQM | NE7_CB); 751 1.1 reinoud if (i == NE7_RQM) 752 1.1 reinoud return n; 753 1.1 reinoud if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 754 1.1 reinoud if (n >= sizeof(fdc->sc_status)) { 755 1.1 reinoud log(LOG_ERR, "fdcresult: overrun\n"); 756 1.1 reinoud return -1; 757 1.1 reinoud } 758 1.1 reinoud fdc->sc_status[n++] = 759 1.1 reinoud bus_space_read_1(iot, ioh, fddata); 760 1.1 reinoud } 761 1.1 reinoud delay(10); 762 1.1 reinoud } 763 1.1 reinoud log(LOG_ERR, "fdcresult: timeout\n"); 764 1.1 reinoud return -1; 765 1.1 reinoud } 766 1.1 reinoud 767 1.1 reinoud int 768 1.44 dsl out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x) 769 1.1 reinoud { 770 1.1 reinoud int i = 100000; 771 1.1 reinoud 772 1.1 reinoud while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 773 1.1 reinoud if (i <= 0) 774 1.1 reinoud return -1; 775 1.1 reinoud while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 776 1.1 reinoud if (i <= 0) 777 1.1 reinoud return -1; 778 1.1 reinoud bus_space_write_2(iot, ioh, fddata, x); 779 1.1 reinoud return 0; 780 1.1 reinoud } 781 1.1 reinoud 782 1.1 reinoud int 783 1.39 cegger fdopen(dev_t dev, int flags, int mode, struct lwp *l) 784 1.1 reinoud { 785 1.1 reinoud struct fd_softc *fd; 786 1.1 reinoud struct fd_type *type; 787 1.1 reinoud 788 1.39 cegger fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 789 1.39 cegger if (fd == NULL) 790 1.1 reinoud return ENXIO; 791 1.1 reinoud type = fd_dev_to_type(fd, dev); 792 1.1 reinoud if (type == NULL) 793 1.1 reinoud return ENXIO; 794 1.1 reinoud 795 1.1 reinoud if ((fd->sc_flags & FD_OPEN) != 0 && 796 1.1 reinoud memcmp(fd->sc_type, type, sizeof(*type))) 797 1.1 reinoud return EBUSY; 798 1.1 reinoud 799 1.1 reinoud fd->sc_type_copy = *type; 800 1.1 reinoud fd->sc_type = &fd->sc_type_copy; 801 1.1 reinoud fd->sc_cylin = -1; 802 1.1 reinoud fd->sc_flags |= FD_OPEN; 803 1.1 reinoud 804 1.1 reinoud return 0; 805 1.1 reinoud } 806 1.1 reinoud 807 1.1 reinoud int 808 1.39 cegger fdclose(dev_t dev, int flags, int mode, struct lwp *l) 809 1.1 reinoud { 810 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 811 1.1 reinoud 812 1.1 reinoud fd->sc_flags &= ~FD_OPEN; 813 1.1 reinoud fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 814 1.1 reinoud return 0; 815 1.1 reinoud } 816 1.1 reinoud 817 1.1 reinoud void 818 1.44 dsl fdcstart(struct fdc_softc *fdc) 819 1.1 reinoud { 820 1.1 reinoud 821 1.1 reinoud #ifdef DIAGNOSTIC 822 1.1 reinoud /* only got here if controller's drive queue was inactive; should 823 1.1 reinoud be in idle state */ 824 1.1 reinoud if (fdc->sc_state != DEVIDLE) { 825 1.1 reinoud printf("fdcstart: not idle\n"); 826 1.1 reinoud return; 827 1.1 reinoud } 828 1.1 reinoud #endif 829 1.1 reinoud (void) fdcintr(fdc); 830 1.1 reinoud } 831 1.1 reinoud 832 1.40 christos static void 833 1.40 christos fdcpstatus(int n, struct fdc_softc *fdc) 834 1.1 reinoud { 835 1.1 reinoud char bits[64]; 836 1.1 reinoud 837 1.1 reinoud switch (n) { 838 1.1 reinoud case 0: 839 1.1 reinoud printf("\n"); 840 1.1 reinoud break; 841 1.1 reinoud case 2: 842 1.40 christos snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 843 1.40 christos printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]); 844 1.1 reinoud break; 845 1.1 reinoud case 7: 846 1.40 christos snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 847 1.40 christos printf(" (st0 %s", bits); 848 1.40 christos snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]); 849 1.40 christos printf(" st1 %s", bits); 850 1.40 christos snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]); 851 1.40 christos printf(" st2 %s", bits); 852 1.1 reinoud printf(" cyl %d head %d sec %d)\n", 853 1.1 reinoud fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 854 1.1 reinoud break; 855 1.1 reinoud #ifdef DIAGNOSTIC 856 1.1 reinoud default: 857 1.1 reinoud printf("\nfdcstatus: weird size"); 858 1.1 reinoud break; 859 1.1 reinoud #endif 860 1.1 reinoud } 861 1.1 reinoud } 862 1.1 reinoud 863 1.1 reinoud void 864 1.50 matt fdcstatus(device_t dv, int n, const char *s) 865 1.40 christos { 866 1.52 chs struct fdc_softc *fdc = device_private(device_parent(dv)); 867 1.40 christos 868 1.40 christos if (n == 0) { 869 1.40 christos out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 870 1.40 christos (void) fdcresult(fdc); 871 1.40 christos n = 2; 872 1.40 christos } 873 1.40 christos 874 1.46 cegger printf("%s: %s", device_xname(dv), s); 875 1.40 christos fdcpstatus(n, fdc); 876 1.40 christos } 877 1.40 christos 878 1.40 christos void 879 1.44 dsl fdctimeout(void *arg) 880 1.1 reinoud { 881 1.1 reinoud struct fdc_softc *fdc = arg; 882 1.1 reinoud struct fd_softc *fd = fdc->sc_drives.tqh_first; 883 1.1 reinoud int s; 884 1.1 reinoud 885 1.1 reinoud s = splbio(); 886 1.1 reinoud #ifdef DEBUG 887 1.1 reinoud log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state); 888 1.1 reinoud #endif 889 1.52 chs fdcstatus(fd->sc_dev, 0, "timeout"); 890 1.1 reinoud 891 1.41 yamt if (bufq_peek(fd->sc_q) != NULL) 892 1.1 reinoud fdc->sc_state++; 893 1.1 reinoud else 894 1.1 reinoud fdc->sc_state = DEVIDLE; 895 1.1 reinoud 896 1.1 reinoud (void) fdcintr(fdc); 897 1.1 reinoud splx(s); 898 1.1 reinoud } 899 1.1 reinoud 900 1.1 reinoud void 901 1.44 dsl fdcpseudointr(void *arg) 902 1.1 reinoud { 903 1.1 reinoud int s; 904 1.1 reinoud 905 1.1 reinoud /* Just ensure it has the right spl. */ 906 1.1 reinoud s = splbio(); 907 1.1 reinoud (void) fdcintr(arg); 908 1.1 reinoud splx(s); 909 1.1 reinoud } 910 1.1 reinoud 911 1.1 reinoud int 912 1.44 dsl fdcintr(void *arg) 913 1.1 reinoud { 914 1.1 reinoud struct fdc_softc *fdc = arg; 915 1.1 reinoud #define st0 fdc->sc_status[0] 916 1.1 reinoud #define cyl fdc->sc_status[1] 917 1.1 reinoud struct fd_softc *fd; 918 1.1 reinoud struct buf *bp; 919 1.1 reinoud bus_space_tag_t iot = fdc->sc_iot; 920 1.1 reinoud bus_space_handle_t ioh = fdc->sc_ioh; 921 1.1 reinoud int read, head, sec, i, nblks; 922 1.1 reinoud struct fd_type *type; 923 1.1 reinoud struct ne7_fd_formb *finfo = NULL; 924 1.1 reinoud 925 1.1 reinoud loop: 926 1.1 reinoud /* Is there a drive for the controller to do a transfer with? */ 927 1.1 reinoud fd = fdc->sc_drives.tqh_first; 928 1.1 reinoud if (fd == NULL) { 929 1.1 reinoud fdc->sc_state = DEVIDLE; 930 1.1 reinoud return 1; 931 1.1 reinoud } 932 1.1 reinoud 933 1.1 reinoud /* Is there a transfer to this drive? If not, deactivate drive. */ 934 1.41 yamt bp = bufq_peek(fd->sc_q); 935 1.1 reinoud if (bp == NULL) { 936 1.1 reinoud fd->sc_ops = 0; 937 1.1 reinoud TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 938 1.1 reinoud fd->sc_active = 0; 939 1.1 reinoud goto loop; 940 1.1 reinoud } 941 1.1 reinoud 942 1.1 reinoud if (bp->b_flags & B_FORMAT) 943 1.1 reinoud finfo = (struct ne7_fd_formb *)bp->b_data; 944 1.1 reinoud 945 1.1 reinoud switch (fdc->sc_state) { 946 1.1 reinoud case DEVIDLE: 947 1.1 reinoud fdc->sc_errors = 0; 948 1.1 reinoud fd->sc_skip = 0; 949 1.1 reinoud fd->sc_bcount = bp->b_bcount; 950 1.1 reinoud fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 951 1.1 reinoud callout_stop(&fd->sc_motoroff_ch); 952 1.1 reinoud if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 953 1.1 reinoud fdc->sc_state = MOTORWAIT; 954 1.1 reinoud return 1; 955 1.1 reinoud } 956 1.1 reinoud if ((fd->sc_flags & FD_MOTOR) == 0) { 957 1.1 reinoud /* Turn on the motor, being careful about pairing. */ 958 1.1 reinoud struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 959 1.1 reinoud if (ofd && ofd->sc_flags & FD_MOTOR) { 960 1.1 reinoud callout_stop(&ofd->sc_motoroff_ch); 961 1.1 reinoud ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 962 1.1 reinoud } 963 1.1 reinoud fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 964 1.1 reinoud fd_set_motor(fdc, 0); 965 1.1 reinoud fdc->sc_state = MOTORWAIT; 966 1.1 reinoud /* Allow .25s for motor to stabilize. */ 967 1.1 reinoud callout_reset(&fd->sc_motoron_ch, hz / 4, 968 1.1 reinoud fd_motor_on, fd); 969 1.1 reinoud return 1; 970 1.1 reinoud } 971 1.1 reinoud /* Make sure the right drive is selected. */ 972 1.1 reinoud fd_set_motor(fdc, 0); 973 1.1 reinoud 974 1.1 reinoud /* fall through */ 975 1.1 reinoud case DOSEEK: 976 1.1 reinoud doseek: 977 1.1 reinoud if (fd->sc_cylin == bp->b_cylinder) 978 1.1 reinoud goto doio; 979 1.1 reinoud 980 1.1 reinoud #if 1 981 1.1 reinoud out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */ 982 1.1 reinoud out_fdc(iot, ioh, 0); 983 1.1 reinoud out_fdc(iot, ioh, 0x18); 984 1.1 reinoud out_fdc(iot, ioh, 0); 985 1.1 reinoud #endif 986 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 987 1.1 reinoud out_fdc(iot, ioh, fd->sc_type->steprate); 988 1.1 reinoud out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ 989 1.1 reinoud 990 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 991 1.1 reinoud out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 992 1.1 reinoud out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 993 1.1 reinoud 994 1.1 reinoud fd->sc_cylin = -1; 995 1.1 reinoud fdc->sc_state = SEEKWAIT; 996 1.1 reinoud 997 1.26 blymn iostat_seek(fd->sc_dk.dk_stats); 998 1.1 reinoud disk_busy(&fd->sc_dk); 999 1.1 reinoud 1000 1.1 reinoud callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1001 1.1 reinoud return 1; 1002 1.1 reinoud 1003 1.1 reinoud case DOIO: 1004 1.1 reinoud doio: 1005 1.1 reinoud type = fd->sc_type; 1006 1.1 reinoud if (finfo) 1007 1.1 reinoud fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1008 1.1 reinoud (char *)finfo; 1009 1.1 reinoud sec = fd->sc_blkno % type->seccyl; 1010 1.1 reinoud nblks = type->seccyl - sec; 1011 1.59 riastrad nblks = uimin(nblks, fd->sc_bcount / FDC_BSIZE); 1012 1.59 riastrad nblks = uimin(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1013 1.1 reinoud fd->sc_nblks = nblks; 1014 1.1 reinoud fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1015 1.1 reinoud head = sec / type->sectrac; 1016 1.1 reinoud sec -= head * type->sectrac; 1017 1.1 reinoud #ifdef DIAGNOSTIC 1018 1.14 thorpej {daddr_t block; 1019 1.1 reinoud block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; 1020 1.1 reinoud if (block != fd->sc_blkno) { 1021 1.14 thorpej printf("fdcintr: block %" PRId64 1022 1.14 thorpej " != blkno %" PRId64 "\n", 1023 1.1 reinoud block, fd->sc_blkno); 1024 1.1 reinoud #ifdef DDB 1025 1.1 reinoud Debugger(); 1026 1.1 reinoud #endif 1027 1.1 reinoud }} 1028 1.1 reinoud #endif 1029 1.1 reinoud read = bp->b_flags & B_READ; 1030 1.4 thorpej if (read) { 1031 1.4 thorpej fdc->sc_fh.fh_func = floppy_read_fiq; 1032 1.4 thorpej fdc->sc_fh.fh_size = floppy_read_fiq_end - 1033 1.4 thorpej floppy_read_fiq; 1034 1.4 thorpej } else { 1035 1.4 thorpej fdc->sc_fh.fh_func = floppy_write_fiq; 1036 1.4 thorpej fdc->sc_fh.fh_size = floppy_read_fiq_end - 1037 1.4 thorpej floppy_read_fiq; 1038 1.4 thorpej } 1039 1.4 thorpej fdc->sc_fh.fh_flags = 0; 1040 1.4 thorpej fdc->sc_fh.fh_regs = &fdc->sc_fr; 1041 1.4 thorpej fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2); 1042 1.4 thorpej fdc->sc_fr.fr_r10 = fd->sc_nbytes; 1043 1.34 yamt fdc->sc_fr.fr_r11 = 1044 1.34 yamt (u_int)((uintptr_t)bp->b_data + fd->sc_skip); 1045 1.4 thorpej fdc->sc_fr.fr_r12 = fdc->sc_drq; 1046 1.1 reinoud #ifdef FD_DEBUG 1047 1.4 thorpej printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n", 1048 1.65 andvar fdc->sc_fr.fr_r9, fdc->sc_fr.fr_r10, fdc->sc_fr.fr_r11, 1049 1.65 andvar fdc->sc_fr.fr_r12, (u_int)bp->b_data, fd->sc_skip); 1050 1.1 reinoud #endif 1051 1.4 thorpej if (fiq_claim(&fdc->sc_fh) == -1) 1052 1.50 matt panic("%s: Cannot claim FIQ vector", 1053 1.52 chs device_xname(fdc->sc_dev)); 1054 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01); 1055 1.1 reinoud bus_space_write_2(iot, ioh, fdctl, type->rate); 1056 1.1 reinoud #ifdef FD_DEBUG 1057 1.1 reinoud printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", 1058 1.1 reinoud read ? "read" : "write", fd->sc_drive, fd->sc_cylin, 1059 1.1 reinoud head, sec, nblks); 1060 1.1 reinoud #endif 1061 1.1 reinoud if (finfo) { 1062 1.1 reinoud /* formatting */ 1063 1.1 reinoud if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) { 1064 1.1 reinoud fdc->sc_errors = 4; 1065 1.1 reinoud fdcretry(fdc); 1066 1.1 reinoud goto loop; 1067 1.1 reinoud } 1068 1.1 reinoud out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1069 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_secshift); 1070 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_nsecs); 1071 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_gaplen); 1072 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_fillbyte); 1073 1.1 reinoud } else { 1074 1.1 reinoud if (read) 1075 1.1 reinoud out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1076 1.1 reinoud else 1077 1.1 reinoud out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1078 1.1 reinoud out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1079 1.1 reinoud out_fdc(iot, ioh, fd->sc_cylin); /* track */ 1080 1.1 reinoud out_fdc(iot, ioh, head); 1081 1.1 reinoud out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1082 1.1 reinoud out_fdc(iot, ioh, type->secsize);/* sector size */ 1083 1.1 reinoud out_fdc(iot, ioh, type->sectrac);/* sectors/track */ 1084 1.1 reinoud out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1085 1.1 reinoud out_fdc(iot, ioh, type->datalen);/* data length */ 1086 1.1 reinoud } 1087 1.1 reinoud fdc->sc_state = IOCOMPLETE; 1088 1.1 reinoud 1089 1.1 reinoud disk_busy(&fd->sc_dk); 1090 1.1 reinoud 1091 1.1 reinoud /* allow 2 seconds for operation */ 1092 1.1 reinoud callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1093 1.1 reinoud return 1; /* will return later */ 1094 1.1 reinoud 1095 1.1 reinoud case SEEKWAIT: 1096 1.1 reinoud callout_stop(&fdc->sc_timo_ch); 1097 1.1 reinoud fdc->sc_state = SEEKCOMPLETE; 1098 1.1 reinoud /* allow 1/50 second for heads to settle */ 1099 1.1 reinoud #if 0 1100 1.1 reinoud callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1101 1.1 reinoud #endif 1102 1.1 reinoud return 1; 1103 1.1 reinoud 1104 1.1 reinoud case SEEKCOMPLETE: 1105 1.12 mrg /* no data on seek */ 1106 1.12 mrg disk_unbusy(&fd->sc_dk, 0, 0); 1107 1.1 reinoud 1108 1.1 reinoud /* Make sure seek really happened. */ 1109 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI); 1110 1.1 reinoud if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1111 1.1 reinoud cyl != bp->b_cylinder * fd->sc_type->step) { 1112 1.1 reinoud #ifdef FD_DEBUG 1113 1.52 chs fdcstatus(fd->sc_dev, 2, "seek failed"); 1114 1.1 reinoud #endif 1115 1.1 reinoud fdcretry(fdc); 1116 1.1 reinoud goto loop; 1117 1.1 reinoud } 1118 1.1 reinoud fd->sc_cylin = bp->b_cylinder; 1119 1.1 reinoud goto doio; 1120 1.1 reinoud 1121 1.1 reinoud case IOTIMEDOUT: 1122 1.4 thorpej fiq_release(&fdc->sc_fh); 1123 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1124 1.1 reinoud case SEEKTIMEDOUT: 1125 1.1 reinoud case RECALTIMEDOUT: 1126 1.1 reinoud case RESETTIMEDOUT: 1127 1.1 reinoud fdcretry(fdc); 1128 1.1 reinoud goto loop; 1129 1.1 reinoud 1130 1.1 reinoud case IOCOMPLETE: /* IO DONE, post-analyze */ 1131 1.1 reinoud callout_stop(&fdc->sc_timo_ch); 1132 1.1 reinoud 1133 1.12 mrg disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1134 1.12 mrg (bp->b_flags & B_READ)); 1135 1.1 reinoud 1136 1.1 reinoud if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { 1137 1.4 thorpej fiq_release(&fdc->sc_fh); 1138 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1139 1.1 reinoud #ifdef FD_DEBUG 1140 1.52 chs fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ? 1141 1.1 reinoud "read failed" : "write failed"); 1142 1.65 andvar printf("blkno %lld nblks %d\n", 1143 1.1 reinoud fd->sc_blkno, fd->sc_nblks); 1144 1.1 reinoud #endif 1145 1.1 reinoud fdcretry(fdc); 1146 1.1 reinoud goto loop; 1147 1.1 reinoud } 1148 1.4 thorpej fiq_release(&fdc->sc_fh); 1149 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1150 1.1 reinoud if (fdc->sc_errors) { 1151 1.1 reinoud #if 0 1152 1.1 reinoud diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 1153 1.1 reinoud fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1154 1.1 reinoud printf("\n"); 1155 1.1 reinoud #endif 1156 1.1 reinoud fdc->sc_errors = 0; 1157 1.1 reinoud } 1158 1.1 reinoud fd->sc_blkno += fd->sc_nblks; 1159 1.1 reinoud fd->sc_skip += fd->sc_nbytes; 1160 1.1 reinoud fd->sc_bcount -= fd->sc_nbytes; 1161 1.1 reinoud if (!finfo && fd->sc_bcount > 0) { 1162 1.1 reinoud bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1163 1.1 reinoud goto doseek; 1164 1.1 reinoud } 1165 1.1 reinoud fdfinish(fd, bp); 1166 1.1 reinoud goto loop; 1167 1.1 reinoud 1168 1.1 reinoud case DORESET: 1169 1.1 reinoud /* try a reset, keep motor on */ 1170 1.1 reinoud fd_set_motor(fdc, 1); 1171 1.1 reinoud delay(100); 1172 1.1 reinoud fd_set_motor(fdc, 0); 1173 1.1 reinoud fdc->sc_state = RESETCOMPLETE; 1174 1.1 reinoud callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1175 1.1 reinoud return 1; /* will return later */ 1176 1.1 reinoud 1177 1.1 reinoud case RESETCOMPLETE: 1178 1.1 reinoud callout_stop(&fdc->sc_timo_ch); 1179 1.1 reinoud /* clear the controller output buffer */ 1180 1.1 reinoud for (i = 0; i < 4; i++) { 1181 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI); 1182 1.1 reinoud (void) fdcresult(fdc); 1183 1.1 reinoud } 1184 1.1 reinoud 1185 1.1 reinoud /* fall through */ 1186 1.1 reinoud case DORECAL: 1187 1.1 reinoud out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 1188 1.1 reinoud out_fdc(iot, ioh, fd->sc_drive); 1189 1.1 reinoud fdc->sc_state = RECALWAIT; 1190 1.1 reinoud callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1191 1.1 reinoud return 1; /* will return later */ 1192 1.1 reinoud 1193 1.1 reinoud case RECALWAIT: 1194 1.1 reinoud callout_stop(&fdc->sc_timo_ch); 1195 1.1 reinoud fdc->sc_state = RECALCOMPLETE; 1196 1.1 reinoud /* allow 1/30 second for heads to settle */ 1197 1.1 reinoud #if 0 1198 1.1 reinoud callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1199 1.1 reinoud #endif 1200 1.1 reinoud return 1; /* will return later */ 1201 1.1 reinoud 1202 1.1 reinoud case RECALCOMPLETE: 1203 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI); 1204 1.1 reinoud if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1205 1.1 reinoud #ifdef FD_DEBUG 1206 1.52 chs fdcstatus(fd->sc_dev, 2, "recalibrate failed"); 1207 1.1 reinoud #endif 1208 1.1 reinoud fdcretry(fdc); 1209 1.1 reinoud goto loop; 1210 1.1 reinoud } 1211 1.1 reinoud fd->sc_cylin = 0; 1212 1.1 reinoud goto doseek; 1213 1.1 reinoud 1214 1.1 reinoud case MOTORWAIT: 1215 1.1 reinoud if (fd->sc_flags & FD_MOTOR_WAIT) 1216 1.1 reinoud return 1; /* time's not up yet */ 1217 1.1 reinoud goto doseek; 1218 1.1 reinoud 1219 1.1 reinoud default: 1220 1.52 chs fdcstatus(fd->sc_dev, 0, "stray interrupt"); 1221 1.1 reinoud return 1; 1222 1.1 reinoud } 1223 1.1 reinoud #ifdef DIAGNOSTIC 1224 1.1 reinoud panic("fdcintr: impossible"); 1225 1.1 reinoud #endif 1226 1.1 reinoud #undef st0 1227 1.1 reinoud #undef cyl 1228 1.1 reinoud } 1229 1.1 reinoud 1230 1.1 reinoud void 1231 1.44 dsl fdcretry(struct fdc_softc *fdc) 1232 1.1 reinoud { 1233 1.1 reinoud struct fd_softc *fd; 1234 1.1 reinoud struct buf *bp; 1235 1.1 reinoud 1236 1.1 reinoud fd = fdc->sc_drives.tqh_first; 1237 1.41 yamt bp = bufq_peek(fd->sc_q); 1238 1.1 reinoud 1239 1.1 reinoud if (fd->sc_opts & FDOPT_NORETRY) 1240 1.1 reinoud goto fail; 1241 1.1 reinoud switch (fdc->sc_errors) { 1242 1.1 reinoud case 0: 1243 1.1 reinoud /* try again */ 1244 1.1 reinoud fdc->sc_state = DOSEEK; 1245 1.1 reinoud break; 1246 1.1 reinoud 1247 1.1 reinoud case 1: case 2: case 3: 1248 1.1 reinoud /* didn't work; try recalibrating */ 1249 1.1 reinoud fdc->sc_state = DORECAL; 1250 1.1 reinoud break; 1251 1.1 reinoud 1252 1.1 reinoud case 4: 1253 1.1 reinoud /* still no go; reset the bastard */ 1254 1.1 reinoud fdc->sc_state = DORESET; 1255 1.1 reinoud break; 1256 1.1 reinoud 1257 1.1 reinoud default: 1258 1.1 reinoud fail: 1259 1.1 reinoud if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1260 1.1 reinoud diskerr(bp, "fd", "hard error", LOG_PRINTF, 1261 1.1 reinoud fd->sc_skip / FDC_BSIZE, 1262 1.1 reinoud (struct disklabel *)NULL); 1263 1.40 christos fdcpstatus(7, fdc); 1264 1.1 reinoud } 1265 1.1 reinoud 1266 1.1 reinoud bp->b_error = EIO; 1267 1.1 reinoud fdfinish(fd, bp); 1268 1.1 reinoud } 1269 1.1 reinoud fdc->sc_errors++; 1270 1.1 reinoud } 1271 1.1 reinoud 1272 1.1 reinoud int 1273 1.39 cegger fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1274 1.1 reinoud { 1275 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 1276 1.1 reinoud struct fdformat_parms *form_parms; 1277 1.1 reinoud struct fdformat_cmd *form_cmd; 1278 1.1 reinoud struct ne7_fd_formb *fd_formb; 1279 1.1 reinoud struct disklabel buffer; 1280 1.1 reinoud int error; 1281 1.1 reinoud unsigned int scratch; 1282 1.1 reinoud int il[FD_MAX_NSEC + 1]; 1283 1.1 reinoud register int i, j; 1284 1.1 reinoud 1285 1.1 reinoud switch (cmd) { 1286 1.1 reinoud case DIOCGDINFO: 1287 1.1 reinoud memset(&buffer, 0, sizeof(buffer)); 1288 1.1 reinoud 1289 1.1 reinoud buffer.d_secpercyl = fd->sc_type->seccyl; 1290 1.57 christos buffer.d_type = DKTYPE_FLOPPY; 1291 1.1 reinoud buffer.d_secsize = FDC_BSIZE; 1292 1.1 reinoud 1293 1.1 reinoud if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1294 1.1 reinoud return EINVAL; 1295 1.1 reinoud 1296 1.1 reinoud *(struct disklabel *)addr = buffer; 1297 1.1 reinoud return 0; 1298 1.1 reinoud 1299 1.1 reinoud case DIOCWLABEL: 1300 1.1 reinoud if ((flag & FWRITE) == 0) 1301 1.1 reinoud return EBADF; 1302 1.1 reinoud /* XXX do something */ 1303 1.1 reinoud return 0; 1304 1.1 reinoud 1305 1.1 reinoud case DIOCWDINFO: 1306 1.1 reinoud if ((flag & FWRITE) == 0) 1307 1.1 reinoud return EBADF; 1308 1.1 reinoud 1309 1.1 reinoud error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL); 1310 1.1 reinoud if (error) 1311 1.1 reinoud return error; 1312 1.1 reinoud 1313 1.1 reinoud error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1314 1.1 reinoud return error; 1315 1.1 reinoud 1316 1.1 reinoud case FDIOCGETFORMAT: 1317 1.1 reinoud form_parms = (struct fdformat_parms *)addr; 1318 1.1 reinoud form_parms->fdformat_version = FDFORMAT_VERSION; 1319 1.1 reinoud form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1320 1.1 reinoud form_parms->ncyl = fd->sc_type->cyls; 1321 1.1 reinoud form_parms->nspt = fd->sc_type->sectrac; 1322 1.1 reinoud form_parms->ntrk = fd->sc_type->heads; 1323 1.1 reinoud form_parms->stepspercyl = fd->sc_type->step; 1324 1.1 reinoud form_parms->gaplen = fd->sc_type->gap2; 1325 1.1 reinoud form_parms->fillbyte = fd->sc_type->fillbyte; 1326 1.1 reinoud form_parms->interleave = fd->sc_type->interleave; 1327 1.1 reinoud switch (fd->sc_type->rate) { 1328 1.1 reinoud case FDC_500KBPS: 1329 1.1 reinoud form_parms->xfer_rate = 500 * 1024; 1330 1.1 reinoud break; 1331 1.1 reinoud case FDC_300KBPS: 1332 1.1 reinoud form_parms->xfer_rate = 300 * 1024; 1333 1.1 reinoud break; 1334 1.1 reinoud case FDC_250KBPS: 1335 1.1 reinoud form_parms->xfer_rate = 250 * 1024; 1336 1.1 reinoud break; 1337 1.1 reinoud default: 1338 1.1 reinoud return EINVAL; 1339 1.1 reinoud } 1340 1.1 reinoud return 0; 1341 1.1 reinoud 1342 1.1 reinoud case FDIOCSETFORMAT: 1343 1.1 reinoud if((flag & FWRITE) == 0) 1344 1.1 reinoud return EBADF; /* must be opened for writing */ 1345 1.1 reinoud form_parms = (struct fdformat_parms *)addr; 1346 1.1 reinoud if (form_parms->fdformat_version != FDFORMAT_VERSION) 1347 1.1 reinoud return EINVAL; /* wrong version of formatting prog */ 1348 1.1 reinoud 1349 1.1 reinoud scratch = form_parms->nbps >> 7; 1350 1.1 reinoud if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1351 1.1 reinoud scratch & ~(1 << (ffs(scratch)-1))) 1352 1.1 reinoud /* not a power-of-two multiple of 128 */ 1353 1.1 reinoud return EINVAL; 1354 1.1 reinoud 1355 1.1 reinoud switch (form_parms->xfer_rate) { 1356 1.1 reinoud case 500 * 1024: 1357 1.1 reinoud fd->sc_type->rate = FDC_500KBPS; 1358 1.1 reinoud break; 1359 1.1 reinoud case 300 * 1024: 1360 1.1 reinoud fd->sc_type->rate = FDC_300KBPS; 1361 1.1 reinoud break; 1362 1.1 reinoud case 250 * 1024: 1363 1.1 reinoud fd->sc_type->rate = FDC_250KBPS; 1364 1.1 reinoud break; 1365 1.1 reinoud default: 1366 1.1 reinoud return EINVAL; 1367 1.1 reinoud } 1368 1.1 reinoud 1369 1.1 reinoud if (form_parms->nspt > FD_MAX_NSEC || 1370 1.1 reinoud form_parms->fillbyte > 0xff || 1371 1.1 reinoud form_parms->interleave > 0xff) 1372 1.1 reinoud return EINVAL; 1373 1.1 reinoud fd->sc_type->sectrac = form_parms->nspt; 1374 1.1 reinoud if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1375 1.1 reinoud return EINVAL; 1376 1.1 reinoud fd->sc_type->heads = form_parms->ntrk; 1377 1.1 reinoud fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1378 1.1 reinoud fd->sc_type->secsize = ffs(scratch)-1; 1379 1.1 reinoud fd->sc_type->gap2 = form_parms->gaplen; 1380 1.1 reinoud fd->sc_type->cyls = form_parms->ncyl; 1381 1.1 reinoud fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1382 1.1 reinoud form_parms->nbps / DEV_BSIZE; 1383 1.1 reinoud fd->sc_type->step = form_parms->stepspercyl; 1384 1.1 reinoud fd->sc_type->fillbyte = form_parms->fillbyte; 1385 1.1 reinoud fd->sc_type->interleave = form_parms->interleave; 1386 1.1 reinoud return 0; 1387 1.1 reinoud 1388 1.1 reinoud case FDIOCFORMAT_TRACK: 1389 1.1 reinoud if((flag & FWRITE) == 0) 1390 1.1 reinoud return EBADF; /* must be opened for writing */ 1391 1.1 reinoud form_cmd = (struct fdformat_cmd *)addr; 1392 1.1 reinoud if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1393 1.1 reinoud return EINVAL; /* wrong version of formatting prog */ 1394 1.1 reinoud 1395 1.1 reinoud if (form_cmd->head >= fd->sc_type->heads || 1396 1.1 reinoud form_cmd->cylinder >= fd->sc_type->cyls) { 1397 1.1 reinoud return EINVAL; 1398 1.1 reinoud } 1399 1.1 reinoud 1400 1.62 thorpej fd_formb = kmem_alloc(sizeof(*fd_formb), KM_SLEEP); 1401 1.1 reinoud fd_formb->head = form_cmd->head; 1402 1.1 reinoud fd_formb->cyl = form_cmd->cylinder; 1403 1.1 reinoud fd_formb->transfer_rate = fd->sc_type->rate; 1404 1.1 reinoud fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1405 1.1 reinoud fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1406 1.1 reinoud fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1407 1.1 reinoud fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1408 1.1 reinoud 1409 1.1 reinoud memset(il, 0, sizeof il); 1410 1.1 reinoud for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1411 1.1 reinoud while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1412 1.1 reinoud j++; 1413 1.1 reinoud il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1414 1.1 reinoud j += fd->sc_type->interleave; 1415 1.1 reinoud } 1416 1.1 reinoud for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1417 1.1 reinoud fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1418 1.1 reinoud fd_formb->fd_formb_headno(i) = form_cmd->head; 1419 1.1 reinoud fd_formb->fd_formb_secno(i) = il[i+1]; 1420 1.1 reinoud fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1421 1.1 reinoud } 1422 1.1 reinoud 1423 1.22 christos error = fdformat(dev, fd_formb, l); 1424 1.62 thorpej kmem_free(fd_formb, sizeof(*fd_formb)); 1425 1.1 reinoud return error; 1426 1.1 reinoud 1427 1.1 reinoud case FDIOCGETOPTS: /* get drive options */ 1428 1.1 reinoud *(int *)addr = fd->sc_opts; 1429 1.1 reinoud return 0; 1430 1.1 reinoud 1431 1.1 reinoud case FDIOCSETOPTS: /* set drive options */ 1432 1.1 reinoud fd->sc_opts = *(int *)addr; 1433 1.1 reinoud return 0; 1434 1.1 reinoud 1435 1.1 reinoud default: 1436 1.1 reinoud return ENOTTY; 1437 1.1 reinoud } 1438 1.1 reinoud 1439 1.1 reinoud #ifdef DIAGNOSTIC 1440 1.1 reinoud panic("fdioctl: impossible"); 1441 1.1 reinoud #endif 1442 1.1 reinoud } 1443 1.1 reinoud 1444 1.1 reinoud int 1445 1.39 cegger fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l) 1446 1.1 reinoud { 1447 1.37 matt int rv = 0; 1448 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev)); 1449 1.1 reinoud struct fd_type *type = fd->sc_type; 1450 1.1 reinoud struct buf *bp; 1451 1.1 reinoud 1452 1.1 reinoud /* set up a buffer header for fdstrategy() */ 1453 1.35 ad bp = getiobuf(NULL, false); 1454 1.1 reinoud if(bp == 0) 1455 1.1 reinoud return ENOBUFS; 1456 1.35 ad bp->b_flags = B_PHYS | B_FORMAT; 1457 1.35 ad bp->b_cflags |= BC_BUSY; 1458 1.22 christos bp->b_proc = l->l_proc; 1459 1.1 reinoud bp->b_dev = dev; 1460 1.1 reinoud 1461 1.1 reinoud /* 1462 1.1 reinoud * calculate a fake blkno, so fdstrategy() would initiate a 1463 1.1 reinoud * seek to the requested cylinder 1464 1.1 reinoud */ 1465 1.1 reinoud bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1466 1.1 reinoud + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1467 1.1 reinoud 1468 1.1 reinoud bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1469 1.28 christos bp->b_data = (void *)finfo; 1470 1.1 reinoud 1471 1.1 reinoud #ifdef DEBUG 1472 1.49 uebayasi printf("fdformat: blkno %llx count %x\n", 1473 1.15 bjh21 (unsigned long long)bp->b_blkno, bp->b_bcount); 1474 1.1 reinoud #endif 1475 1.1 reinoud 1476 1.1 reinoud /* now do the format */ 1477 1.1 reinoud fdstrategy(bp); 1478 1.1 reinoud 1479 1.1 reinoud /* ...and wait for it to complete */ 1480 1.35 ad /* XXX very dodgy */ 1481 1.35 ad mutex_enter(bp->b_objlock); 1482 1.35 ad while (!(bp->b_oflags & BO_DONE)) { 1483 1.36 ad rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz); 1484 1.1 reinoud if (rv == EWOULDBLOCK) 1485 1.1 reinoud break; 1486 1.1 reinoud } 1487 1.35 ad mutex_exit(bp->b_objlock); 1488 1.35 ad 1489 1.1 reinoud if (rv == EWOULDBLOCK) { 1490 1.1 reinoud /* timed out */ 1491 1.1 reinoud rv = EIO; 1492 1.1 reinoud biodone(bp); 1493 1.30 ad } else if (bp->b_error != 0) 1494 1.1 reinoud rv = bp->b_error; 1495 1.35 ad putiobuf(bp); 1496 1.1 reinoud return rv; 1497 1.1 reinoud } 1498 1.1 reinoud 1499 1.1 reinoud #include <dev/md.h> 1500 1.1 reinoud 1501 1.43 dsl int load_memory_disc_from_floppy(struct md_conf *md, dev_t dev); 1502 1.1 reinoud 1503 1.1 reinoud int 1504 1.44 dsl load_memory_disc_from_floppy(struct md_conf *md, dev_t dev) 1505 1.1 reinoud { 1506 1.1 reinoud struct buf *bp; 1507 1.1 reinoud int loop; 1508 1.1 reinoud int s; 1509 1.1 reinoud int type; 1510 1.1 reinoud int floppysize; 1511 1.1 reinoud 1512 1.6 gehenna if (bdevsw_lookup(dev) != &fd_bdevsw) 1513 1.1 reinoud return(EINVAL); 1514 1.1 reinoud 1515 1.1 reinoud if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0) 1516 1.1 reinoud return(EBUSY); 1517 1.1 reinoud 1518 1.1 reinoud type = FDTYPE(dev) - 1; 1519 1.1 reinoud if (type < 0) type = 0; 1520 1.1 reinoud floppysize = fd_types[type].size << (fd_types[type].secsize + 7); 1521 1.1 reinoud 1522 1.1 reinoud if (md->md_size < floppysize) { 1523 1.1 reinoud printf("Memory disc is not big enough for floppy image\n"); 1524 1.1 reinoud return(EINVAL); 1525 1.1 reinoud } 1526 1.1 reinoud 1527 1.1 reinoud /* We have the memory disk ! */ 1528 1.1 reinoud 1529 1.1 reinoud printf("Loading memory disc : %4dK ", 0); 1530 1.1 reinoud 1531 1.1 reinoud /* obtain a buffer */ 1532 1.1 reinoud 1533 1.1 reinoud bp = geteblk(fd_types[type].sectrac * DEV_BSIZE); 1534 1.1 reinoud 1535 1.1 reinoud /* request no partition relocation by driver on I/O operations */ 1536 1.1 reinoud 1537 1.1 reinoud bp->b_dev = dev; 1538 1.1 reinoud 1539 1.42 cegger s = splbio(); 1540 1.1 reinoud 1541 1.22 christos if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) { 1542 1.32 ad brelse(bp, 0); 1543 1.1 reinoud printf("Cannot open floppy device\n"); 1544 1.1 reinoud return(EINVAL); 1545 1.1 reinoud } 1546 1.1 reinoud 1547 1.1 reinoud for (loop = 0; 1548 1.1 reinoud loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac); 1549 1.1 reinoud ++loop) { 1550 1.1 reinoud printf("\x08\x08\x08\x08\x08\x08%4dK ", 1551 1.1 reinoud loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1552 1.1 reinoud bp->b_blkno = loop * fd_types[type].sectrac; 1553 1.1 reinoud bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE; 1554 1.1 reinoud bp->b_flags |= B_READ; 1555 1.1 reinoud bp->b_error = 0; 1556 1.1 reinoud bp->b_resid = 0; 1557 1.1 reinoud fdstrategy(bp); 1558 1.1 reinoud 1559 1.1 reinoud if (biowait(bp)) 1560 1.7 provos panic("Cannot load floppy image"); 1561 1.1 reinoud 1562 1.34 yamt memcpy((char *)md->md_addr + loop * fd_types[type].sectrac 1563 1.28 christos * DEV_BSIZE, (void *)bp->b_data, 1564 1.1 reinoud fd_types[type].sectrac * DEV_BSIZE); 1565 1.1 reinoud } 1566 1.1 reinoud printf("\x08\x08\x08\x08\x08\x08%4dK done\n", 1567 1.1 reinoud loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1568 1.1 reinoud 1569 1.22 christos fdclose(bp->b_dev, 0, 0, curlwp); 1570 1.1 reinoud 1571 1.32 ad brelse(bp, 0); 1572 1.1 reinoud 1573 1.1 reinoud splx(s); 1574 1.1 reinoud return(0); 1575 1.1 reinoud } 1576