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