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