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