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