1 /* $NetBSD: fd.c,v 1.51 2011/07/19 15:59:53 dyoung 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. 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 * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp 65 */ 66 67 /* 68 * Floppy formatting facilities merged from FreeBSD fd.c driver: 69 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp 70 * which carries the same copyright/redistribution notice as shown above with 71 * the addition of the following statement before the "Redistribution and 72 * use ..." clause: 73 * 74 * Copyright (c) 1993, 1994 by 75 * jc@irbs.UUCP (John Capo) 76 * vak@zebub.msk.su (Serge Vakulenko) 77 * ache@astral.msk.su (Andrew A. Chernov) 78 * 79 * Copyright (c) 1993, 1994, 1995 by 80 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 81 * dufault@hda.com (Peter Dufault) 82 */ 83 84 #include <sys/cdefs.h> 85 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.51 2011/07/19 15:59:53 dyoung Exp $"); 86 87 #include "opt_ddb.h" 88 89 #include <sys/param.h> 90 #include <sys/systm.h> 91 #include <sys/callout.h> 92 #include <sys/kernel.h> 93 #include <sys/file.h> 94 #include <sys/ioctl.h> 95 #include <sys/device.h> 96 #include <sys/disklabel.h> 97 #include <sys/disk.h> 98 #include <sys/buf.h> 99 #include <sys/bufq.h> 100 #include <sys/malloc.h> 101 #include <sys/uio.h> 102 #include <sys/syslog.h> 103 #include <sys/queue.h> 104 #include <sys/proc.h> 105 #include <sys/fdio.h> 106 #include <sys/conf.h> 107 #include <sys/bus.h> 108 109 #include <uvm/uvm_extern.h> 110 111 #include <arm/fiq.h> 112 113 #include <machine/cpu.h> 114 #include <machine/intr.h> 115 #include <machine/io.h> 116 #include <arm/arm32/katelib.h> 117 118 #include <arm/iomd/iomdreg.h> 119 #include <arm/iomd/iomdvar.h> 120 121 #include <acorn32/mainbus/piocvar.h> 122 #include <acorn32/mainbus/fdreg.h> 123 124 #include "locators.h" 125 126 #define NE7CMD_CONFIGURE 0x13 127 128 #define FDUNIT(dev) (minor(dev) / 8) 129 #define FDTYPE(dev) (minor(dev) % 8) 130 131 /* (mis)use device use flag to identify format operation */ 132 #define B_FORMAT B_DEVPRIVATE 133 134 enum fdc_state { 135 DEVIDLE = 0, 136 MOTORWAIT, 137 DOSEEK, 138 SEEKWAIT, 139 SEEKTIMEDOUT, 140 SEEKCOMPLETE, 141 DOIO, 142 IOCOMPLETE, 143 IOTIMEDOUT, 144 DORESET, 145 RESETCOMPLETE, 146 RESETTIMEDOUT, 147 DORECAL, 148 RECALWAIT, 149 RECALTIMEDOUT, 150 RECALCOMPLETE, 151 }; 152 153 /* software state, per controller */ 154 struct fdc_softc { 155 struct device sc_dev; /* boilerplate */ 156 void *sc_ih; 157 158 bus_space_tag_t sc_iot; /* ISA i/o space identifier */ 159 bus_space_handle_t sc_ioh; /* ISA io handle */ 160 161 struct callout sc_timo_ch; /* timeout callout */ 162 struct callout sc_intr_ch; /* pseudo-intr callout */ 163 164 /* ...for pseudo-DMA... */ 165 struct fiqhandler sc_fh; /* FIQ handler descriptor */ 166 struct fiqregs sc_fr; /* FIQ handler reg context */ 167 int sc_drq; 168 169 struct fd_softc *sc_fd[4]; /* pointers to children */ 170 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 171 enum fdc_state sc_state; 172 int sc_errors; /* number of retries so far */ 173 u_char sc_status[7]; /* copy of registers */ 174 }; 175 176 /* controller driver configuration */ 177 int fdcprobe(device_t, cfdata_t, void *); 178 int fdprint(void *, const char *); 179 void fdcattach(device_t, device_t, void *); 180 181 CFATTACH_DECL(fdc, sizeof(struct fdc_softc), 182 fdcprobe, fdcattach, NULL, NULL); 183 184 /* 185 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 186 * we tell them apart. 187 */ 188 struct fd_type { 189 int sectrac; /* sectors per track */ 190 int heads; /* number of heads */ 191 int seccyl; /* sectors per cylinder */ 192 int secsize; /* size code for sectors */ 193 int datalen; /* data len when secsize = 0 */ 194 int steprate; /* step rate and head unload time */ 195 int gap1; /* gap len between sectors */ 196 int gap2; /* formatting gap */ 197 int cyls; /* total num of cylinders */ 198 int size; /* size of disk in sectors */ 199 int step; /* steps per cylinder */ 200 int rate; /* transfer speed code */ 201 u_char fillbyte; /* format fill byte */ 202 u_char interleave; /* interleave factor (formatting) */ 203 const char *name; 204 }; 205 206 /* The order of entries in the following table is important -- BEWARE! */ 207 struct fd_type fd_types[] = { 208 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */ 209 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */ 210 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */ 211 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */ 212 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */ 213 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */ 214 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */ 215 }; 216 217 /* software state, per disk (with up to 4 disks per ctlr) */ 218 struct fd_softc { 219 struct device sc_dev; 220 struct disk sc_dk; 221 222 struct fd_type *sc_deftype; /* default type descriptor */ 223 struct fd_type *sc_type; /* current type descriptor */ 224 struct fd_type sc_type_copy; /* copy for fiddling when formatting */ 225 226 struct callout sc_motoron_ch; 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_OPEN 0x01 /* it's open */ 239 #define FD_MOTOR 0x02 /* motor should be on */ 240 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 241 int sc_cylin; /* where we think the head is */ 242 243 void *sc_sdhook; /* saved shutdown hook for drive. */ 244 245 TAILQ_ENTRY(fd_softc) sc_drivechain; 246 int sc_ops; /* I/O ops since last switch */ 247 struct bufq_state *sc_q;/* pending I/O requests */ 248 int sc_active; /* number of active I/O operations */ 249 }; 250 251 /* floppy driver configuration */ 252 int fdprobe(device_t, cfdata_t, void *); 253 void fdattach(device_t, device_t, void *); 254 255 extern char floppy_read_fiq[], floppy_read_fiq_end[]; 256 extern char floppy_write_fiq[], floppy_write_fiq_end[]; 257 258 CFATTACH_DECL(fd, sizeof(struct fd_softc), 259 fdprobe, fdattach, NULL, NULL); 260 261 extern struct cfdriver fd_cd; 262 263 dev_type_open(fdopen); 264 dev_type_close(fdclose); 265 dev_type_read(fdread); 266 dev_type_write(fdwrite); 267 dev_type_ioctl(fdioctl); 268 dev_type_strategy(fdstrategy); 269 270 const struct bdevsw fd_bdevsw = { 271 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 272 }; 273 274 const struct cdevsw fd_cdevsw = { 275 fdopen, fdclose, fdread, fdwrite, fdioctl, 276 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 277 }; 278 279 void fdgetdisklabel(struct fd_softc *); 280 int fd_get_parms(struct fd_softc *); 281 void fdstart(struct fd_softc *); 282 283 struct dkdriver fddkdriver = { fdstrategy }; 284 285 struct fd_type *fd_nvtotype(const char *, int, int); 286 void fd_set_motor(struct fdc_softc *fdc, int reset); 287 void fd_motor_off(void *arg); 288 void fd_motor_on(void *arg); 289 int fdcresult(struct fdc_softc *fdc); 290 int out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x); 291 void fdcstart(struct fdc_softc *fdc); 292 void fdcstatus(device_t dv, int n, const char *s); 293 void fdctimeout(void *arg); 294 void fdcpseudointr(void *arg); 295 int fdcintr(void *); 296 void fdcretry(struct fdc_softc *fdc); 297 void fdfinish(struct fd_softc *fd, struct buf *bp); 298 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t); 299 int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *); 300 301 int 302 fdcprobe(device_t parent, cfdata_t cf, void *aux) 303 { 304 struct pioc_attach_args *pa = aux; 305 bus_space_tag_t iot; 306 bus_space_handle_t ioh; 307 int rv; 308 309 if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0) 310 return(0); 311 312 iot = pa->pa_iot; 313 rv = 0; 314 315 /* Map the i/o space. */ 316 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 317 return 0; 318 319 /* reset */ 320 bus_space_write_2(iot, ioh, fdout, 0); 321 delay(100); 322 bus_space_write_2(iot, ioh, fdout, FDO_FRST); 323 324 /* see if it can handle a command */ 325 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) 326 goto out; 327 out_fdc(iot, ioh, 0xdf); 328 out_fdc(iot, ioh, 2); 329 330 rv = 1; 331 pa->pa_iosize = FDC_NPORT; 332 333 out: 334 bus_space_unmap(iot, ioh, FDC_NPORT); 335 return rv; 336 } 337 338 /* 339 * Arguments passed between fdcattach and fdprobe. 340 */ 341 struct fdc_attach_args { 342 int fa_drive; 343 struct fd_type *fa_deftype; 344 }; 345 346 /* 347 * Print the location of a disk drive (called just before attaching the 348 * the drive). If `fdc' is not NULL, the drive was found but was not 349 * in the system config file; print the drive name as well. 350 * Return QUIET (config_find ignores this if the device was configured) to 351 * avoid printing `fdN not configured' messages. 352 */ 353 int 354 fdprint(void *aux, const char *fdc) 355 { 356 register struct fdc_attach_args *fa = aux; 357 358 if (!fdc) 359 aprint_normal(" drive %d", fa->fa_drive); 360 return QUIET; 361 } 362 363 void 364 fdcattach(device_t parent, device_t self, void *aux) 365 { 366 struct fdc_softc *fdc = device_private(self); 367 bus_space_tag_t iot; 368 bus_space_handle_t ioh; 369 struct pioc_attach_args *pa = aux; 370 struct fdc_attach_args fa; 371 int type; 372 373 iot = pa->pa_iot; 374 375 /* Re-map the I/O space. */ 376 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 377 panic("fdcattach: couldn't map I/O ports"); 378 379 fdc->sc_iot = iot; 380 fdc->sc_ioh = ioh; 381 382 fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq; 383 fdc->sc_state = DEVIDLE; 384 TAILQ_INIT(&fdc->sc_drives); 385 386 printf("\n"); 387 388 callout_init(&fdc->sc_timo_ch, 0); 389 callout_init(&fdc->sc_intr_ch, 0); 390 391 fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc", fdcintr, fdc); 392 if (!fdc->sc_ih) 393 panic("%s: Cannot claim IRQ %d", 394 device_xname(self), pa->pa_irq); 395 396 #if 0 397 /* 398 * The NVRAM info only tells us about the first two disks on the 399 * `primary' floppy controller. 400 */ 401 if (device_unit(&fdc->sc_dev) == 0) 402 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */ 403 else 404 type = -1; 405 #endif 406 type = 0x10; /* XXX - hardcoded for 1 floppy */ 407 408 /* physical limit: four drives per controller. */ 409 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 410 if (type >= 0 && fa.fa_drive < 2) 411 fa.fa_deftype = fd_nvtotype(device_xname(&fdc->sc_dev), 412 type, fa.fa_drive); 413 else 414 fa.fa_deftype = NULL; /* unknown */ 415 (void)config_found(self, (void *)&fa, fdprint); 416 } 417 } 418 419 int 420 fdprobe(device_t parent, cfdata_t cf, void *aux) 421 { 422 struct fdc_softc *fdc = device_private(parent); 423 struct fdc_attach_args *fa = aux; 424 int drive = fa->fa_drive; 425 bus_space_tag_t iot = fdc->sc_iot; 426 bus_space_handle_t ioh = fdc->sc_ioh; 427 int n; 428 429 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT 430 && cf->cf_loc[FDCCF_DRIVE] != drive) 431 return 0; 432 /* 433 * XXX 434 * This is to work around some odd interactions between this driver 435 * and SMC Ethernet cards. 436 */ 437 438 /* Don't need this for arm32 port but leave for the time being (it won't hurt) */ 439 440 if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2) 441 return 0; 442 443 /* select drive and turn on motor */ 444 bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive)); 445 /* wait for motor to spin up */ 446 delay(250000); 447 out_fdc(iot, ioh, NE7CMD_RECAL); 448 out_fdc(iot, ioh, drive); 449 /* wait for recalibrate */ 450 delay(2000000); 451 out_fdc(iot, ioh, NE7CMD_SENSEI); 452 n = fdcresult(fdc); 453 #ifdef FD_DEBUG 454 { 455 int i; 456 printf("fdprobe: status"); 457 for (i = 0; i < n; i++) 458 printf(" %x", fdc->sc_status[i]); 459 printf("\n"); 460 } 461 #endif 462 /* turn off motor */ 463 bus_space_write_1(iot, ioh, fdout, FDO_FRST); 464 465 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 466 return 0; 467 468 return 1; 469 } 470 471 /* 472 * Controller is working, and drive responded. Attach it. 473 */ 474 void 475 fdattach(device_t parent, device_t self, void *aux) 476 { 477 struct fdc_softc *fdc = device_private(parent); 478 struct fd_softc *fd = device_private(self); 479 struct fdc_attach_args *fa = aux; 480 struct fd_type *type = fa->fa_deftype; 481 int drive = fa->fa_drive; 482 483 callout_init(&fd->sc_motoron_ch, 0); 484 callout_init(&fd->sc_motoroff_ch, 0); 485 486 /* XXX Allow `flags' to override device type? */ 487 488 if (type) 489 printf(": %s %d cyl, %d head, %d sec\n", type->name, 490 type->cyls, type->heads, type->sectrac); 491 else 492 printf(": density unknown\n"); 493 494 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 495 fd->sc_cylin = -1; 496 fd->sc_drive = drive; 497 fd->sc_deftype = type; 498 fdc->sc_fd[drive] = fd; 499 500 /* 501 * Initialize and attach the disk structure. 502 */ 503 disk_init(&fd->sc_dk, device_xname(&fd->sc_dev), &fddkdriver); 504 disk_attach(&fd->sc_dk); 505 506 /* Needed to power off if the motor is on when we halt. */ 507 508 } 509 510 /* 511 * Translate nvram type into internal data structure. Return NULL for 512 * none/unknown/unusable. 513 */ 514 struct fd_type * 515 fd_nvtotype(const char *fdc, int nvraminfo, int drive) 516 { 517 int type; 518 519 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 520 switch (type) { 521 #ifndef RC7500 522 case 0x00 : 523 return NULL; 524 #else 525 case 0x00 : 526 #endif /* !RC7500 */ 527 case 0x10 : 528 return &fd_types[0]; 529 default: 530 printf("%s: drive %d: unknown device type 0x%x\n", 531 fdc, drive, type); 532 return NULL; 533 } 534 } 535 536 inline struct fd_type * 537 fd_dev_to_type(struct fd_softc *fd, dev_t dev) 538 { 539 int type = FDTYPE(dev); 540 541 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 542 return NULL; 543 return type ? &fd_types[type - 1] : fd->sc_deftype; 544 } 545 546 void 547 fdstrategy(struct buf *bp) 548 { 549 struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(bp->b_dev)); 550 int sz; 551 int s; 552 553 /* Valid unit, controller, and request? */ 554 if (bp->b_blkno < 0 || 555 ((bp->b_bcount % FDC_BSIZE) != 0 && 556 (bp->b_flags & B_FORMAT) == 0)) { 557 bp->b_error = EINVAL; 558 goto done; 559 } 560 561 /* If it's a null transfer, return immediately. */ 562 if (bp->b_bcount == 0) 563 goto done; 564 565 sz = howmany(bp->b_bcount, FDC_BSIZE); 566 567 if (bp->b_blkno + sz > fd->sc_type->size) { 568 sz = fd->sc_type->size - bp->b_blkno; 569 if (sz == 0) { 570 /* If exactly at end of disk, return EOF. */ 571 goto done; 572 } 573 if (sz < 0) { 574 /* If past end of disk, return EINVAL. */ 575 bp->b_error = EINVAL; 576 goto done; 577 } 578 /* Otherwise, truncate request. */ 579 bp->b_bcount = sz << DEV_BSHIFT; 580 } 581 582 bp->b_rawblkno = bp->b_blkno; 583 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 584 585 #ifdef FD_DEBUG 586 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n", 587 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz); 588 #endif 589 590 /* Queue transfer on drive, activate drive and controller if idle. */ 591 s = splbio(); 592 bufq_put(fd->sc_q, bp); 593 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 594 if (fd->sc_active == 0) 595 fdstart(fd); 596 #ifdef DIAGNOSTIC 597 else { 598 struct fdc_softc *fdc = 599 device_private(device_parent(&fd->sc_dev)); 600 if (fdc->sc_state == DEVIDLE) { 601 printf("fdstrategy: controller inactive\n"); 602 fdcstart(fdc); 603 } 604 } 605 #endif 606 splx(s); 607 return; 608 609 done: 610 /* Toss transfer; we're done early. */ 611 bp->b_resid = bp->b_bcount; 612 biodone(bp); 613 } 614 615 void 616 fdstart(struct fd_softc *fd) 617 { 618 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 619 int active = fdc->sc_drives.tqh_first != 0; 620 621 /* Link into controller queue. */ 622 fd->sc_active = 1; 623 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 624 625 /* If controller not already active, start it. */ 626 if (!active) 627 fdcstart(fdc); 628 } 629 630 void 631 fdfinish(struct fd_softc *fd, struct buf *bp) 632 { 633 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 634 635 /* 636 * Move this drive to the end of the queue to give others a `fair' 637 * chance. We only force a switch if N operations are completed while 638 * another drive is waiting to be serviced, since there is a long motor 639 * startup delay whenever we switch. 640 */ 641 (void)bufq_get(fd->sc_q); 642 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 643 fd->sc_ops = 0; 644 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 645 if (bufq_peek(fd->sc_q) != NULL) 646 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 647 else 648 fd->sc_active = 0; 649 } 650 bp->b_resid = fd->sc_bcount; 651 fd->sc_skip = 0; 652 653 biodone(bp); 654 /* turn off motor 5s from now */ 655 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 656 fdc->sc_state = DEVIDLE; 657 } 658 659 int 660 fdread(dev_t dev, struct uio *uio, int flags) 661 { 662 663 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 664 } 665 666 int 667 fdwrite(dev_t dev, struct uio *uio, int flags) 668 { 669 670 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 671 } 672 673 void 674 fd_set_motor(struct fdc_softc *fdc, int reset) 675 { 676 struct fd_softc *fd; 677 u_char status; 678 int n; 679 680 if ((fd = fdc->sc_drives.tqh_first) != NULL) 681 status = fd->sc_drive; 682 else 683 status = 0; 684 if (!reset) 685 status |= FDO_FRST | FDO_FDMAEN; 686 for (n = 0; n < 4; n++) 687 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 688 status |= FDO_MOEN(n); 689 bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status); 690 } 691 692 void 693 fd_motor_off(void *arg) 694 { 695 struct fd_softc *fd = arg; 696 int s; 697 698 s = splbio(); 699 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 700 fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0); 701 splx(s); 702 } 703 704 void 705 fd_motor_on(void *arg) 706 { 707 struct fd_softc *fd = arg; 708 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 709 int s; 710 711 s = splbio(); 712 fd->sc_flags &= ~FD_MOTOR_WAIT; 713 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 714 (void) fdcintr(fdc); 715 splx(s); 716 } 717 718 int 719 fdcresult(struct fdc_softc *fdc) 720 { 721 bus_space_tag_t iot = fdc->sc_iot; 722 bus_space_handle_t ioh = fdc->sc_ioh; 723 u_char i; 724 int j = 100000, 725 n = 0; 726 727 for (; j; j--) { 728 i = bus_space_read_1(iot, ioh, fdsts) & 729 (NE7_DIO | NE7_RQM | NE7_CB); 730 if (i == NE7_RQM) 731 return n; 732 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 733 if (n >= sizeof(fdc->sc_status)) { 734 log(LOG_ERR, "fdcresult: overrun\n"); 735 return -1; 736 } 737 fdc->sc_status[n++] = 738 bus_space_read_1(iot, ioh, fddata); 739 } 740 delay(10); 741 } 742 log(LOG_ERR, "fdcresult: timeout\n"); 743 return -1; 744 } 745 746 int 747 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x) 748 { 749 int i = 100000; 750 751 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 752 if (i <= 0) 753 return -1; 754 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 755 if (i <= 0) 756 return -1; 757 bus_space_write_2(iot, ioh, fddata, x); 758 return 0; 759 } 760 761 int 762 fdopen(dev_t dev, int flags, int mode, struct lwp *l) 763 { 764 struct fd_softc *fd; 765 struct fd_type *type; 766 767 fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 768 if (fd == NULL) 769 return ENXIO; 770 type = fd_dev_to_type(fd, dev); 771 if (type == NULL) 772 return ENXIO; 773 774 if ((fd->sc_flags & FD_OPEN) != 0 && 775 memcmp(fd->sc_type, type, sizeof(*type))) 776 return EBUSY; 777 778 fd->sc_type_copy = *type; 779 fd->sc_type = &fd->sc_type_copy; 780 fd->sc_cylin = -1; 781 fd->sc_flags |= FD_OPEN; 782 783 return 0; 784 } 785 786 int 787 fdclose(dev_t dev, int flags, int mode, struct lwp *l) 788 { 789 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 790 791 fd->sc_flags &= ~FD_OPEN; 792 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 793 return 0; 794 } 795 796 void 797 fdcstart(struct fdc_softc *fdc) 798 { 799 800 #ifdef DIAGNOSTIC 801 /* only got here if controller's drive queue was inactive; should 802 be in idle state */ 803 if (fdc->sc_state != DEVIDLE) { 804 printf("fdcstart: not idle\n"); 805 return; 806 } 807 #endif 808 (void) fdcintr(fdc); 809 } 810 811 static void 812 fdcpstatus(int n, struct fdc_softc *fdc) 813 { 814 char bits[64]; 815 816 switch (n) { 817 case 0: 818 printf("\n"); 819 break; 820 case 2: 821 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 822 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]); 823 break; 824 case 7: 825 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 826 printf(" (st0 %s", bits); 827 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]); 828 printf(" st1 %s", bits); 829 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]); 830 printf(" st2 %s", bits); 831 printf(" cyl %d head %d sec %d)\n", 832 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 833 break; 834 #ifdef DIAGNOSTIC 835 default: 836 printf("\nfdcstatus: weird size"); 837 break; 838 #endif 839 } 840 } 841 842 void 843 fdcstatus(device_t dv, int n, const char *s) 844 { 845 struct fdc_softc *fdc = (void *) device_parent(dv); 846 847 if (n == 0) { 848 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 849 (void) fdcresult(fdc); 850 n = 2; 851 } 852 853 printf("%s: %s", device_xname(dv), s); 854 fdcpstatus(n, fdc); 855 } 856 857 void 858 fdctimeout(void *arg) 859 { 860 struct fdc_softc *fdc = arg; 861 struct fd_softc *fd = fdc->sc_drives.tqh_first; 862 int s; 863 864 s = splbio(); 865 #ifdef DEBUG 866 log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state); 867 #endif 868 fdcstatus(&fd->sc_dev, 0, "timeout"); 869 870 if (bufq_peek(fd->sc_q) != NULL) 871 fdc->sc_state++; 872 else 873 fdc->sc_state = DEVIDLE; 874 875 (void) fdcintr(fdc); 876 splx(s); 877 } 878 879 void 880 fdcpseudointr(void *arg) 881 { 882 int s; 883 884 /* Just ensure it has the right spl. */ 885 s = splbio(); 886 (void) fdcintr(arg); 887 splx(s); 888 } 889 890 int 891 fdcintr(void *arg) 892 { 893 struct fdc_softc *fdc = arg; 894 #define st0 fdc->sc_status[0] 895 #define cyl fdc->sc_status[1] 896 struct fd_softc *fd; 897 struct buf *bp; 898 bus_space_tag_t iot = fdc->sc_iot; 899 bus_space_handle_t ioh = fdc->sc_ioh; 900 int read, head, sec, i, nblks; 901 struct fd_type *type; 902 struct ne7_fd_formb *finfo = NULL; 903 904 loop: 905 /* Is there a drive for the controller to do a transfer with? */ 906 fd = fdc->sc_drives.tqh_first; 907 if (fd == NULL) { 908 fdc->sc_state = DEVIDLE; 909 return 1; 910 } 911 912 /* Is there a transfer to this drive? If not, deactivate drive. */ 913 bp = bufq_peek(fd->sc_q); 914 if (bp == NULL) { 915 fd->sc_ops = 0; 916 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 917 fd->sc_active = 0; 918 goto loop; 919 } 920 921 if (bp->b_flags & B_FORMAT) 922 finfo = (struct ne7_fd_formb *)bp->b_data; 923 924 switch (fdc->sc_state) { 925 case DEVIDLE: 926 fdc->sc_errors = 0; 927 fd->sc_skip = 0; 928 fd->sc_bcount = bp->b_bcount; 929 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 930 callout_stop(&fd->sc_motoroff_ch); 931 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 932 fdc->sc_state = MOTORWAIT; 933 return 1; 934 } 935 if ((fd->sc_flags & FD_MOTOR) == 0) { 936 /* Turn on the motor, being careful about pairing. */ 937 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 938 if (ofd && ofd->sc_flags & FD_MOTOR) { 939 callout_stop(&ofd->sc_motoroff_ch); 940 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 941 } 942 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 943 fd_set_motor(fdc, 0); 944 fdc->sc_state = MOTORWAIT; 945 /* Allow .25s for motor to stabilize. */ 946 callout_reset(&fd->sc_motoron_ch, hz / 4, 947 fd_motor_on, fd); 948 return 1; 949 } 950 /* Make sure the right drive is selected. */ 951 fd_set_motor(fdc, 0); 952 953 /* fall through */ 954 case DOSEEK: 955 doseek: 956 if (fd->sc_cylin == bp->b_cylinder) 957 goto doio; 958 959 #if 1 960 out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */ 961 out_fdc(iot, ioh, 0); 962 out_fdc(iot, ioh, 0x18); 963 out_fdc(iot, ioh, 0); 964 #endif 965 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 966 out_fdc(iot, ioh, fd->sc_type->steprate); 967 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ 968 969 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 970 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 971 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 972 973 fd->sc_cylin = -1; 974 fdc->sc_state = SEEKWAIT; 975 976 iostat_seek(fd->sc_dk.dk_stats); 977 disk_busy(&fd->sc_dk); 978 979 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 980 return 1; 981 982 case DOIO: 983 doio: 984 type = fd->sc_type; 985 if (finfo) 986 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 987 (char *)finfo; 988 sec = fd->sc_blkno % type->seccyl; 989 nblks = type->seccyl - sec; 990 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 991 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 992 fd->sc_nblks = nblks; 993 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 994 head = sec / type->sectrac; 995 sec -= head * type->sectrac; 996 #ifdef DIAGNOSTIC 997 {daddr_t block; 998 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; 999 if (block != fd->sc_blkno) { 1000 printf("fdcintr: block %" PRId64 1001 " != blkno %" PRId64 "\n", 1002 block, fd->sc_blkno); 1003 #ifdef DDB 1004 Debugger(); 1005 #endif 1006 }} 1007 #endif 1008 read = bp->b_flags & B_READ; 1009 if (read) { 1010 fdc->sc_fh.fh_func = floppy_read_fiq; 1011 fdc->sc_fh.fh_size = floppy_read_fiq_end - 1012 floppy_read_fiq; 1013 } else { 1014 fdc->sc_fh.fh_func = floppy_write_fiq; 1015 fdc->sc_fh.fh_size = floppy_read_fiq_end - 1016 floppy_read_fiq; 1017 } 1018 fdc->sc_fh.fh_flags = 0; 1019 fdc->sc_fh.fh_regs = &fdc->sc_fr; 1020 fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2); 1021 fdc->sc_fr.fr_r10 = fd->sc_nbytes; 1022 fdc->sc_fr.fr_r11 = 1023 (u_int)((uintptr_t)bp->b_data + fd->sc_skip); 1024 fdc->sc_fr.fr_r12 = fdc->sc_drq; 1025 #ifdef FD_DEBUG 1026 printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n", 1027 fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11, 1028 fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip); 1029 #endif 1030 if (fiq_claim(&fdc->sc_fh) == -1) 1031 panic("%s: Cannot claim FIQ vector", 1032 device_xname(&fdc->sc_dev)); 1033 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01); 1034 bus_space_write_2(iot, ioh, fdctl, type->rate); 1035 #ifdef FD_DEBUG 1036 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", 1037 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, 1038 head, sec, nblks); 1039 #endif 1040 if (finfo) { 1041 /* formatting */ 1042 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) { 1043 fdc->sc_errors = 4; 1044 fdcretry(fdc); 1045 goto loop; 1046 } 1047 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1048 out_fdc(iot, ioh, finfo->fd_formb_secshift); 1049 out_fdc(iot, ioh, finfo->fd_formb_nsecs); 1050 out_fdc(iot, ioh, finfo->fd_formb_gaplen); 1051 out_fdc(iot, ioh, finfo->fd_formb_fillbyte); 1052 } else { 1053 if (read) 1054 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1055 else 1056 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1057 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1058 out_fdc(iot, ioh, fd->sc_cylin); /* track */ 1059 out_fdc(iot, ioh, head); 1060 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1061 out_fdc(iot, ioh, type->secsize);/* sector size */ 1062 out_fdc(iot, ioh, type->sectrac);/* sectors/track */ 1063 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1064 out_fdc(iot, ioh, type->datalen);/* data length */ 1065 } 1066 fdc->sc_state = IOCOMPLETE; 1067 1068 disk_busy(&fd->sc_dk); 1069 1070 /* allow 2 seconds for operation */ 1071 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1072 return 1; /* will return later */ 1073 1074 case SEEKWAIT: 1075 callout_stop(&fdc->sc_timo_ch); 1076 fdc->sc_state = SEEKCOMPLETE; 1077 /* allow 1/50 second for heads to settle */ 1078 #if 0 1079 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1080 #endif 1081 return 1; 1082 1083 case SEEKCOMPLETE: 1084 /* no data on seek */ 1085 disk_unbusy(&fd->sc_dk, 0, 0); 1086 1087 /* Make sure seek really happened. */ 1088 out_fdc(iot, ioh, NE7CMD_SENSEI); 1089 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1090 cyl != bp->b_cylinder * fd->sc_type->step) { 1091 #ifdef FD_DEBUG 1092 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1093 #endif 1094 fdcretry(fdc); 1095 goto loop; 1096 } 1097 fd->sc_cylin = bp->b_cylinder; 1098 goto doio; 1099 1100 case IOTIMEDOUT: 1101 fiq_release(&fdc->sc_fh); 1102 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1103 case SEEKTIMEDOUT: 1104 case RECALTIMEDOUT: 1105 case RESETTIMEDOUT: 1106 fdcretry(fdc); 1107 goto loop; 1108 1109 case IOCOMPLETE: /* IO DONE, post-analyze */ 1110 callout_stop(&fdc->sc_timo_ch); 1111 1112 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1113 (bp->b_flags & B_READ)); 1114 1115 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { 1116 fiq_release(&fdc->sc_fh); 1117 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1118 #ifdef FD_DEBUG 1119 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1120 "read failed" : "write failed"); 1121 printf("blkno %d nblks %d\n", 1122 fd->sc_blkno, fd->sc_nblks); 1123 #endif 1124 fdcretry(fdc); 1125 goto loop; 1126 } 1127 fiq_release(&fdc->sc_fh); 1128 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1129 if (fdc->sc_errors) { 1130 #if 0 1131 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 1132 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1133 printf("\n"); 1134 #endif 1135 fdc->sc_errors = 0; 1136 } 1137 fd->sc_blkno += fd->sc_nblks; 1138 fd->sc_skip += fd->sc_nbytes; 1139 fd->sc_bcount -= fd->sc_nbytes; 1140 if (!finfo && fd->sc_bcount > 0) { 1141 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1142 goto doseek; 1143 } 1144 fdfinish(fd, bp); 1145 goto loop; 1146 1147 case DORESET: 1148 /* try a reset, keep motor on */ 1149 fd_set_motor(fdc, 1); 1150 delay(100); 1151 fd_set_motor(fdc, 0); 1152 fdc->sc_state = RESETCOMPLETE; 1153 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1154 return 1; /* will return later */ 1155 1156 case RESETCOMPLETE: 1157 callout_stop(&fdc->sc_timo_ch); 1158 /* clear the controller output buffer */ 1159 for (i = 0; i < 4; i++) { 1160 out_fdc(iot, ioh, NE7CMD_SENSEI); 1161 (void) fdcresult(fdc); 1162 } 1163 1164 /* fall through */ 1165 case DORECAL: 1166 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 1167 out_fdc(iot, ioh, fd->sc_drive); 1168 fdc->sc_state = RECALWAIT; 1169 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1170 return 1; /* will return later */ 1171 1172 case RECALWAIT: 1173 callout_stop(&fdc->sc_timo_ch); 1174 fdc->sc_state = RECALCOMPLETE; 1175 /* allow 1/30 second for heads to settle */ 1176 #if 0 1177 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1178 #endif 1179 return 1; /* will return later */ 1180 1181 case RECALCOMPLETE: 1182 out_fdc(iot, ioh, NE7CMD_SENSEI); 1183 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1184 #ifdef FD_DEBUG 1185 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1186 #endif 1187 fdcretry(fdc); 1188 goto loop; 1189 } 1190 fd->sc_cylin = 0; 1191 goto doseek; 1192 1193 case MOTORWAIT: 1194 if (fd->sc_flags & FD_MOTOR_WAIT) 1195 return 1; /* time's not up yet */ 1196 goto doseek; 1197 1198 default: 1199 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1200 return 1; 1201 } 1202 #ifdef DIAGNOSTIC 1203 panic("fdcintr: impossible"); 1204 #endif 1205 #undef st0 1206 #undef cyl 1207 } 1208 1209 void 1210 fdcretry(struct fdc_softc *fdc) 1211 { 1212 struct fd_softc *fd; 1213 struct buf *bp; 1214 1215 fd = fdc->sc_drives.tqh_first; 1216 bp = bufq_peek(fd->sc_q); 1217 1218 if (fd->sc_opts & FDOPT_NORETRY) 1219 goto fail; 1220 switch (fdc->sc_errors) { 1221 case 0: 1222 /* try again */ 1223 fdc->sc_state = DOSEEK; 1224 break; 1225 1226 case 1: case 2: case 3: 1227 /* didn't work; try recalibrating */ 1228 fdc->sc_state = DORECAL; 1229 break; 1230 1231 case 4: 1232 /* still no go; reset the bastard */ 1233 fdc->sc_state = DORESET; 1234 break; 1235 1236 default: 1237 fail: 1238 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1239 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1240 fd->sc_skip / FDC_BSIZE, 1241 (struct disklabel *)NULL); 1242 fdcpstatus(7, fdc); 1243 } 1244 1245 bp->b_error = EIO; 1246 fdfinish(fd, bp); 1247 } 1248 fdc->sc_errors++; 1249 } 1250 1251 int 1252 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1253 { 1254 struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); 1255 struct fdformat_parms *form_parms; 1256 struct fdformat_cmd *form_cmd; 1257 struct ne7_fd_formb *fd_formb; 1258 struct disklabel buffer; 1259 int error; 1260 unsigned int scratch; 1261 int il[FD_MAX_NSEC + 1]; 1262 register int i, j; 1263 1264 switch (cmd) { 1265 case DIOCGDINFO: 1266 memset(&buffer, 0, sizeof(buffer)); 1267 1268 buffer.d_secpercyl = fd->sc_type->seccyl; 1269 buffer.d_type = DTYPE_FLOPPY; 1270 buffer.d_secsize = FDC_BSIZE; 1271 1272 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1273 return EINVAL; 1274 1275 *(struct disklabel *)addr = buffer; 1276 return 0; 1277 1278 case DIOCWLABEL: 1279 if ((flag & FWRITE) == 0) 1280 return EBADF; 1281 /* XXX do something */ 1282 return 0; 1283 1284 case DIOCWDINFO: 1285 if ((flag & FWRITE) == 0) 1286 return EBADF; 1287 1288 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL); 1289 if (error) 1290 return error; 1291 1292 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1293 return error; 1294 1295 case FDIOCGETFORMAT: 1296 form_parms = (struct fdformat_parms *)addr; 1297 form_parms->fdformat_version = FDFORMAT_VERSION; 1298 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1299 form_parms->ncyl = fd->sc_type->cyls; 1300 form_parms->nspt = fd->sc_type->sectrac; 1301 form_parms->ntrk = fd->sc_type->heads; 1302 form_parms->stepspercyl = fd->sc_type->step; 1303 form_parms->gaplen = fd->sc_type->gap2; 1304 form_parms->fillbyte = fd->sc_type->fillbyte; 1305 form_parms->interleave = fd->sc_type->interleave; 1306 switch (fd->sc_type->rate) { 1307 case FDC_500KBPS: 1308 form_parms->xfer_rate = 500 * 1024; 1309 break; 1310 case FDC_300KBPS: 1311 form_parms->xfer_rate = 300 * 1024; 1312 break; 1313 case FDC_250KBPS: 1314 form_parms->xfer_rate = 250 * 1024; 1315 break; 1316 default: 1317 return EINVAL; 1318 } 1319 return 0; 1320 1321 case FDIOCSETFORMAT: 1322 if((flag & FWRITE) == 0) 1323 return EBADF; /* must be opened for writing */ 1324 form_parms = (struct fdformat_parms *)addr; 1325 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1326 return EINVAL; /* wrong version of formatting prog */ 1327 1328 scratch = form_parms->nbps >> 7; 1329 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1330 scratch & ~(1 << (ffs(scratch)-1))) 1331 /* not a power-of-two multiple of 128 */ 1332 return EINVAL; 1333 1334 switch (form_parms->xfer_rate) { 1335 case 500 * 1024: 1336 fd->sc_type->rate = FDC_500KBPS; 1337 break; 1338 case 300 * 1024: 1339 fd->sc_type->rate = FDC_300KBPS; 1340 break; 1341 case 250 * 1024: 1342 fd->sc_type->rate = FDC_250KBPS; 1343 break; 1344 default: 1345 return EINVAL; 1346 } 1347 1348 if (form_parms->nspt > FD_MAX_NSEC || 1349 form_parms->fillbyte > 0xff || 1350 form_parms->interleave > 0xff) 1351 return EINVAL; 1352 fd->sc_type->sectrac = form_parms->nspt; 1353 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1354 return EINVAL; 1355 fd->sc_type->heads = form_parms->ntrk; 1356 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1357 fd->sc_type->secsize = ffs(scratch)-1; 1358 fd->sc_type->gap2 = form_parms->gaplen; 1359 fd->sc_type->cyls = form_parms->ncyl; 1360 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1361 form_parms->nbps / DEV_BSIZE; 1362 fd->sc_type->step = form_parms->stepspercyl; 1363 fd->sc_type->fillbyte = form_parms->fillbyte; 1364 fd->sc_type->interleave = form_parms->interleave; 1365 return 0; 1366 1367 case FDIOCFORMAT_TRACK: 1368 if((flag & FWRITE) == 0) 1369 return EBADF; /* must be opened for writing */ 1370 form_cmd = (struct fdformat_cmd *)addr; 1371 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1372 return EINVAL; /* wrong version of formatting prog */ 1373 1374 if (form_cmd->head >= fd->sc_type->heads || 1375 form_cmd->cylinder >= fd->sc_type->cyls) { 1376 return EINVAL; 1377 } 1378 1379 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1380 M_TEMP, M_NOWAIT); 1381 if(fd_formb == 0) 1382 return ENOMEM; 1383 1384 1385 fd_formb->head = form_cmd->head; 1386 fd_formb->cyl = form_cmd->cylinder; 1387 fd_formb->transfer_rate = fd->sc_type->rate; 1388 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1389 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1390 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1391 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1392 1393 memset(il, 0, sizeof il); 1394 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1395 while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1396 j++; 1397 il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1398 j += fd->sc_type->interleave; 1399 } 1400 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1401 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1402 fd_formb->fd_formb_headno(i) = form_cmd->head; 1403 fd_formb->fd_formb_secno(i) = il[i+1]; 1404 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1405 } 1406 1407 error = fdformat(dev, fd_formb, l); 1408 free(fd_formb, M_TEMP); 1409 return error; 1410 1411 case FDIOCGETOPTS: /* get drive options */ 1412 *(int *)addr = fd->sc_opts; 1413 return 0; 1414 1415 case FDIOCSETOPTS: /* set drive options */ 1416 fd->sc_opts = *(int *)addr; 1417 return 0; 1418 1419 default: 1420 return ENOTTY; 1421 } 1422 1423 #ifdef DIAGNOSTIC 1424 panic("fdioctl: impossible"); 1425 #endif 1426 } 1427 1428 int 1429 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l) 1430 { 1431 int rv = 0; 1432 struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev)); 1433 struct fd_type *type = fd->sc_type; 1434 struct buf *bp; 1435 1436 /* set up a buffer header for fdstrategy() */ 1437 bp = getiobuf(NULL, false); 1438 if(bp == 0) 1439 return ENOBUFS; 1440 bp->b_flags = B_PHYS | B_FORMAT; 1441 bp->b_cflags |= BC_BUSY; 1442 bp->b_proc = l->l_proc; 1443 bp->b_dev = dev; 1444 1445 /* 1446 * calculate a fake blkno, so fdstrategy() would initiate a 1447 * seek to the requested cylinder 1448 */ 1449 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1450 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1451 1452 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1453 bp->b_data = (void *)finfo; 1454 1455 #ifdef DEBUG 1456 printf("fdformat: blkno %llx count %x\n", 1457 (unsigned long long)bp->b_blkno, bp->b_bcount); 1458 #endif 1459 1460 /* now do the format */ 1461 fdstrategy(bp); 1462 1463 /* ...and wait for it to complete */ 1464 /* XXX very dodgy */ 1465 mutex_enter(bp->b_objlock); 1466 while (!(bp->b_oflags & BO_DONE)) { 1467 rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz); 1468 if (rv == EWOULDBLOCK) 1469 break; 1470 } 1471 mutex_exit(bp->b_objlock); 1472 1473 if (rv == EWOULDBLOCK) { 1474 /* timed out */ 1475 rv = EIO; 1476 biodone(bp); 1477 } else if (bp->b_error != 0) 1478 rv = bp->b_error; 1479 putiobuf(bp); 1480 return rv; 1481 } 1482 1483 #include <dev/md.h> 1484 1485 int load_memory_disc_from_floppy(struct md_conf *md, dev_t dev); 1486 1487 int 1488 load_memory_disc_from_floppy(struct md_conf *md, dev_t dev) 1489 { 1490 struct buf *bp; 1491 int loop; 1492 int s; 1493 int type; 1494 int floppysize; 1495 1496 if (bdevsw_lookup(dev) != &fd_bdevsw) 1497 return(EINVAL); 1498 1499 if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0) 1500 return(EBUSY); 1501 1502 type = FDTYPE(dev) - 1; 1503 if (type < 0) type = 0; 1504 floppysize = fd_types[type].size << (fd_types[type].secsize + 7); 1505 1506 if (md->md_size < floppysize) { 1507 printf("Memory disc is not big enough for floppy image\n"); 1508 return(EINVAL); 1509 } 1510 1511 /* We have the memory disk ! */ 1512 1513 printf("Loading memory disc : %4dK ", 0); 1514 1515 /* obtain a buffer */ 1516 1517 bp = geteblk(fd_types[type].sectrac * DEV_BSIZE); 1518 1519 /* request no partition relocation by driver on I/O operations */ 1520 1521 bp->b_dev = dev; 1522 1523 s = splbio(); 1524 1525 if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) { 1526 brelse(bp, 0); 1527 printf("Cannot open floppy device\n"); 1528 return(EINVAL); 1529 } 1530 1531 for (loop = 0; 1532 loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac); 1533 ++loop) { 1534 printf("\x08\x08\x08\x08\x08\x08%4dK ", 1535 loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1536 bp->b_blkno = loop * fd_types[type].sectrac; 1537 bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE; 1538 bp->b_flags |= B_READ; 1539 bp->b_error = 0; 1540 bp->b_resid = 0; 1541 fdstrategy(bp); 1542 1543 if (biowait(bp)) 1544 panic("Cannot load floppy image"); 1545 1546 memcpy((char *)md->md_addr + loop * fd_types[type].sectrac 1547 * DEV_BSIZE, (void *)bp->b_data, 1548 fd_types[type].sectrac * DEV_BSIZE); 1549 } 1550 printf("\x08\x08\x08\x08\x08\x08%4dK done\n", 1551 loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1552 1553 fdclose(bp->b_dev, 0, 0, curlwp); 1554 1555 brelse(bp, 0); 1556 1557 splx(s); 1558 return(0); 1559 } 1560