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