1 /* $NetBSD: fd.c,v 1.118 2015/07/11 10:32:46 kamil 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.118 2015/07/11 10:32:46 kamil 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 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 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ, 492 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &fdc->sc_dmamap)) { 493 aprint_error_dev(self, "can't set up intio DMA map\n"); 494 return; 495 } 496 497 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc) != 0) 498 panic("Could not establish interrupt (duplicated vector?)."); 499 intio_set_ivec(ia->ia_intr); 500 501 /* reset */ 502 intio_disable_intr(SICILIAN_INTR_FDD); 503 intio_enable_intr(SICILIAN_INTR_FDC); 504 fdcresult(fdc); 505 fdcreset(fdc); 506 507 aprint_normal_dev(self, "uPD72065 FDC\n"); 508 out_fdc(iot, ioh, NE7CMD_SPECIFY); /* specify command */ 509 out_fdc(iot, ioh, 0xd0); 510 out_fdc(iot, ioh, 0x10); 511 512 /* physical limit: four drives per controller. */ 513 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 514 (void)config_found(self, (void *)&fa, fdprint); 515 } 516 517 intio_enable_intr(SICILIAN_INTR_FDC); 518 } 519 520 void 521 fdcreset(struct fdc_softc *fdc) 522 { 523 524 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET); 525 } 526 527 static int 528 fdcpoll(struct fdc_softc *fdc) 529 { 530 int i = 25000; 531 532 while (--i > 0) { 533 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC) != 0) { 534 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 535 fdcresult(fdc); 536 break; 537 } 538 DELAY(100); 539 } 540 return i; 541 } 542 543 int 544 fdprobe(device_t parent, cfdata_t cf, void *aux) 545 { 546 struct fdc_softc *fdc = device_private(parent); 547 struct fd_type *type; 548 struct fdc_attach_args *fa = aux; 549 int drive = fa->fa_drive; 550 bus_space_tag_t iot = fdc->sc_iot; 551 bus_space_handle_t ioh = fdc->sc_ioh; 552 int n = 0; 553 int found = 0; 554 int i; 555 556 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT && 557 cf->cf_loc[FDCCF_UNIT] != drive) 558 return 0; 559 560 type = &fd_types[0]; /* XXX 1.2MB */ 561 562 /* toss any interrupt status */ 563 for (n = 0; n < 4; n++) { 564 out_fdc(iot, ioh, NE7CMD_SENSEI); 565 (void)fdcresult(fdc); 566 } 567 intio_disable_intr(SICILIAN_INTR_FDC); 568 569 /* select drive and turn on motor */ 570 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive); 571 fdc_force_ready(FDCRDY); 572 fdcpoll(fdc); 573 574 retry: 575 out_fdc(iot, ioh, NE7CMD_RECAL); 576 out_fdc(iot, ioh, drive); 577 578 i = 25000; 579 while (--i > 0) { 580 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC) != 0) { 581 out_fdc(iot, ioh, NE7CMD_SENSEI); 582 n = fdcresult(fdc); 583 break; 584 } 585 DELAY(100); 586 } 587 588 #ifdef FDDEBUG 589 { 590 int _i; 591 DPRINTF(("fdprobe: status")); 592 for (_i = 0; _i < n; _i++) 593 DPRINTF((" %x", fdc->sc_status[_i])); 594 DPRINTF(("\n")); 595 } 596 #endif 597 598 if (n == 2) { 599 if ((fdc->sc_status[0] & 0xf0) == 0x20) 600 found = 1; 601 else if ((fdc->sc_status[0] & 0xf0) == 0xc0) 602 goto retry; 603 } 604 605 /* turn off motor */ 606 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, 607 fdctl, (type->rate << 4) | drive); 608 fdc_force_ready(FDCSTBY); 609 if (!found) { 610 intio_enable_intr(SICILIAN_INTR_FDC); 611 return 0; 612 } 613 614 return 1; 615 } 616 617 /* 618 * Controller is working, and drive responded. Attach it. 619 */ 620 void 621 fdattach(device_t parent, device_t self, void *aux) 622 { 623 struct fdc_softc *fdc = device_private(parent); 624 struct fd_softc *fd = device_private(self); 625 struct fdc_attach_args *fa = aux; 626 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */ 627 int drive = fa->fa_drive; 628 629 #if 0 630 callout_init(&fd->sc_motoron_ch, 0); 631 #endif 632 callout_init(&fd->sc_motoroff_ch, 0); 633 634 fd->sc_dev = self; 635 fd->sc_flags = 0; 636 637 if (type) 638 aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name, 639 type->cyls, type->heads, type->sectrac); 640 else 641 aprint_normal(": density unknown\n"); 642 643 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 644 fd->sc_cylin = -1; 645 fd->sc_drive = drive; 646 fd->sc_deftype = type; 647 fdc->sc_fd[drive] = fd; 648 649 fd->sc_copybuf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 650 if (fd->sc_copybuf == 0) 651 aprint_error("%s: WARNING!! malloc() failed.\n", __func__); 652 fd->sc_flags |= FD_ALIVE; 653 654 /* 655 * Initialize and attach the disk structure. 656 */ 657 disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver); 658 disk_attach(&fd->sc_dk); 659 660 /* 661 * Establish a mountroot_hook anyway in case we booted 662 * with RB_ASKNAME and get selected as the boot device. 663 */ 664 mountroothook_establish(fd_mountroot_hook, fd->sc_dev); 665 666 rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev), 667 RND_TYPE_DISK, RND_FLAG_DEFAULT); 668 } 669 670 struct fd_type * 671 fd_dev_to_type(struct fd_softc *fd, dev_t dev) 672 { 673 size_t type = FDTYPE(dev); 674 675 if (type > __arraycount(fd_types)) 676 return NULL; 677 return &fd_types[type]; 678 } 679 680 void 681 fdstrategy(struct buf *bp) 682 { 683 struct fd_softc *fd; 684 int unit; 685 int sz; 686 int s; 687 688 unit = FDUNIT(bp->b_dev); 689 fd = device_lookup_private(&fd_cd, unit); 690 if (fd == NULL) { 691 bp->b_error = EINVAL; 692 goto done; 693 } 694 695 if (bp->b_blkno < 0 || 696 ((bp->b_bcount % FDC_BSIZE) != 0 && 697 (bp->b_flags & B_FORMAT) == 0)) { 698 DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", " 699 "bcount=%d\n", unit, 700 bp->b_blkno, bp->b_bcount)); 701 bp->b_error = EINVAL; 702 goto done; 703 } 704 705 /* If it's a null transfer, return immediately. */ 706 if (bp->b_bcount == 0) 707 goto done; 708 709 sz = howmany(bp->b_bcount, FDC_BSIZE); 710 711 if (bp->b_blkno + sz > 712 (fd->sc_type->size << (fd->sc_type->secsize - 2))) { 713 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) 714 - bp->b_blkno; 715 if (sz == 0) { 716 /* If exactly at end of disk, return EOF. */ 717 bp->b_resid = bp->b_bcount; 718 goto done; 719 } 720 if (sz < 0) { 721 /* If past end of disk, return EINVAL. */ 722 bp->b_error = EINVAL; 723 goto done; 724 } 725 /* Otherwise, truncate request. */ 726 bp->b_bcount = sz << DEV_BSHIFT; 727 } 728 729 bp->b_rawblkno = bp->b_blkno; 730 bp->b_cylinder = (bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)) / 731 (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2))); 732 733 DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n", 734 bp->b_flags & B_READ ? "read" : "write", 735 bp->b_blkno, bp->b_bcount, bp->b_cylinder)); 736 /* Queue transfer on drive, activate drive and controller if idle. */ 737 s = splbio(); 738 bufq_put(fd->sc_q, bp); 739 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 740 if (fd->sc_active == 0) 741 fdstart(fd); 742 #ifdef DIAGNOSTIC 743 else { 744 struct fdc_softc *fdc; 745 746 fdc = device_private(device_parent(fd->sc_dev)); 747 if (fdc->sc_state == DEVIDLE) { 748 printf("fdstrategy: controller inactive\n"); 749 fdcstart(fdc); 750 } 751 } 752 #endif 753 splx(s); 754 return; 755 756 done: 757 /* Toss transfer; we're done early. */ 758 biodone(bp); 759 } 760 761 void 762 fdstart(struct fd_softc *fd) 763 { 764 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 765 int active = !TAILQ_EMPTY(&fdc->sc_drives); 766 767 /* Link into controller queue. */ 768 fd->sc_active = 1; 769 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 770 771 /* If controller not already active, start it. */ 772 if (!active) 773 fdcstart(fdc); 774 } 775 776 void 777 fdfinish(struct fd_softc *fd, struct buf *bp) 778 { 779 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 780 781 /* 782 * Move this drive to the end of the queue to give others a `fair' 783 * chance. We only force a switch if N operations are completed while 784 * another drive is waiting to be serviced, since there is a long motor 785 * startup delay whenever we switch. 786 */ 787 (void)bufq_get(fd->sc_q); 788 if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) { 789 fd->sc_ops = 0; 790 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 791 if (bufq_peek(fd->sc_q) != NULL) 792 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 793 else 794 fd->sc_active = 0; 795 } 796 bp->b_resid = fd->sc_bcount; 797 fd->sc_skip = 0; 798 799 rnd_add_uint32(&fd->rnd_source, bp->b_blkno); 800 801 biodone(bp); 802 /* turn off motor 5s from now */ 803 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 804 fdc->sc_state = DEVIDLE; 805 } 806 807 int 808 fdread(dev_t dev, struct uio *uio, int flags) 809 { 810 811 return physio(fdstrategy, NULL, dev, B_READ, minphys, uio); 812 } 813 814 int 815 fdwrite(dev_t dev, struct uio *uio, int flags) 816 { 817 818 return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio); 819 } 820 821 void 822 fd_set_motor(struct fdc_softc *fdc, int reset) 823 { 824 struct fd_softc *fd; 825 int n; 826 827 DPRINTF(("fd_set_motor:\n")); 828 for (n = 0; n < 4; n++) { 829 fd = fdc->sc_fd[n]; 830 if (fd != NULL && (fd->sc_flags & FD_MOTOR) != 0) 831 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl, 832 0x80 | (fd->sc_type->rate << 4)| n); 833 } 834 } 835 836 void 837 fd_motor_off(void *arg) 838 { 839 struct fd_softc *fd = arg; 840 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 841 int s; 842 843 DPRINTF(("fd_motor_off:\n")); 844 845 s = splbio(); 846 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 847 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl, 848 (fd->sc_type->rate << 4) | fd->sc_drive); 849 #if 0 850 fd_set_motor(fdc, 0); /* XXX */ 851 #endif 852 splx(s); 853 } 854 855 #if 0 /* on x68k motor on triggers interrupts by state change of ready line. */ 856 void 857 fd_motor_on(void *arg) 858 { 859 struct fd_softc *fd = arg; 860 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 861 int s; 862 863 DPRINTF(("fd_motor_on:\n")); 864 865 s = splbio(); 866 fd->sc_flags &= ~FD_MOTOR_WAIT; 867 if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && 868 (fdc->sc_state == MOTORWAIT)) 869 (void)fdcintr(fdc); 870 splx(s); 871 } 872 #endif 873 874 int 875 fdcresult(struct fdc_softc *fdc) 876 { 877 bus_space_tag_t iot = fdc->sc_iot; 878 bus_space_handle_t ioh = fdc->sc_ioh; 879 uint8_t i; 880 int j, n; 881 882 n = 0; 883 for (j = 100000; j != 0; j--) { 884 i = bus_space_read_1(iot, ioh, fdsts) & 885 (NE7_DIO | NE7_RQM | NE7_CB); 886 887 if (i == NE7_RQM) 888 return n; 889 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 890 if (n >= sizeof(fdc->sc_status)) { 891 log(LOG_ERR, "fdcresult: overrun\n"); 892 return -1; 893 } 894 fdc->sc_status[n++] = 895 bus_space_read_1(iot, ioh, fddata); 896 } 897 delay(10); 898 } 899 log(LOG_ERR, "fdcresult: timeout\n"); 900 return -1; 901 } 902 903 int 904 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t x) 905 { 906 int i = 100000; 907 908 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 909 if (i <= 0) 910 return -1; 911 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 912 if (i <= 0) 913 return -1; 914 bus_space_write_1(iot, ioh, fddata, x); 915 return 0; 916 } 917 918 int 919 fdopen(dev_t dev, int flags, int mode, struct lwp *l) 920 { 921 int unit; 922 struct fd_softc *fd; 923 struct fd_type *type; 924 struct fdc_softc *fdc; 925 926 unit = FDUNIT(dev); 927 fd = device_lookup_private(&fd_cd, unit); 928 if (fd == NULL) 929 return ENXIO; 930 type = fd_dev_to_type(fd, dev); 931 if (type == NULL) 932 return ENXIO; 933 934 if ((fd->sc_flags & FD_OPEN) != 0 && 935 fd->sc_type != type) 936 return EBUSY; 937 938 fdc = device_private(device_parent(fd->sc_dev)); 939 if ((fd->sc_flags & FD_OPEN) == 0) { 940 /* Lock eject button */ 941 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 942 0x40 | (1 << unit)); 943 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40); 944 } 945 946 fd->sc_type = type; 947 fd->sc_cylin = -1; 948 949 switch (mode) { 950 case S_IFCHR: 951 fd->sc_flags |= FD_COPEN; 952 break; 953 case S_IFBLK: 954 fd->sc_flags |= FD_BOPEN; 955 break; 956 } 957 958 fdgetdisklabel(fd, dev); 959 960 return 0; 961 } 962 963 int 964 fdclose(dev_t dev, int flags, int mode, struct lwp *l) 965 { 966 int unit = FDUNIT(dev); 967 struct fd_softc *fd = device_lookup_private(&fd_cd, unit); 968 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 969 970 DPRINTF(("fdclose %d\n", unit)); 971 972 switch (mode) { 973 case S_IFCHR: 974 fd->sc_flags &= ~FD_COPEN; 975 break; 976 case S_IFBLK: 977 fd->sc_flags &= ~FD_BOPEN; 978 break; 979 } 980 981 /* clear flags */ 982 fd->sc_opts &= ~(FDOPT_NORETRY | FDOPT_SILENT); 983 984 if ((fd->sc_flags & FD_OPEN) == 0) { 985 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 986 (1 << unit)); 987 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0); 988 } 989 return 0; 990 } 991 992 void 993 fdcstart(struct fdc_softc *fdc) 994 { 995 996 #ifdef DIAGNOSTIC 997 /* 998 * only got here if controller's drive queue was inactive; should 999 * be in idle state 1000 */ 1001 if (fdc->sc_state != DEVIDLE) { 1002 printf("fdcstart: not idle\n"); 1003 return; 1004 } 1005 #endif 1006 (void)fdcintr(fdc); 1007 } 1008 1009 1010 static void 1011 fdcpstatus(int n, struct fdc_softc *fdc) 1012 { 1013 char bits[64]; 1014 1015 switch (n) { 1016 case 0: 1017 printf("\n"); 1018 break; 1019 case 2: 1020 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 1021 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]); 1022 break; 1023 case 7: 1024 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 1025 printf(" (st0 %s", bits); 1026 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]); 1027 printf(" st1 %s", bits); 1028 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]); 1029 printf(" st2 %s", bits); 1030 printf(" cyl %d head %d sec %d)\n", 1031 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 1032 break; 1033 #ifdef DIAGNOSTIC 1034 default: 1035 printf("\nfdcstatus: weird size"); 1036 break; 1037 #endif 1038 } 1039 } 1040 1041 void 1042 fdcstatus(device_t dv, int n, const char *s) 1043 { 1044 struct fdc_softc *fdc = device_private(device_parent(dv)); 1045 1046 if (n == 0) { 1047 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 1048 (void)fdcresult(fdc); 1049 n = 2; 1050 } 1051 1052 printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state); 1053 fdcpstatus(n, fdc); 1054 } 1055 1056 void 1057 fdctimeout(void *arg) 1058 { 1059 struct fdc_softc *fdc = arg; 1060 struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives); 1061 int s; 1062 1063 s = splbio(); 1064 fdcstatus(fd->sc_dev, 0, "timeout"); 1065 1066 if (bufq_peek(fd->sc_q) != NULL) 1067 fdc->sc_state++; 1068 else 1069 fdc->sc_state = DEVIDLE; 1070 1071 (void)fdcintr(fdc); 1072 splx(s); 1073 } 1074 1075 #if 0 1076 void 1077 fdcpseudointr(void *arg) 1078 { 1079 int s; 1080 struct fdc_softc *fdc = arg; 1081 1082 /* just ensure it has the right spl */ 1083 s = splbio(); 1084 (void)fdcintr(fdc); 1085 splx(s); 1086 } 1087 #endif 1088 1089 int 1090 fdcintr(void *arg) 1091 { 1092 struct fdc_softc *fdc = arg; 1093 #define st0 fdc->sc_status[0] 1094 #define cyl fdc->sc_status[1] 1095 struct fd_softc *fd; 1096 struct buf *bp; 1097 bus_space_tag_t iot = fdc->sc_iot; 1098 bus_space_handle_t ioh = fdc->sc_ioh; 1099 int read, head, sec, pos, i, sectrac, nblks; 1100 int tmp; 1101 struct fd_type *type; 1102 struct ne7_fd_formb *finfo = NULL; 1103 1104 loop: 1105 fd = TAILQ_FIRST(&fdc->sc_drives); 1106 if (fd == NULL) { 1107 DPRINTF(("fdcintr: set DEVIDLE\n")); 1108 if (fdc->sc_state == DEVIDLE) { 1109 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC) 1110 != 0) { 1111 out_fdc(iot, ioh, NE7CMD_SENSEI); 1112 if ((tmp = fdcresult(fdc)) != 2 || 1113 (st0 & 0xf8) != 0x20) { 1114 goto loop; 1115 } 1116 } 1117 } 1118 /* no drives waiting; end */ 1119 fdc->sc_state = DEVIDLE; 1120 return 1; 1121 } 1122 1123 /* Is there a transfer to this drive? If not, deactivate drive. */ 1124 bp = bufq_peek(fd->sc_q); 1125 if (bp == NULL) { 1126 fd->sc_ops = 0; 1127 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 1128 fd->sc_active = 0; 1129 goto loop; 1130 } 1131 1132 if (bp->b_flags & B_FORMAT) 1133 finfo = (struct ne7_fd_formb *)bp->b_data; 1134 1135 switch (fdc->sc_state) { 1136 case DEVIDLE: 1137 DPRINTF(("fdcintr: in DEVIDLE\n")); 1138 fdc->sc_errors = 0; 1139 fd->sc_skip = 0; 1140 fd->sc_bcount = bp->b_bcount; 1141 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1142 callout_stop(&fd->sc_motoroff_ch); 1143 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1144 fdc->sc_state = MOTORWAIT; 1145 return 1; 1146 } 1147 if ((fd->sc_flags & FD_MOTOR) == 0) { 1148 /* Turn on the motor */ 1149 /* being careful about other drives. */ 1150 for (i = 0; i < 4; i++) { 1151 struct fd_softc *ofd = fdc->sc_fd[i]; 1152 if (ofd != NULL && 1153 (ofd->sc_flags & FD_MOTOR) != 0) { 1154 callout_stop(&ofd->sc_motoroff_ch); 1155 ofd->sc_flags &= 1156 ~(FD_MOTOR | FD_MOTOR_WAIT); 1157 break; 1158 } 1159 } 1160 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1161 fd_set_motor(fdc, 0); 1162 fdc->sc_state = MOTORWAIT; 1163 #if 0 /* no need to callout on x68k; motor on will trigger interrupts */ 1164 /* allow .5s for motor to stabilize */ 1165 callout_reset(&fd->sc_motoron_ch, hz / 2, 1166 fd_motor_on, fd); 1167 #endif 1168 return 1; 1169 } 1170 /* Make sure the right drive is selected. */ 1171 fd_set_motor(fdc, 0); 1172 1173 /* fall through */ 1174 case DOSEEK: 1175 doseek: 1176 DPRINTF(("fdcintr: in DOSEEK\n")); 1177 if (fd->sc_cylin == bp->b_cylinder) 1178 goto doio; 1179 1180 out_fdc(iot, ioh, NE7CMD_SPECIFY); /* specify command */ 1181 out_fdc(iot, ioh, 0xd0); /* XXX const */ 1182 out_fdc(iot, ioh, 0x10); 1183 1184 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 1185 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 1186 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 1187 1188 fd->sc_cylin = -1; 1189 fdc->sc_state = SEEKWAIT; 1190 1191 iostat_seek(fd->sc_dk.dk_stats); 1192 disk_busy(&fd->sc_dk); 1193 1194 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1195 return 1; 1196 1197 case DOIO: 1198 doio: 1199 DPRINTF(("fdcintr: DOIO: ")); 1200 type = fd->sc_type; 1201 if (finfo != NULL) 1202 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1203 (char *)finfo; 1204 sectrac = type->sectrac; 1205 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2))); 1206 sec = pos / (1 << (type->secsize - 2)); 1207 if (finfo != NULL || type->secsize == 2) { 1208 fd->sc_part = SEC_P11; 1209 nblks = (sectrac - sec) << (type->secsize - 2); 1210 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1211 DPRINTF(("nblks(0)")); 1212 } else if ((fd->sc_blkno % 2) == 0) { 1213 if (fd->sc_bcount & 0x00000200) { 1214 if (fd->sc_bcount == FDC_BSIZE) { 1215 fd->sc_part = SEC_P10; 1216 nblks = 1; 1217 DPRINTF(("nblks(1)")); 1218 } else { 1219 fd->sc_part = SEC_P11; 1220 nblks = (sectrac - sec) * 2; 1221 nblks = min(nblks, 1222 fd->sc_bcount / FDC_BSIZE - 1); 1223 DPRINTF(("nblks(2)")); 1224 } 1225 } else { 1226 fd->sc_part = SEC_P11; 1227 nblks = (sectrac - sec) << (type->secsize - 2); 1228 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1229 DPRINTF(("nblks(3)")); 1230 } 1231 } else { 1232 fd->sc_part = SEC_P01; 1233 nblks = 1; 1234 DPRINTF(("nblks(4)")); 1235 } 1236 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1237 DPRINTF((" %d\n", nblks)); 1238 fd->sc_nblks = nblks; 1239 fd->sc_nbytes = 1240 (finfo != NULL) ? bp->b_bcount : nblks * FDC_BSIZE; 1241 head = (fd->sc_blkno 1242 % (type->seccyl * (1 << (type->secsize - 2)))) 1243 / (type->sectrac * (1 << (type->secsize - 2))); 1244 1245 #ifdef DIAGNOSTIC 1246 { 1247 int block; 1248 block = ((fd->sc_cylin * type->heads + head) * 1249 type->sectrac + sec) * (1 << (type->secsize - 2)); 1250 block += (fd->sc_part == SEC_P01) ? 1 : 0; 1251 if (block != fd->sc_blkno) { 1252 printf("C H R N: %d %d %d %d\n", 1253 fd->sc_cylin, head, sec, type->secsize); 1254 printf("fdcintr: doio: block %d != blkno %" 1255 PRId64 "\n", 1256 block, fd->sc_blkno); 1257 #ifdef DDB 1258 Debugger(); 1259 #endif 1260 } 1261 } 1262 #endif 1263 read = bp->b_flags & B_READ; 1264 DPRINTF(("fdcintr: %s drive %d track %d " 1265 "head %d sec %d nblks %d, skip %d\n", 1266 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, 1267 head, sec, nblks, fd->sc_skip)); 1268 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, 1269 type->secsize)); 1270 1271 if (finfo == NULL && fd->sc_part != SEC_P11) 1272 goto docopy; 1273 1274 fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip, 1275 fd->sc_nbytes); 1276 if (finfo != NULL) { 1277 /* formatting */ 1278 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) { 1279 fdc->sc_errors = 4; 1280 fdcretry(fdc); 1281 goto loop; 1282 } 1283 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1284 out_fdc(iot, ioh, finfo->fd_formb_secshift); 1285 out_fdc(iot, ioh, finfo->fd_formb_nsecs); 1286 out_fdc(iot, ioh, finfo->fd_formb_gaplen); 1287 out_fdc(iot, ioh, finfo->fd_formb_fillbyte); 1288 } else { 1289 if (read) 1290 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1291 else 1292 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1293 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1294 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1295 out_fdc(iot, ioh, head); 1296 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1297 out_fdc(iot, ioh, type->secsize); /* sector size */ 1298 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 1299 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1300 out_fdc(iot, ioh, type->datalen); /* data length */ 1301 } 1302 fdc->sc_state = IOCOMPLETE; 1303 1304 disk_busy(&fd->sc_dk); 1305 1306 /* allow 2 seconds for operation */ 1307 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1308 return 1; /* will return later */ 1309 1310 case DOCOPY: 1311 docopy: 1312 DPRINTF(("fdcintr: DOCOPY:\n")); 1313 type = fd->sc_type; 1314 head = (fd->sc_blkno 1315 % (type->seccyl * (1 << (type->secsize - 2)))) 1316 / (type->sectrac * (1 << (type->secsize - 2))); 1317 pos = fd->sc_blkno % 1318 (type->sectrac * (1 << (type->secsize - 2))); 1319 sec = pos / (1 << (type->secsize - 2)); 1320 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024); 1321 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1322 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1323 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1324 out_fdc(iot, ioh, head); 1325 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1326 out_fdc(iot, ioh, type->secsize); /* sector size */ 1327 out_fdc(iot, ioh, type->sectrac); /* sectors/track */ 1328 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1329 out_fdc(iot, ioh, type->datalen); /* data length */ 1330 fdc->sc_state = COPYCOMPLETE; 1331 /* allow 2 seconds for operation */ 1332 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1333 return 1; /* will return later */ 1334 1335 case DOIOHALF: 1336 doiohalf: 1337 DPRINTF((" DOIOHALF:\n")); 1338 1339 type = fd->sc_type; 1340 sectrac = type->sectrac; 1341 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2))); 1342 sec = pos / (1 << (type->secsize - 2)); 1343 head = (fd->sc_blkno 1344 % (type->seccyl * (1 << (type->secsize - 2)))) 1345 / (type->sectrac * (1 << (type->secsize - 2))); 1346 #ifdef DIAGNOSTIC 1347 { 1348 int block; 1349 block = ((fd->sc_cylin * type->heads + head) * 1350 type->sectrac + sec) * (1 << (type->secsize - 2)); 1351 block += (fd->sc_part == SEC_P01) ? 1 : 0; 1352 if (block != fd->sc_blkno) { 1353 printf("fdcintr: block %d != blkno %" PRId64 1354 "\n", 1355 block, fd->sc_blkno); 1356 #ifdef DDB 1357 Debugger(); 1358 #endif 1359 } 1360 } 1361 #endif 1362 if ((read = bp->b_flags & B_READ)) { 1363 memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf 1364 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0), 1365 FDC_BSIZE); 1366 fdc->sc_state = IOCOMPLETE; 1367 goto iocomplete2; 1368 } else { 1369 memcpy((char *)fd->sc_copybuf 1370 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0), 1371 (char *)bp->b_data + fd->sc_skip, FDC_BSIZE); 1372 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024); 1373 } 1374 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1375 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1376 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */ 1377 out_fdc(iot, ioh, head); 1378 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1379 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */ 1380 out_fdc(iot, ioh, sectrac); /* sectors/track */ 1381 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */ 1382 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */ 1383 fdc->sc_state = IOCOMPLETE; 1384 /* allow 2 seconds for operation */ 1385 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1386 return 1; /* will return later */ 1387 1388 case SEEKWAIT: 1389 callout_stop(&fdc->sc_timo_ch); 1390 fdc->sc_state = SEEKCOMPLETE; 1391 /* allow 1/50 second for heads to settle */ 1392 #if 0 1393 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1394 #endif 1395 return 1; 1396 1397 case SEEKCOMPLETE: 1398 /* Make sure seek really happened */ 1399 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n", 1400 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts))); 1401 out_fdc(iot, ioh, NE7CMD_SENSEI); 1402 tmp = fdcresult(fdc); 1403 if ((st0 & 0xf8) == 0xc0) { 1404 DPRINTF(("fdcintr: first seek!\n")); 1405 fdc->sc_state = DORECAL; 1406 goto loop; 1407 } else if (tmp != 2 || 1408 (st0 & 0xf8) != 0x20 || 1409 cyl != bp->b_cylinder) { 1410 #ifdef FDDEBUG 1411 fdcstatus(fd->sc_dev, 2, "seek failed"); 1412 #endif 1413 fdcretry(fdc); 1414 goto loop; 1415 } 1416 fd->sc_cylin = bp->b_cylinder; 1417 goto doio; 1418 1419 case IOTIMEDOUT: 1420 fdc_dmaabort(fdc); 1421 case SEEKTIMEDOUT: 1422 case RECALTIMEDOUT: 1423 case RESETTIMEDOUT: 1424 fdcretry(fdc); 1425 goto loop; 1426 1427 case IOCOMPLETE: /* IO DONE, post-analyze */ 1428 callout_stop(&fdc->sc_timo_ch); 1429 DPRINTF(("fdcintr: in IOCOMPLETE\n")); 1430 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) { 1431 fdc_dmaabort(fdc); 1432 fdcstatus(fd->sc_dev, tmp, bp->b_flags & B_READ ? 1433 "read failed" : "write failed"); 1434 printf("blkno %" PRId64 " nblks %d\n", 1435 fd->sc_blkno, fd->sc_nblks); 1436 fdcretry(fdc); 1437 goto loop; 1438 } 1439 iocomplete2: 1440 if (fdc->sc_errors) { 1441 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 1442 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1443 printf("\n"); 1444 fdc->sc_errors = 0; 1445 } 1446 fd->sc_blkno += fd->sc_nblks; 1447 fd->sc_skip += fd->sc_nbytes; 1448 fd->sc_bcount -= fd->sc_nbytes; 1449 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount)); 1450 if (finfo == NULL && fd->sc_bcount > 0) { 1451 bp->b_cylinder = fd->sc_blkno 1452 / (fd->sc_type->seccyl 1453 * (1 << (fd->sc_type->secsize - 2))); 1454 goto doseek; 1455 } 1456 fdfinish(fd, bp); 1457 goto loop; 1458 1459 case COPYCOMPLETE: /* IO DONE, post-analyze */ 1460 DPRINTF(("fdcintr: COPYCOMPLETE:")); 1461 callout_stop(&fdc->sc_timo_ch); 1462 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) { 1463 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0); 1464 fdc_dmaabort(fdc); 1465 fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ? 1466 "read failed" : "write failed"); 1467 printf("blkno %" PRId64 " nblks %d\n", 1468 fd->sc_blkno, fd->sc_nblks); 1469 fdcretry(fdc); 1470 goto loop; 1471 } 1472 goto doiohalf; 1473 1474 case DORESET: 1475 DPRINTF(("fdcintr: in DORESET\n")); 1476 /* try a reset, keep motor on */ 1477 fd_set_motor(fdc, 1); 1478 DELAY(100); 1479 fd_set_motor(fdc, 0); 1480 fdc->sc_state = RESETCOMPLETE; 1481 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1482 return 1; /* will return later */ 1483 1484 case RESETCOMPLETE: 1485 DPRINTF(("fdcintr: in RESETCOMPLETE\n")); 1486 callout_stop(&fdc->sc_timo_ch); 1487 /* clear the controller output buffer */ 1488 for (i = 0; i < 4; i++) { 1489 out_fdc(iot, ioh, NE7CMD_SENSEI); 1490 (void)fdcresult(fdc); 1491 } 1492 1493 /* fall through */ 1494 case DORECAL: 1495 DPRINTF(("fdcintr: in DORECAL\n")); 1496 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 1497 out_fdc(iot, ioh, fd->sc_drive); 1498 fdc->sc_state = RECALWAIT; 1499 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1500 return 1; /* will return later */ 1501 1502 case RECALWAIT: 1503 DPRINTF(("fdcintr: in RECALWAIT\n")); 1504 callout_stop(&fdc->sc_timo_ch); 1505 fdc->sc_state = RECALCOMPLETE; 1506 /* allow 1/30 second for heads to settle */ 1507 #if 0 1508 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1509 #endif 1510 return 1; /* will return later */ 1511 1512 case RECALCOMPLETE: 1513 DPRINTF(("fdcintr: in RECALCOMPLETE\n")); 1514 out_fdc(iot, ioh, NE7CMD_SENSEI); 1515 tmp = fdcresult(fdc); 1516 if ((st0 & 0xf8) == 0xc0) { 1517 DPRINTF(("fdcintr: first seek!\n")); 1518 fdc->sc_state = DORECAL; 1519 goto loop; 1520 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1521 #ifdef FDDEBUG 1522 fdcstatus(fd->sc_dev, 2, "recalibrate failed"); 1523 #endif 1524 fdcretry(fdc); 1525 goto loop; 1526 } 1527 fd->sc_cylin = 0; 1528 goto doseek; 1529 1530 case MOTORWAIT: 1531 #if 0 /* on x68k motor on triggers interrupts by state change of ready line. */ 1532 if (fd->sc_flags & FD_MOTOR_WAIT) 1533 return 1; /* time's not up yet */ 1534 #else 1535 /* check drive ready by state change interrupt */ 1536 KASSERT(fd->sc_flags & FD_MOTOR_WAIT); 1537 out_fdc(iot, ioh, NE7CMD_SENSEI); 1538 tmp = fdcresult(fdc); 1539 if (tmp != 2 || (st0 & 0xc0) != 0xc0 /* ready changed */) { 1540 printf("%s: unexpected interrupt during MOTORWAIT", 1541 device_xname(fd->sc_dev)); 1542 fdcpstatus(7, fdc); 1543 return 1; 1544 } 1545 fd->sc_flags &= ~FD_MOTOR_WAIT; 1546 #endif 1547 goto doseek; 1548 1549 default: 1550 fdcstatus(fd->sc_dev, 0, "stray interrupt"); 1551 return 1; 1552 } 1553 #ifdef DIAGNOSTIC 1554 panic("fdcintr: impossible"); 1555 #endif 1556 #undef st0 1557 #undef cyl 1558 } 1559 1560 void 1561 fdcretry(struct fdc_softc *fdc) 1562 { 1563 struct fd_softc *fd; 1564 struct buf *bp; 1565 1566 DPRINTF(("fdcretry:\n")); 1567 fd = TAILQ_FIRST(&fdc->sc_drives); 1568 bp = bufq_peek(fd->sc_q); 1569 1570 if (fd->sc_opts & FDOPT_NORETRY) 1571 goto fail; 1572 1573 switch (fdc->sc_errors) { 1574 case 0: 1575 /* try again */ 1576 fdc->sc_state = SEEKCOMPLETE; 1577 break; 1578 1579 case 1: 1580 case 2: 1581 case 3: 1582 /* didn't work; try recalibrating */ 1583 fdc->sc_state = DORECAL; 1584 break; 1585 1586 case 4: 1587 /* still no go; reset the bastard */ 1588 fdc->sc_state = DORESET; 1589 break; 1590 1591 default: 1592 fail: 1593 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1594 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1595 fd->sc_skip, (struct disklabel *)NULL); 1596 fdcpstatus(7, fdc); 1597 } 1598 1599 bp->b_error = EIO; 1600 fdfinish(fd, bp); 1601 } 1602 fdc->sc_errors++; 1603 } 1604 1605 int 1606 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1607 { 1608 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 1609 struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); 1610 struct fdformat_parms *form_parms; 1611 struct fdformat_cmd *form_cmd; 1612 struct ne7_fd_formb *fd_formb; 1613 int part = DISKPART(dev); 1614 struct disklabel buffer; 1615 int error; 1616 unsigned int scratch; 1617 int il[FD_MAX_NSEC + 1]; 1618 int i, j; 1619 1620 error = disk_ioctl(&fd->sc_dk, dev, cmd, addr, flag, l); 1621 if (error != EPASSTHROUGH) 1622 return error; 1623 1624 DPRINTF(("fdioctl:")); 1625 switch (cmd) { 1626 case DIOCWLABEL: 1627 DPRINTF(("DIOCWLABEL\n")); 1628 if ((flag & FWRITE) == 0) 1629 return EBADF; 1630 /* XXX do something */ 1631 return 0; 1632 1633 case DIOCWDINFO: 1634 DPRINTF(("DIOCWDINFO\n")); 1635 if ((flag & FWRITE) == 0) 1636 return EBADF; 1637 1638 error = setdisklabel(&buffer, (struct disklabel *)addr, 1639 0, NULL); 1640 if (error) 1641 return error; 1642 1643 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1644 return error; 1645 1646 case FDIOCGETFORMAT: 1647 DPRINTF(("FDIOCGETFORMAT\n")); 1648 form_parms = (struct fdformat_parms *)addr; 1649 form_parms->fdformat_version = FDFORMAT_VERSION; 1650 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1651 form_parms->ncyl = fd->sc_type->cyls; 1652 form_parms->nspt = fd->sc_type->sectrac; 1653 form_parms->ntrk = fd->sc_type->heads; 1654 form_parms->stepspercyl = fd->sc_type->step; 1655 form_parms->gaplen = fd->sc_type->gap2; 1656 form_parms->fillbyte = fd->sc_type->fillbyte; 1657 form_parms->interleave = fd->sc_type->interleave; 1658 switch (fd->sc_type->rate) { 1659 case FDC_500KBPS: 1660 form_parms->xfer_rate = 500 * 1024; 1661 break; 1662 case FDC_300KBPS: 1663 form_parms->xfer_rate = 300 * 1024; 1664 break; 1665 case FDC_250KBPS: 1666 form_parms->xfer_rate = 250 * 1024; 1667 break; 1668 default: 1669 return EINVAL; 1670 } 1671 return 0; 1672 1673 case FDIOCSETFORMAT: 1674 DPRINTF(("FDIOCSETFORMAT\n")); 1675 if((flag & FWRITE) == 0) 1676 return EBADF; /* must be opened for writing */ 1677 form_parms = (struct fdformat_parms *)addr; 1678 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1679 return EINVAL; /* wrong version of formatting prog */ 1680 1681 scratch = form_parms->nbps >> 7; 1682 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1683 scratch & ~(1 << (ffs(scratch) - 1))) 1684 /* not a power-of-two multiple of 128 */ 1685 return EINVAL; 1686 1687 switch (form_parms->xfer_rate) { 1688 case 500 * 1024: 1689 fd->sc_type->rate = FDC_500KBPS; 1690 break; 1691 case 300 * 1024: 1692 fd->sc_type->rate = FDC_300KBPS; 1693 break; 1694 case 250 * 1024: 1695 fd->sc_type->rate = FDC_250KBPS; 1696 break; 1697 default: 1698 return EINVAL; 1699 } 1700 1701 if (form_parms->nspt > FD_MAX_NSEC || 1702 form_parms->fillbyte > 0xff || 1703 form_parms->interleave > 0xff) 1704 return EINVAL; 1705 fd->sc_type->sectrac = form_parms->nspt; 1706 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1707 return EINVAL; 1708 fd->sc_type->heads = form_parms->ntrk; 1709 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1710 fd->sc_type->secsize = ffs(scratch)-1; 1711 fd->sc_type->gap2 = form_parms->gaplen; 1712 fd->sc_type->cyls = form_parms->ncyl; 1713 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1714 form_parms->nbps / DEV_BSIZE; 1715 fd->sc_type->step = form_parms->stepspercyl; 1716 fd->sc_type->fillbyte = form_parms->fillbyte; 1717 fd->sc_type->interleave = form_parms->interleave; 1718 return 0; 1719 1720 case FDIOCFORMAT_TRACK: 1721 DPRINTF(("FDIOCFORMAT_TRACK\n")); 1722 if ((flag & FWRITE) == 0) 1723 return EBADF; /* must be opened for writing */ 1724 form_cmd = (struct fdformat_cmd *)addr; 1725 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1726 return EINVAL; /* wrong version of formatting prog */ 1727 1728 if (form_cmd->head >= fd->sc_type->heads || 1729 form_cmd->cylinder >= fd->sc_type->cyls) { 1730 return EINVAL; 1731 } 1732 1733 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1734 M_TEMP, M_NOWAIT); 1735 if (fd_formb == NULL) 1736 return ENOMEM; 1737 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