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