1 /* $NetBSD: iwm_fd.c,v 1.19 2002/11/01 11:31:53 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1997, 1998 Hauke Fath. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * iwm_fd.c -- Sony (floppy disk) driver for m68k Macintoshes 31 * 32 * The present implementation supports the GCR format (800K) on 33 * non-{DMA,IOP} machines. 34 */ 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/callout.h> 38 #include <sys/kernel.h> 39 #include <sys/file.h> 40 #include <sys/ioctl.h> 41 #include <sys/malloc.h> 42 #include <sys/device.h> 43 #include <sys/event.h> 44 45 #define FSTYPENAMES 46 #define DKTYPENAMES 47 #include <sys/disklabel.h> 48 49 #include <sys/disk.h> 50 #include <sys/dkbad.h> 51 #include <sys/buf.h> 52 #include <sys/uio.h> 53 #include <sys/stat.h> 54 #include <sys/syslog.h> 55 #include <sys/conf.h> 56 57 #include <machine/autoconf.h> 58 #include <machine/cpu.h> 59 60 #include <mac68k/obio/iwmreg.h> 61 #include <mac68k/obio/iwm_fdvar.h> 62 63 /** 64 ** Private functions 65 **/ 66 static int map_iwm_base __P((vm_offset_t base)); 67 68 /* Autoconfig */ 69 int iwm_match __P((struct device *, struct cfdata *, void *)); 70 void iwm_attach __P((struct device *, struct device *, void *)); 71 int iwm_print __P((void *, const char *)); 72 int fd_match __P((struct device *, struct cfdata *, void *)); 73 void fd_attach __P((struct device *, struct device *, void *)); 74 int fd_print __P((void *, const char *)); 75 76 /* Disklabel stuff */ 77 static void fdGetDiskLabel __P((fd_softc_t *fd, dev_t dev)); 78 static void fdPrintDiskLabel __P((struct disklabel *lp)); 79 80 static fdInfo_t *getFDType __P((short unit)); 81 static fdInfo_t *fdDeviceToType __P((fd_softc_t *fd, dev_t dev)); 82 83 static void fdstart __P((fd_softc_t *fd)); 84 static void remap_geometry __P((daddr_t block, int heads, diskPosition_t *loc)); 85 static void motor_off __P((void *param)); 86 static int seek __P((fd_softc_t *fd, int style)); 87 static int checkTrack __P((diskPosition_t *loc, int debugFlag)); 88 static int initCylinderCache __P((fd_softc_t *fd)); 89 static void invalidateCylinderCache __P((fd_softc_t *fd)); 90 91 #ifdef _LKM 92 static int probe_fd __P((void)); 93 int fd_mod_init __P((void)); 94 void fd_mod_free __P((void)); 95 #endif 96 97 static int fdstart_Init __P((fd_softc_t *fd)); 98 static int fdstart_Seek __P((fd_softc_t *fd)); 99 static int fdstart_Read __P((fd_softc_t *fd)); 100 static int fdstart_Write __P((fd_softc_t *fd)); 101 static int fdstart_Flush __P((fd_softc_t *fd)); 102 static int fdstart_IOFinish __P((fd_softc_t *fd)); 103 static int fdstart_IOErr __P((fd_softc_t *fd)); 104 static int fdstart_Fault __P((fd_softc_t *fd)); 105 static int fdstart_Exit __P((fd_softc_t *fd)); 106 107 108 /** 109 ** Driver debugging 110 **/ 111 112 #ifdef DEBUG 113 #define IWM_DEBUG 114 #endif 115 116 117 static void hexDump __P((u_char *buf, int len)); 118 119 /* 120 * Stuff taken from Egan/Teixeira ch 8: 'if(TRACE_FOO)' debug output 121 * statements don't break indentation, and when DEBUG is not defined, 122 * the compiler code optimizer drops them as dead code. 123 */ 124 #ifdef IWM_DEBUG 125 #define M_TRACE_CONFIG 0x0001 126 #define M_TRACE_OPEN 0x0002 127 #define M_TRACE_CLOSE 0x0004 128 #define M_TRACE_READ 0x0008 129 #define M_TRACE_WRITE 0x0010 130 #define M_TRACE_STRAT (M_TRACE_READ | M_TRACE_WRITE) 131 #define M_TRACE_IOCTL 0x0020 132 #define M_TRACE_STEP 0x0040 133 #define M_TRACE_ALL 0xFFFF 134 135 #define TRACE_CONFIG (iwmDebugging & M_TRACE_CONFIG) 136 #define TRACE_OPEN (iwmDebugging & M_TRACE_OPEN) 137 #define TRACE_CLOSE (iwmDebugging & M_TRACE_CLOSE) 138 #define TRACE_READ (iwmDebugging & M_TRACE_READ) 139 #define TRACE_WRITE (iwmDebugging & M_TRACE_WRITE) 140 #define TRACE_STRAT (iwmDebugging & M_TRACE_STRAT) 141 #define TRACE_IOCTL (iwmDebugging & M_TRACE_IOCTL) 142 #define TRACE_STEP (iwmDebugging & M_TRACE_STEP) 143 #define TRACE_ALL (iwmDebugging & M_TRACE_ALL) 144 145 /* -1 = all active */ 146 int iwmDebugging = 0 /* | M_TRACE_OPEN | M_TRACE_STRAT | M_TRACE_IOCTL */ ; 147 148 #else 149 #define TRACE_CONFIG 0 150 #define TRACE_OPEN 0 151 #define TRACE_CLOSE 0 152 #define TRACE_READ 0 153 #define TRACE_WRITE 0 154 #define TRACE_STRAT 0 155 #define TRACE_IOCTL 0 156 #define TRACE_STEP 0 157 #define TRACE_ALL 0 158 #endif 159 160 #define DISABLED 0 161 162 163 164 /** 165 ** Module-global Variables 166 **/ 167 168 /* The IWM base address */ 169 u_long IWMBase; 170 171 /* 172 * Table of supported disk types. 173 * The table order seems to be pretty standardized across NetBSD ports, but 174 * then, they are all MFM... So we roll our own for now. 175 */ 176 static fdInfo_t fdTypes[] = { 177 {1, 80, 512, 10, 10, 800, 12, 2, IWM_GCR, "400K Sony"}, 178 {2, 80, 512, 10, 20, 1600, 12, 2, IWM_GCR, "800K Sony"} 179 }; 180 181 /* Table of GCR disk zones for one side (see IM II-211, The Disk Driver) */ 182 static diskZone_t diskZones[] = { 183 {16, 12, 0, 191}, 184 {16, 11, 192, 367}, 185 {16, 10, 368, 527}, 186 {16, 9, 528, 671}, 187 {16, 8, 672, 799} 188 }; 189 190 /* Drive format codes/indexes */ 191 enum { 192 IWM_400K_GCR = 0, 193 IWM_800K_GCR = 1, 194 IWM_720K_MFM = 2, 195 IWM_1440K_MFM = 3 196 }; 197 198 199 /** 200 ** Autoconfiguration code 201 **/ 202 203 /* 204 * Autoconfig data structures 205 * 206 * These data structures (see <sys/device.h>) are referenced in 207 * compile/$KERNEL/ioconf.c, which is generated by config(8). 208 * Their names are formed like {device}_{ca,cd}. 209 * 210 * {device}_ca 211 * is used for dynamically allocating driver data, probing and 212 * attaching a device; 213 * 214 * {device}_cd 215 * references all found devices of a type. 216 */ 217 #ifndef _LKM 218 219 extern struct cfdriver iwm_cd; 220 extern struct cfdriver fd_cd; 221 222 #endif /* defined _LKM */ 223 224 /* IWM floppy disk controller */ 225 CFATTACH_DECL(iwm, sizeof(iwm_softc_t), 226 iwm_match, iwm_attach, NULL, NULL); 227 228 /* Attached floppy disk drives */ 229 CFATTACH_DECL(fd, sizeof(fd_softc_t), 230 fd_match, fd_attach, NULL, NULL); 231 232 dev_type_open(fdopen); 233 dev_type_close(fdclose); 234 dev_type_read(fdread); 235 dev_type_write(fdwrite); 236 dev_type_ioctl(fdioctl); 237 dev_type_strategy(fdstrategy); 238 239 const struct bdevsw fd_bdevsw = { 240 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 241 }; 242 243 const struct cdevsw fd_cdevsw = { 244 fdopen, fdclose, fdread, fdwrite, fdioctl, 245 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 246 }; 247 248 /* disk(9) framework device switch */ 249 struct dkdriver fd_dkDriver = { 250 fdstrategy 251 }; 252 253 /*** Configure the IWM controller ***/ 254 255 /* 256 * iwm_match 257 * 258 * Is the IWM chip present? Here, *auxp is a ptr to struct confargs 259 * (see <mac68k/mac68k/autoconf.h>), which does not hold any information 260 * to match against. After all, that's what the obio concept is 261 * about: Onboard components that are present depending (only) 262 * on machine type. 263 */ 264 int 265 iwm_match(parent, match, auxp) 266 struct device *parent; 267 struct cfdata *match; 268 void *auxp; 269 { 270 int matched; 271 #ifdef _LKM 272 int iwmErr; 273 #endif 274 extern u_long IOBase; /* from mac68k/machdep.c */ 275 extern u_long IWMBase; 276 277 if (0 == map_iwm_base(IOBase)) { 278 /* 279 * Unknown machine HW: 280 * The SWIM II/III chips that are present in post-Q700 281 * '040 Macs have dropped the IWM register structure. 282 * We know next to nothing about the SWIM. 283 */ 284 matched = 0; 285 if (TRACE_CONFIG) 286 printf("IWM or SWIM not found: Unknown location (SWIM II?).\n"); 287 } else { 288 matched = 1; 289 if (TRACE_CONFIG) { 290 printf("iwm: IWMBase mapped to 0x%lx in VM.\n", 291 IWMBase); 292 } 293 #ifdef _LKM 294 iwmErr = iwmInit(); 295 if (TRACE_CONFIG) 296 printf("initIWM() says %d.\n", iwmErr); 297 matched = (iwmErr == 0) ? 1 : 0; 298 #endif 299 } 300 return matched; 301 } 302 303 304 /* 305 * iwm_attach 306 * 307 * The IWM is present, initialize it. Then look up the connected drives 308 * and attach them. 309 */ 310 void 311 iwm_attach(parent, self, auxp) 312 struct device *parent; 313 struct device *self; 314 void *auxp; 315 { 316 int iwmErr; 317 iwm_softc_t *iwm; 318 iwmAttachArgs_t ia; 319 320 printf(": Apple GCR floppy disk controller\n"); 321 iwm = (iwm_softc_t *)self; 322 323 iwmErr = iwmInit(); 324 if (TRACE_CONFIG) 325 printf("initIWM() says %d.\n", iwmErr); 326 327 if (0 == iwmErr) { 328 /* Set up the IWM softc */ 329 iwm->maxRetries = 10; 330 331 /* Look for attached drives */ 332 for (ia.unit = 0; ia.unit < IWM_MAX_DRIVE; ia.unit++) { 333 iwm->fd[ia.unit] = NULL; 334 ia.driveType = getFDType(ia.unit); 335 if (NULL != ia.driveType) 336 config_found_sm(self, (void *)&ia, 337 fd_print, NULL); 338 } 339 if (TRACE_CONFIG) 340 printf("iwm: Initialization completed.\n"); 341 } else { 342 printf("iwm: Chip revision not supported (%d)\n", iwmErr); 343 } 344 } 345 346 347 /* 348 * iwm_print -- print device configuration. 349 * 350 * If the device is not configured 'controller' it is NULL and 351 * we print a message in the *Attach routine; the return value 352 * of *Print() is ignored. 353 */ 354 int 355 iwm_print(auxp, controller) 356 void *auxp; 357 const char *controller; 358 { 359 return UNCONF; 360 } 361 362 363 /* 364 * map_iwm_base 365 * 366 * Map physical IO address of IWM to VM address 367 */ 368 static int 369 map_iwm_base(base) 370 vm_offset_t base; 371 { 372 int known; 373 extern u_long IWMBase; 374 375 switch (current_mac_model->class) { 376 case MACH_CLASSQ: 377 case MACH_CLASSQ2: 378 case MACH_CLASSP580: 379 IWMBase = base + 0x1E000; 380 known = 1; 381 break; 382 case MACH_CLASSII: 383 case MACH_CLASSPB: 384 case MACH_CLASSDUO: 385 case MACH_CLASSIIci: 386 case MACH_CLASSIIsi: 387 case MACH_CLASSIIvx: 388 case MACH_CLASSLC: 389 IWMBase = base + 0x16000; 390 known = 1; 391 break; 392 case MACH_CLASSIIfx: 393 case MACH_CLASSAV: 394 default: 395 /* 396 * Neither IIfx/Q9[05]0 style IOP controllers nor 397 * Q[68]40AV DMA based controllers are supported. 398 */ 399 if (TRACE_CONFIG) 400 printf("Unknown floppy controller chip.\n"); 401 IWMBase = 0L; 402 known = 0; 403 break; 404 } 405 return known; 406 } 407 408 409 /*** Configure Sony disk drive(s) ***/ 410 411 /* 412 * fd_match 413 */ 414 int 415 fd_match(parent, match, auxp) 416 struct device *parent; 417 struct cfdata *match; 418 void *auxp; 419 { 420 int matched, cfUnit; 421 struct cfdata *cfp; 422 iwmAttachArgs_t *fdParams; 423 424 cfp = match; 425 fdParams = (iwmAttachArgs_t *)auxp; 426 cfUnit = cfp->cf_loc[0]; 427 matched = (cfUnit == fdParams->unit || cfUnit == -1) ? 1 : 0; 428 if (TRACE_CONFIG) { 429 printf("fdMatch() drive %d ? cfUnit = %d\n", 430 fdParams->unit, cfp->cf_loc[0]); 431 } 432 return matched; 433 } 434 435 436 /* 437 * fd_attach 438 * 439 * We have checked that the IWM is fine and the drive is present, 440 * so we can attach it. 441 */ 442 void 443 fd_attach(parent, self, auxp) 444 struct device *parent; 445 struct device *self; 446 void *auxp; 447 { 448 iwm_softc_t *iwm; 449 fd_softc_t *fd; 450 iwmAttachArgs_t *ia; 451 int driveInfo; 452 453 iwm = (iwm_softc_t *)parent; 454 fd = (fd_softc_t *)self; 455 ia = (iwmAttachArgs_t *)auxp; 456 457 driveInfo = iwmCheckDrive(ia->unit); 458 459 fd->currentType = ia->driveType; 460 fd->unit = ia->unit; 461 fd->defaultType = &fdTypes[IWM_800K_GCR]; 462 fd->stepDirection = 0; 463 464 iwm->fd[ia->unit] = fd; /* iwm has ptr to this drive */ 465 iwm->drives++; 466 467 bufq_alloc(&fd->bufQueue, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER); 468 callout_init(&fd->motor_ch); 469 470 printf(" drive %d: ", fd->unit); 471 472 if (IWM_NO_DISK & driveInfo) { 473 printf("(drive empty)\n"); 474 } else 475 if (!(IWM_DD_DISK & driveInfo)) { 476 printf("(HD disk -- not supported)\n"); 477 iwmDiskEject(fd->unit); /* XXX */ 478 } else { 479 printf("%s %d cyl, %d head(s)\n", 480 fd->currentType->description, 481 fd->currentType->tracks, 482 fd->currentType->heads); 483 } 484 if (TRACE_CONFIG) { 485 int reg, flags, spl; 486 487 /* List contents of drive status registers */ 488 spl = spl6(); 489 for (reg = 0; reg < 0x10; reg++) { 490 flags = iwmQueryDrvFlag(fd->unit, reg); 491 printf("iwm: Drive register 0x%x = 0x%x\n", reg, flags); 492 } 493 splx(spl); 494 } 495 fd->diskInfo.dk_name = fd->devInfo.dv_xname; 496 fd->diskInfo.dk_driver = &fd_dkDriver; 497 disk_attach(&fd->diskInfo); 498 } 499 500 501 /* 502 * fdPrint -- print device configuration. 503 * 504 * If the device is not configured 'controller' refers to a name string 505 * we print here. 506 * Else it is NULL and we print a message in the *Attach routine; the 507 * return value of *Print() is ignored. 508 */ 509 int 510 fd_print(auxp, controller) 511 void *auxp; 512 const char *controller; 513 { 514 iwmAttachArgs_t *ia; 515 516 ia = (iwmAttachArgs_t *)auxp; 517 if (NULL != controller) 518 printf("fd%d at %s", ia->unit, controller); 519 return UNCONF; 520 } 521 522 523 #ifdef _LKM 524 525 static iwm_softc_t *iwm; 526 527 /* 528 * fd_mod_init 529 * 530 * Any initializations necessary after loading the module happen here. 531 */ 532 int 533 fd_mod_init(void) 534 { 535 int err; 536 537 iwm = (iwm_softc_t *)malloc(sizeof(iwm_softc_t), M_DEVBUF, M_WAITOK); 538 539 err = (1 == iwm_match(NULL, NULL, NULL)) ? 0 : EIO; 540 if (!err) { 541 memset(iwm, 0, sizeof(iwm_softc_t)); 542 iwm->maxRetries = 10; 543 err = (0 == probe_fd()) ? 0 : EIO; 544 } 545 return err; 546 } 547 548 549 /* 550 * fd_mod_free 551 * 552 * Necessary clean-up before unloading the module. 553 */ 554 void 555 fd_mod_free(void) 556 { 557 int unit, spl; 558 559 spl = splbio(); 560 /* Release any allocated memory */ 561 for (unit = 0; unit < IWM_MAX_DRIVE; unit++) 562 if (iwm->fd[unit] != NULL) { 563 /* 564 * Let's hope there is only one task per drive, 565 * see callout(9). 566 */ 567 callout_stop(&iwm->fd[unit]->motor_ch); 568 disk_detach(&iwm->fd[unit]->diskInfo); 569 free(iwm->fd[unit], M_DEVBUF); 570 iwm->fd[unit] = NULL; 571 } 572 free(iwm, M_DEVBUF); 573 splx(spl); 574 } 575 576 577 /* 578 * probe_fd 579 * 580 * See if there are any drives out there and configure them. 581 * If we find a drive we allocate a softc structure for it and 582 * insert its address into the iwm_softc. 583 * 584 * XXX Merge the remainder of probeFD() with the autoconfig framework. 585 */ 586 static int 587 probe_fd(void) 588 { 589 fd_softc_t *fd; 590 iwmAttachArgs_t ia; 591 int err, unit; 592 593 err = 0; 594 for (ia.unit = 0; ia.unit < IWM_MAX_DRIVE; ia.unit++) { 595 ia.driveType = getFDType(ia.unit); 596 if (NULL == ia.driveType) { 597 iwm->fd[ia.unit] = NULL; 598 continue; 599 } 600 fd = (fd_softc_t *)malloc(sizeof(fd_softc_t), 601 M_DEVBUF, M_WAITOK); 602 if (fd == NULL) { 603 err = ENOMEM; 604 break; 605 } else { 606 memset(fd, 0, sizeof(fd_softc_t)); 607 608 /* This is usually set by the autoconfig framework */ 609 sprintf(fd->devInfo.dv_xname, "fd%d%c", ia.unit, 'a'); 610 fd_attach((struct device *)iwm, (struct device *)fd, 611 &ia); 612 } 613 } 614 if (err) { 615 /* Release any allocated memory */ 616 for (unit = 0; unit < IWM_MAX_DRIVE; unit++) 617 if (iwm->fd[unit] != NULL) { 618 free(iwm->fd[unit], M_DEVBUF); 619 iwm->fd[unit] = NULL; 620 } 621 } 622 return err; 623 } 624 625 #endif /* defined _LKM */ 626 627 628 /** 629 ** Implementation section of driver interface 630 ** 631 ** The prototypes for these functions are set up automagically 632 ** by macros in mac68k/conf.c. Their names are generated from {fd} 633 ** and {open,close,strategy,dump,size,read,write}. The driver entry 634 ** points are then plugged into bdevsw[] and cdevsw[]. 635 **/ 636 637 638 /* 639 * fdopen 640 * 641 * Open a floppy disk device. 642 */ 643 int 644 fdopen(dev, flags, devType, proc) 645 dev_t dev; 646 int flags; 647 int devType; 648 struct proc *proc; 649 { 650 fd_softc_t *fd; 651 fdInfo_t *info; 652 int partitionMask; 653 int fdType, fdUnit; 654 int ierr, err; 655 #ifndef _LKM 656 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 657 #endif 658 info = NULL; /* XXX shut up egcs */ 659 660 /* 661 * See <device.h> for struct cfdriver, <disklabel.h> for 662 * DISKUNIT() and <atari/atari/device.h> for getsoftc(). 663 */ 664 fdType = minor(dev) % MAXPARTITIONS; 665 fdUnit = minor(dev) / MAXPARTITIONS; 666 if (TRACE_OPEN) 667 printf("iwm: Open drive %d", fdUnit); 668 669 /* Check if device # is valid */ 670 err = (iwm->drives < fdUnit) ? ENXIO : 0; 671 if (!err) { 672 (void)iwmSelectDrive(fdUnit); 673 if (TRACE_OPEN) 674 printf(".\n Get softc"); 675 676 /* Get fd state */ 677 fd = iwm->fd[fdUnit]; 678 err = (NULL == fd) ? ENXIO : 0; 679 } 680 if (!err) { 681 if (fd->state & IWM_FD_IS_OPEN) { 682 /* 683 * Allow multiple open calls only if for identical 684 * floppy format. 685 */ 686 if (TRACE_OPEN) 687 printf(".\n Drive already opened!\n"); 688 err = (fd->partition == fdType) ? 0 : ENXIO; 689 } else { 690 if (TRACE_OPEN) 691 printf(".\n Get format info"); 692 693 /* Get format type */ 694 info = fdDeviceToType(fd, dev); 695 if (NULL == info) { 696 err = ENXIO; 697 if (TRACE_OPEN) 698 printf(".\n No such drive.\n"); 699 } 700 } 701 } 702 if (!err && !(fd->state & IWM_FD_IS_OPEN)) { 703 if (TRACE_OPEN) 704 printf(".\n Set diskInfo flags.\n"); 705 706 fd->writeLabel = 0; /* XXX currently unused */ 707 fd->partition = fdType; 708 fd->currentType = info; 709 fd->drvFlags = iwmCheckDrive(fd->unit); 710 711 if (fd->drvFlags & IWM_NO_DISK) { 712 err = EIO; 713 #ifdef DIAGNOSTIC 714 printf(" Drive %d is empty.\n", fd->unit); 715 #endif 716 } else { 717 if (!(fd->drvFlags & IWM_WRITEABLE) && (flags & FWRITE)) { 718 719 err = EPERM; 720 #ifdef DIAGNOSTIC 721 printf(" Disk is write protected.\n"); 722 #endif 723 } else { 724 if (!(fd->drvFlags & IWM_DD_DISK)) { 725 err = ENXIO; 726 #ifdef DIAGNOSTIC 727 printf(" HD format not supported.\n"); 728 #endif 729 (void)iwmDiskEject(fd->unit); 730 } else { 731 /* We're open now! */ 732 fd->state |= IWM_FD_IS_OPEN; 733 err = initCylinderCache(fd); 734 } 735 } 736 } 737 } 738 if (!err) { 739 /* 740 * Later, we might not want to recalibrate the drive when it 741 * is already open. For now, it doesn't hurt. 742 */ 743 if (TRACE_OPEN) 744 printf(" Seek track 00 says"); 745 746 memset(&fd->pos, 0, sizeof(diskPosition_t)); 747 ierr = seek(fd, IWM_SEEK_RECAL); 748 if (TRACE_OPEN) 749 printf(" %d.\n", ierr); 750 err = (0 == ierr) ? 0 : EIO; 751 } 752 if (!err) { 753 /* 754 * Update disklabel if we are not yet open. 755 * (We shouldn't be: We are synchronous.) 756 */ 757 if (fd->diskInfo.dk_openmask == 0) 758 fdGetDiskLabel(fd, dev); 759 760 partitionMask = (1 << fdType); 761 762 switch (devType) { 763 case S_IFCHR: 764 fd->diskInfo.dk_copenmask |= partitionMask; 765 break; 766 767 case S_IFBLK: 768 fd->diskInfo.dk_bopenmask |= partitionMask; 769 break; 770 } 771 fd->diskInfo.dk_openmask = 772 fd->diskInfo.dk_copenmask | fd->diskInfo.dk_bopenmask; 773 } 774 if (TRACE_OPEN) 775 printf("iwm: fdopen() says %d.\n", err); 776 return err; 777 } 778 779 780 /* 781 * fdclose 782 */ 783 int 784 fdclose(dev, flags, devType, proc) 785 dev_t dev; 786 int flags; 787 int devType; 788 struct proc *proc; 789 { 790 fd_softc_t *fd; 791 int partitionMask, fdUnit, fdType; 792 #ifndef _LKM 793 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 794 #endif 795 796 if (TRACE_CLOSE) 797 printf("iwm: Closing driver."); 798 fdUnit = minor(dev) / MAXPARTITIONS; 799 fdType = minor(dev) % MAXPARTITIONS; 800 fd = iwm->fd[fdUnit]; 801 /* release cylinder cache memory */ 802 if (fd->cbuf != NULL) 803 free(fd->cbuf, M_DEVBUF); 804 805 partitionMask = (1 << fdType); 806 807 /* Set state flag. */ 808 fd->state &= ~IWM_FD_IS_OPEN; 809 810 switch (devType) { 811 case S_IFCHR: 812 fd->diskInfo.dk_copenmask &= ~partitionMask; 813 break; 814 815 case S_IFBLK: 816 fd->diskInfo.dk_bopenmask &= ~partitionMask; 817 break; 818 } 819 fd->diskInfo.dk_openmask = 820 fd->diskInfo.dk_copenmask | fd->diskInfo.dk_bopenmask; 821 return 0; 822 } 823 824 825 /* 826 * fdioctl 827 * 828 * We deal with all the disk-specific ioctls in <sys/dkio.h> here even if 829 * we do not support them. 830 */ 831 int 832 fdioctl(dev, cmd, data, flags, proc) 833 dev_t dev; 834 u_long cmd; 835 caddr_t data; 836 int flags; 837 struct proc *proc; 838 { 839 int result, fdUnit, fdType; 840 fd_softc_t *fd; 841 #ifndef _LKM 842 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 843 #endif 844 845 if (TRACE_IOCTL) 846 printf("iwm: Execute ioctl... "); 847 848 /* Check if device # is valid and get its softc */ 849 fdUnit = minor(dev) / MAXPARTITIONS; 850 fdType = minor(dev) % MAXPARTITIONS; 851 if (fdUnit >= iwm->drives) { 852 if (TRACE_IOCTL) { 853 printf("iwm: Wanted device no (%d) is >= %d.\n", 854 fdUnit, iwm->drives); 855 } 856 return ENXIO; 857 } 858 fd = iwm->fd[fdUnit]; 859 result = 0; 860 861 switch (cmd) { 862 case DIOCGDINFO: 863 if (TRACE_IOCTL) 864 printf(" DIOCGDINFO: Get in-core disklabel.\n"); 865 *(struct disklabel *) data = *(fd->diskInfo.dk_label); 866 result = 0; 867 break; 868 869 case DIOCSDINFO: 870 if (TRACE_IOCTL) 871 printf(" DIOCSDINFO: Set in-core disklabel.\n"); 872 result = ((flags & FWRITE) == 0) ? EBADF : 0; 873 if (result == 0) 874 result = setdisklabel(fd->diskInfo.dk_label, 875 (struct disklabel *)data, 0, 876 fd->diskInfo.dk_cpulabel); 877 break; 878 879 case DIOCWDINFO: 880 if (TRACE_IOCTL) 881 printf(" DIOCWDINFO: Set in-core disklabel " 882 "& update disk.\n"); 883 result = ((flags & FWRITE) == 0) ? EBADF : 0; 884 885 if (result == 0) 886 result = setdisklabel(fd->diskInfo.dk_label, 887 (struct disklabel *)data, 0, 888 fd->diskInfo.dk_cpulabel); 889 if (result == 0) 890 result = writedisklabel(dev, fdstrategy, 891 fd->diskInfo.dk_label, 892 fd->diskInfo.dk_cpulabel); 893 break; 894 895 case DIOCGPART: 896 if (TRACE_IOCTL) 897 printf(" DIOCGPART: Get disklabel & partition table.\n"); 898 ((struct partinfo *)data)->disklab = fd->diskInfo.dk_label; 899 ((struct partinfo *)data)->part = 900 &fd->diskInfo.dk_label->d_partitions[fdType]; 901 result = 0; 902 break; 903 904 case DIOCRFORMAT: 905 case DIOCWFORMAT: 906 if (TRACE_IOCTL) 907 printf(" DIOC{R,W}FORMAT: No formatter support (yet?).\n"); 908 result = EINVAL; 909 break; 910 911 case DIOCSSTEP: 912 if (TRACE_IOCTL) 913 printf(" DIOCSSTEP: IWM does step handshake.\n"); 914 result = EINVAL; 915 break; 916 917 case DIOCSRETRIES: 918 if (TRACE_IOCTL) 919 printf(" DIOCSRETRIES: Set max. # of retries.\n"); 920 if (*(int *)data < 0) 921 result = EINVAL; 922 else { 923 iwm->maxRetries = *(int *)data; 924 result = 0; 925 } 926 break; 927 928 case DIOCWLABEL: 929 if (TRACE_IOCTL) 930 printf(" DIOCWLABEL: Set write access to disklabel.\n"); 931 result = ((flags & FWRITE) == 0) ? EBADF : 0; 932 933 if (result == 0) 934 fd->writeLabel = *(int *)data; 935 break; 936 937 case DIOCSBAD: 938 if (TRACE_IOCTL) 939 printf(" DIOCSBAD: No bad144-style handling.\n"); 940 result = EINVAL; 941 break; 942 943 case ODIOCEJECT: 944 case DIOCEJECT: 945 /* XXX Eject disk only when unlocked */ 946 if (TRACE_IOCTL) 947 printf(" DIOCEJECT: Eject disk from unit %d.\n", 948 fd->unit); 949 result = iwmDiskEject(fd->unit); 950 break; 951 952 case DIOCLOCK: 953 /* XXX Use lock to prevent ejectimg a mounted disk */ 954 if (TRACE_IOCTL) 955 printf(" DIOCLOCK: No need to (un)lock Sony drive.\n"); 956 result = 0; 957 break; 958 959 default: 960 if (TRACE_IOCTL) 961 printf(" Not a disk related ioctl!\n"); 962 result = ENOTTY; 963 break; 964 } 965 return result; 966 } 967 968 969 /* 970 * fdread 971 */ 972 int 973 fdread(dev, uio, flags) 974 dev_t dev; 975 struct uio *uio; 976 int flags; 977 { 978 return physio(fdstrategy, NULL, dev, B_READ, minphys, uio); 979 } 980 981 982 /* 983 * fdwrite 984 */ 985 int 986 fdwrite(dev, uio, flags) 987 dev_t dev; 988 struct uio *uio; 989 int flags; 990 { 991 return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio); 992 } 993 994 995 /* 996 * fdstrategy 997 * 998 * Entry point for read and write requests. The strategy routine usually 999 * queues io requests and kicks off the next transfer if the device is idle; 1000 * but we get no interrupts from the IWM and have to do synchronous 1001 * transfers - no queue. 1002 */ 1003 void 1004 fdstrategy(bp) 1005 struct buf *bp; 1006 { 1007 int fdUnit, err, done, spl; 1008 int sectSize, transferSize; 1009 diskPosition_t physDiskLoc; 1010 fd_softc_t *fd; 1011 #ifndef _LKM 1012 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 1013 #endif 1014 1015 err = 0; 1016 done = 0; 1017 1018 fdUnit = minor(bp->b_dev) / MAXPARTITIONS; 1019 if (TRACE_STRAT) { 1020 printf("iwm: fdstrategy()...\n"); 1021 printf(" struct buf is at %p\n", bp); 1022 printf(" Allocated buffer size (b_bufsize): 0x0%lx\n", 1023 bp->b_bufsize); 1024 printf(" Base address of buffer (b_data): %p\n", 1025 bp->b_data); 1026 printf(" Bytes to be transferred (b_bcount): 0x0%lx\n", 1027 bp->b_bcount); 1028 printf(" Remaining I/O (b_resid): 0x0%lx\n", 1029 bp->b_resid); 1030 } 1031 /* Check for valid fd unit, controller and io request */ 1032 1033 if (fdUnit >= iwm->drives) { 1034 if (TRACE_STRAT) 1035 printf(" No such unit (%d)\n", fdUnit); 1036 err = EINVAL; 1037 } 1038 if (!err) { 1039 fd = iwm->fd[fdUnit]; 1040 err = (NULL == fd) ? EINVAL : 0; 1041 } 1042 if (!err) { 1043 sectSize = fd->currentType->sectorSize; 1044 if (bp->b_blkno < 0 1045 || (bp->b_bcount % sectSize) != 0) { 1046 if (TRACE_STRAT) 1047 printf(" Illegal transfer size: " 1048 "block %d, %ld bytes\n", 1049 bp->b_blkno, bp->b_bcount); 1050 err = EINVAL; 1051 } 1052 } 1053 if (!err) { 1054 /* Null transfer: Return, nothing to do. */ 1055 if (0 == bp->b_bcount) { 1056 if (TRACE_STRAT) 1057 printf(" Zero transfer length.\n"); 1058 done = 1; 1059 } 1060 } 1061 if (!err && !done) { 1062 /* What to do if we touch the boundaries of the disk? */ 1063 transferSize = (bp->b_bcount + (sectSize - 1)) / sectSize; 1064 if (bp->b_blkno + transferSize > fd->currentType->secPerDisk) { 1065 if (TRACE_STRAT) { 1066 printf("iwm: Transfer beyond end of disk!\n" \ 1067 " (Starting block %d, # of blocks %d," \ 1068 " last disk block %d).\n", 1069 bp->b_blkno, transferSize, 1070 fd->currentType->secPerDisk); 1071 } 1072 /* Return EOF if we are exactly at the end of the 1073 * disk, EINVAL if we try to reach past the end; else 1074 * truncate the request. */ 1075 transferSize = fd->currentType->secPerDisk - 1076 bp->b_blkno; 1077 if (0 == transferSize) { 1078 bp->b_resid = bp->b_bcount; 1079 done = 1; 1080 } else 1081 if (0 > transferSize) 1082 err = EINVAL; 1083 else 1084 bp->b_bcount = transferSize << DEV_BSHIFT; 1085 } 1086 } 1087 if (!err && !done) { 1088 /* 1089 * Calculate cylinder # for disksort(). 1090 * 1091 * XXX Shouldn't we use the (fake) logical cyl no here? 1092 */ 1093 remap_geometry(bp->b_blkno, fd->currentType->heads, 1094 &physDiskLoc); 1095 bp->b_rawblkno = bp->b_blkno; 1096 bp->b_cylinder = physDiskLoc.track; 1097 1098 if (TRACE_STRAT) { 1099 printf(" This job starts at b_blkno %d; ", 1100 bp->b_blkno); 1101 printf("it gets sorted for cylinder # %ld.\n", 1102 bp->b_cylinder); 1103 } 1104 spl = splbio(); 1105 callout_stop(&fd->motor_ch); 1106 BUFQ_PUT(&fd->bufQueue, bp); 1107 if (fd->sc_active == 0) 1108 fdstart(fd); 1109 splx(spl); 1110 } 1111 /* Clean up, if necessary */ 1112 else { 1113 if (TRACE_STRAT) 1114 printf(" fdstrategy() finished early, err = %d.\n", 1115 err); 1116 if (err) { 1117 bp->b_error = err; 1118 bp->b_flags |= B_ERROR; 1119 } 1120 bp->b_resid = bp->b_bcount; 1121 biodone(bp); 1122 } 1123 /* Comment on results */ 1124 if (TRACE_STRAT) { 1125 printf("iwm: fdstrategy() done.\n"); 1126 printf(" We have b_resid = %ld bytes left, " \ 1127 "b_error is %d;\n", bp->b_resid, bp->b_error); 1128 printf(" b_flags are 0x0%lx.\n", bp->b_flags); 1129 } 1130 } 1131 1132 1133 1134 /* ======================================================================== */ 1135 1136 1137 /* 1138 * fdstart 1139 * 1140 * we are called from the strategy() routine to perform a data transfer. 1141 * 1142 * The disk(9) framework demands we run at splbio(); our caller 1143 * takes care of that. 1144 * 1145 * Wish we had pascalish local functions here... 1146 */ 1147 1148 /* fdstart FSM states */ 1149 enum { 1150 state_Init = 0, 1151 state_Seek, 1152 state_Read, 1153 state_Write, 1154 state_Flush, 1155 state_IOFinish, 1156 state_IOErr, 1157 state_Fault, 1158 state_Exit, 1159 state_Done 1160 }; 1161 1162 static void 1163 fdstart(fd) 1164 fd_softc_t *fd; 1165 { 1166 int st; 1167 1168 static char *stateDesc[] = { 1169 "Init", 1170 "Seek", 1171 "Read", 1172 "Write", 1173 "Flush", 1174 "IOFinish", 1175 "IOErr", 1176 "Fault", 1177 "Exit", 1178 "Done" 1179 }; 1180 int (*state[])(fd_softc_t *fd) = { 1181 fdstart_Init, 1182 fdstart_Seek, 1183 fdstart_Read, 1184 fdstart_Write, 1185 fdstart_Flush, 1186 fdstart_IOFinish, 1187 fdstart_IOErr, 1188 fdstart_Fault, 1189 fdstart_Exit 1190 }; 1191 1192 st = state_Init; 1193 do { 1194 if (TRACE_STRAT) 1195 printf(" fdstart state %d [%s] ", 1196 st, stateDesc[st]); 1197 1198 st = (*state[st])(fd); 1199 1200 if (TRACE_STRAT) 1201 printf(".\n"); 1202 } while (st != state_Done); 1203 } 1204 1205 1206 /* 1207 * fdstart_Init 1208 * 1209 * Set up things 1210 */ 1211 static int 1212 fdstart_Init(fd) 1213 fd_softc_t *fd; 1214 { 1215 struct buf *bp; 1216 1217 /* 1218 * Get the first entry from the queue. This is the buf we gave to 1219 * fdstrategy(); disksort() put it into our softc. 1220 */ 1221 bp = BUFQ_PEEK(&fd->bufQueue); 1222 if (NULL == bp) { 1223 if (TRACE_STRAT) 1224 printf("Queue empty: Nothing to do"); 1225 return state_Done; 1226 } 1227 fd->ioDirection = bp->b_flags & B_READ; 1228 1229 disk_busy(&fd->diskInfo); 1230 if (!(fd->state & IWM_FD_MOTOR_ON)) { 1231 iwmMotor(fd->unit, 1); 1232 fd->state |= IWM_FD_MOTOR_ON; 1233 } 1234 fd->current_buffer = bp->b_data; 1235 1236 /* XXX - assumes blocks of 512 bytes */ 1237 fd->startBlk = bp->b_blkno; 1238 1239 fd->iwmErr = 0; 1240 fd->ioRetries = 0; /* XXX */ 1241 fd->seekRetries = 0; 1242 fd->bytesDone = 0; 1243 fd->bytesLeft = bp->b_bcount; 1244 return state_Seek; 1245 } 1246 1247 1248 /* 1249 * fdstart_Seek 1250 */ 1251 static int 1252 fdstart_Seek(fd) 1253 fd_softc_t *fd; 1254 { 1255 int state; 1256 1257 /* Calculate the side/track/sector our block is at. */ 1258 if (TRACE_STRAT) 1259 printf(" Remap block %d ", fd->startBlk); 1260 remap_geometry(fd->startBlk, 1261 fd->currentType->heads, &fd->pos); 1262 if (TRACE_STRAT) 1263 printf("to c%d_h%d_s%d ", fd->pos.track, 1264 fd->pos.side, fd->pos.sector); 1265 1266 if (fd->cachedSide != fd->pos.side) { 1267 if (TRACE_STRAT) 1268 printf(" (invalidate cache) "); 1269 invalidateCylinderCache(fd); 1270 fd->cachedSide = fd->pos.side; 1271 } 1272 1273 /* 1274 * If necessary, seek to wanted track. Note that 1275 * seek() performs any necessary retries. 1276 */ 1277 if (fd->pos.track != fd->pos.oldTrack && 1278 0 != (fd->iwmErr = seek(fd, IWM_SEEK_VANILLA))) { 1279 state = state_Fault; 1280 } else { 1281 state = (fd->ioDirection == IWM_WRITE) 1282 ? state_Write : state_Read; 1283 } 1284 return state; 1285 } 1286 1287 1288 /* 1289 * fdstart_Read 1290 * 1291 * Transfer a sector from disk. Get it from the track cache, if available; 1292 * otherwise, while we are at it, store in the cache all the sectors we find 1293 * on the way. 1294 * 1295 * Track buffering reads: 1296 * o Look if the sector is already cached. 1297 * o Else, read sectors into track cache until we meet the header of 1298 * the sector we want. 1299 * o Read that sector directly to fs buffer and return. 1300 */ 1301 static int 1302 fdstart_Read(fd) 1303 fd_softc_t *fd; 1304 { 1305 int i; 1306 diskPosition_t *pos; 1307 sectorHdr_t *shdr; 1308 #ifndef _LKM 1309 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 1310 #endif 1311 1312 /* Initialize retry counters */ 1313 fd->seekRetries = 0; 1314 fd->sectRetries = 0; 1315 pos = &fd->pos; 1316 shdr = &fd->sHdr; 1317 1318 if (TRACE_STRAT) 1319 printf("<%s c%d_h%d_s%d> ", 1320 fd->ioDirection ? "Read" : "Write", 1321 pos->track, pos->side, pos->sector); 1322 1323 /* Sector already cached? */ 1324 i = pos->sector; 1325 if (fd->r_slots[i].valid) { 1326 if (TRACE_STRAT) 1327 printf("(cached)"); 1328 memcpy(fd->current_buffer, fd->r_slots[i].secbuf, 1329 fd->currentType->sectorSize); 1330 return state_IOFinish; 1331 } 1332 1333 /* Get sector from disk */ 1334 shdr->side = pos->side; 1335 shdr->sector = pos->sector; 1336 shdr->track = pos->track; 1337 1338 (void)iwmSelectSide(pos->side); 1339 fd->iwmErr = iwmReadSector(&fd->sHdr, fd->r_slots, 1340 fd->current_buffer); 1341 1342 /* Check possible error conditions */ 1343 if (TRACE_STRAT) 1344 printf("c%d_h%d_s%d_err(%d)_sr%d ", 1345 shdr->track, shdr->side >> 3, 1346 shdr->sector, fd->iwmErr, fd->sectRetries); 1347 1348 /* IWM IO error? */ 1349 if (fd->iwmErr != 0) 1350 return state_IOErr; 1351 1352 /* Bad seek? Retry */ 1353 if (shdr->track != pos->track) { 1354 if (TRACE_STRAT) { 1355 printf("Wanted track %d, got %d, %d seek retries.\n", 1356 pos->track, shdr->track, fd->seekRetries); 1357 } 1358 if (iwm->maxRetries > fd->seekRetries++) { 1359 fd->iwmErr = seek(fd, IWM_SEEK_RECAL); 1360 if (TRACE_STRAT) { 1361 printf("[%d]", fd->seekRetries); 1362 (void)checkTrack(&fd->pos, 1); 1363 } 1364 } else 1365 fd->iwmErr = seekErr; 1366 return (0 == fd->iwmErr) ? state_Read : state_Fault; 1367 } 1368 1369 /* Sector not found? */ 1370 if (shdr->sector != pos->sector) { 1371 if (TRACE_STRAT) 1372 printf("c%d_h%d_s%d sect not found, %d retries ", 1373 shdr->track, shdr->side >> 3, 1374 shdr->sector, fd->sectRetries); 1375 fd->iwmErr = noAdrMkErr; 1376 return state_Fault; 1377 } 1378 1379 /* Success */ 1380 return state_IOFinish; 1381 } 1382 1383 1384 /* 1385 * fdstart_Write 1386 * 1387 * Insert a sector into a write buffer slot and mark the slot dirty. 1388 */ 1389 static int 1390 fdstart_Write(fd) 1391 fd_softc_t *fd; 1392 { 1393 int i; 1394 1395 /* XXX let's see... */ 1396 fd->sHdr.side = fd->pos.side; 1397 fd->sHdr.sector = fd->pos.sector; 1398 fd->sHdr.track = fd->pos.track; 1399 1400 i = fd->pos.sector; 1401 fd->w_slots[i].secbuf = fd->current_buffer; 1402 fd->w_slots[i].valid = 1; /* "valid" is a dirty buffer here */ 1403 1404 if (TRACE_STRAT) 1405 printf("<%s c%d_h%d_s%d> (cached) ", 1406 fd->ioDirection ? "Read" : "Write", 1407 fd->pos.track, fd->pos.side, fd->pos.sector); 1408 return state_IOFinish; 1409 } 1410 1411 1412 1413 /* 1414 * fdstart_Flush 1415 * 1416 * Flush dirty buffers in the track cache to disk. 1417 */ 1418 static int 1419 fdstart_Flush(fd) 1420 fd_softc_t *fd; 1421 { 1422 int state; 1423 int i, dcnt; 1424 diskPosition_t *pos; 1425 sectorHdr_t *shdr; 1426 #ifndef _LKM 1427 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 1428 #endif 1429 dcnt = 0; 1430 pos = &fd->pos; 1431 shdr = &fd->sHdr; 1432 1433 if (TRACE_STRAT) { 1434 for (i=0; i < IWM_MAX_GCR_SECTORS; i++) 1435 if (fd->w_slots[i].valid) { 1436 printf("|%d", i); 1437 dcnt++; 1438 } 1439 printf("|\n"); 1440 1441 printf(" <%s c%d_h%d_#s%d>\n", 1442 fd->ioDirection ? "Read" : "Write", 1443 pos->track, pos->side, dcnt); 1444 } 1445 (void)iwmSelectSide(pos->side); 1446 fd->iwmErr = iwmWriteSector(&fd->sHdr, fd->w_slots); 1447 1448 switch (fd->iwmErr) { 1449 case noErr: /* Success */ 1450 #ifdef DIAGNOSTIC 1451 /* XXX Panic if buffer not clean? */ 1452 for (i=0; i<IWM_MAX_GCR_SECTORS; i++) 1453 if (0 != fd->w_slots[i].valid) 1454 printf("Oops! <c%d_h%d_s%d> not flushed.\n", 1455 fd->pos.track, fd->pos.side, 1456 fd->pos.sector); 1457 #endif 1458 if (TRACE_STRAT) 1459 printf("(Cache flushed, re-initialize) "); 1460 for (i=0; i < IWM_MAX_GCR_SECTORS; i++) { 1461 fd->w_slots[i].valid = 0; 1462 fd->w_slots[i].secbuf = NULL; 1463 } 1464 fd->seekRetries = 0; 1465 state = state_Exit; 1466 break; 1467 1468 case seekErr: /* Bad seek? Retry */ 1469 if (TRACE_STRAT) { 1470 printf("Wanted track %d, got %d, %d seek retries.\n", 1471 pos->track, shdr->track, fd->seekRetries); 1472 } 1473 if (iwm->maxRetries > fd->seekRetries++) { 1474 fd->iwmErr = seek(fd, IWM_SEEK_RECAL); 1475 if (TRACE_STRAT) { 1476 printf("[%d]", fd->seekRetries); 1477 } 1478 } 1479 state = (0 == fd->iwmErr) ? state_Exit : state_Fault; 1480 break; 1481 1482 default: /* General IWM IO error? */ 1483 state = state_IOErr; 1484 } 1485 return state; 1486 } 1487 1488 1489 /* 1490 * fdstart_IOFinish 1491 * 1492 * Prepare for next block, if any is available 1493 */ 1494 static int 1495 fdstart_IOFinish(fd) 1496 fd_softc_t *fd; 1497 { 1498 int state; 1499 1500 if (DISABLED && TRACE_STRAT) 1501 printf("%s c%d_h%d_s%d ok ", 1502 fd->ioDirection ? "Read" : "Write", 1503 fd->sHdr.track, fd->sHdr.side >> 3, fd->sHdr.sector); 1504 1505 fd->bytesDone += fd->currentType->sectorSize; 1506 fd->bytesLeft -= fd->currentType->sectorSize; 1507 fd->current_buffer += fd->currentType->sectorSize; 1508 /* 1509 * Instead of recalculating the chs mapping for 1510 * each and every sector, check for 1511 * 'current sector# <= max sector#' and recalculate 1512 * after overflow. 1513 */ 1514 fd->startBlk++; 1515 if (fd->bytesLeft > 0) { 1516 if (++fd->pos.sector < fd->pos.maxSect) { 1517 if (TRACE_STRAT) 1518 printf("continue"); 1519 state = (fd->ioDirection == IWM_WRITE) 1520 ? state_Write : state_Read; 1521 } 1522 else { 1523 /* 1524 * Invalidate read cache when changing track; 1525 * flush write cache to disk. 1526 */ 1527 if (fd->ioDirection == IWM_WRITE) { 1528 if (TRACE_STRAT) 1529 printf("flush "); 1530 state = (state_Exit == fdstart_Flush(fd)) 1531 ? state_Seek : state_IOErr; 1532 } 1533 else { 1534 if (TRACE_STRAT) 1535 printf("step "); 1536 invalidateCylinderCache(fd); 1537 state = state_Seek; 1538 } 1539 } 1540 } else { 1541 state = (fd->ioDirection == IWM_WRITE) 1542 ? state_Flush : state_Exit; 1543 } 1544 return state; 1545 } 1546 1547 1548 /* 1549 * fdstart_IOErr 1550 * 1551 * Bad IO, repeat 1552 */ 1553 static int 1554 fdstart_IOErr(fd) 1555 fd_softc_t *fd; 1556 { 1557 int state; 1558 #ifndef _LKM 1559 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 1560 #endif 1561 1562 #ifdef DIAGNOSTIC 1563 printf("iwm%sSector() err = %d, %d retries, on c%d_h%d_s%d.\n", 1564 fd->ioDirection ? "Read" : "Write", 1565 fd->iwmErr, fd->ioRetries, fd->pos.track, 1566 fd->pos.side, fd->pos.sector); 1567 #endif 1568 /* XXX Do statistics */ 1569 if (fd->ioRetries++ < iwm->maxRetries) 1570 state = (fd->ioDirection == IWM_WRITE) 1571 ? state_Flush : state_Read; 1572 else 1573 state = state_Fault; 1574 return state; 1575 } 1576 1577 1578 /* 1579 * fdstart_Fault 1580 * 1581 * A non-recoverable error 1582 */ 1583 static int 1584 fdstart_Fault(fd) 1585 fd_softc_t *fd; 1586 { 1587 #ifdef DIAGNOSTIC 1588 printf("Seek retries %d, IO retries %d, sect retries %d :\n" \ 1589 "\t\t only found c%d_h%d_s%d \n", 1590 fd->seekRetries, fd->ioRetries, fd->sectRetries, 1591 fd->sHdr.track, fd->sHdr.side >> 3, fd->sHdr.sector); 1592 printf("A non-recoverable error: %d ", fd->iwmErr); 1593 #else 1594 /* ARGSUSED */ 1595 #endif 1596 return state_Exit; 1597 } 1598 1599 1600 /* 1601 * fdstart_Exit 1602 * 1603 * We are done, for good or bad 1604 */ 1605 static int 1606 fdstart_Exit(fd) 1607 fd_softc_t *fd; 1608 { 1609 struct buf *bp; 1610 #ifdef DIAGNOSTIC 1611 int i; 1612 #endif 1613 1614 invalidateCylinderCache(fd); 1615 1616 #ifdef DIAGNOSTIC 1617 /* XXX Panic if buffer not clean? */ 1618 for (i=0; i<IWM_MAX_GCR_SECTORS; i++) 1619 if (0 != fd->w_slots[i].valid) 1620 printf("Oops! <c%d_h%d_s%d> not flushed.\n", 1621 fd->pos.track, fd->pos.side, fd->pos.sector); 1622 #endif 1623 1624 bp = BUFQ_GET(&fd->bufQueue); 1625 1626 bp->b_resid = fd->bytesLeft; 1627 bp->b_error = (0 == fd->iwmErr) ? 0 : EIO; 1628 if (fd->iwmErr) 1629 bp->b_flags |= B_ERROR; 1630 1631 if (TRACE_STRAT) { 1632 printf(" fdstart() finished job; fd->iwmErr = %d, b_error = %d", 1633 fd->iwmErr, bp->b_error); 1634 if (DISABLED) 1635 hexDump(bp->b_data, bp->b_bcount); 1636 } 1637 if (DISABLED && TRACE_STRAT) 1638 printf(" Next buf (bufQueue first) at %p\n", 1639 BUFQ_PEEK(&fd->bufQueue)); 1640 disk_unbusy(&fd->diskInfo, bp->b_bcount - bp->b_resid, 1641 (bp->b_flags & B_READ)); 1642 biodone(bp); 1643 /* 1644 * Stop motor after 10s 1645 * 1646 * XXX Unloading the module while the timeout is still 1647 * running WILL crash the machine. 1648 */ 1649 callout_reset(&fd->motor_ch, 10 * hz, motor_off, fd); 1650 1651 return state_Done; 1652 } 1653 1654 1655 /* 1656 * remap_geometry 1657 * 1658 * Remap the rigid UN*X view of a disk's cylinder/sector geometry 1659 * to our zone recorded real Sony drive by splitting the disk 1660 * into zones. 1661 * 1662 * Loop { 1663 * Look if logical block number is in current zone 1664 * NO: Add # of tracks for current zone to track counter 1665 * Process next zone 1666 * 1667 * YES: Subtract (number of first sector of current zone times heads) 1668 * from logical block number, then break up the difference 1669 * in tracks/side/sectors (spt is constant within a zone). 1670 * Done 1671 * } 1672 */ 1673 static void 1674 remap_geometry(block, heads, loc) 1675 daddr_t block; 1676 int heads; 1677 diskPosition_t *loc; 1678 { 1679 int zone, spt; 1680 extern diskZone_t diskZones[]; 1681 1682 spt = 0; /* XXX Shut up egcs warning */ 1683 loc->oldTrack = loc->track; 1684 loc->track = 0; 1685 1686 for (zone = 0; zone < IWM_GCR_DISK_ZONES; zone++) { 1687 if (block >= heads * (diskZones[zone].lastBlock + 1)) { 1688 /* Process full zones */ 1689 loc->track += diskZones[zone].tracks; 1690 } else { 1691 /* Process partial zone */ 1692 spt = diskZones[zone].sectPerTrack; 1693 block -= heads * diskZones[zone].firstBlock; 1694 loc->track += block / (spt * heads); 1695 loc->sector = (block % spt); 1696 loc->side = (block % (spt * heads)) / spt; 1697 break; 1698 } 1699 } 1700 loc->maxSect = spt; 1701 } 1702 1703 1704 /* 1705 * motor_off 1706 * 1707 * Callback for timeout() 1708 */ 1709 static void 1710 motor_off(param) 1711 void *param; 1712 { 1713 int spl; 1714 fd_softc_t *fd; 1715 1716 fd = (fd_softc_t *)param; 1717 if (TRACE_STRAT) 1718 printf("iwm: Switching motor OFF (timeout).\n"); 1719 spl = spl6(); 1720 (void)iwmMotor(fd->unit, 0); 1721 fd->state &= ~IWM_FD_MOTOR_ON; 1722 splx(spl); 1723 } 1724 1725 1726 /* 1727 * fdGetDiskLabel 1728 * 1729 * Set up disk label with parameters from current disk type. 1730 * Then call the generic disklabel read routine which tries to 1731 * read a label from disk and insert it. If it doesn't exist use 1732 * our defaults. 1733 */ 1734 static void 1735 fdGetDiskLabel(fd, dev) 1736 fd_softc_t *fd; 1737 dev_t dev; 1738 { 1739 char *msg; 1740 int fdType; 1741 struct disklabel *lp; 1742 struct cpu_disklabel *clp; 1743 1744 if (TRACE_IOCTL) 1745 printf("iwm: fdGetDiskLabel() for disk %d.\n", 1746 minor(dev) / MAXPARTITIONS); 1747 fdType = minor(dev) % MAXPARTITIONS; 1748 lp = fd->diskInfo.dk_label; 1749 clp = fd->diskInfo.dk_cpulabel; 1750 memset(lp, 0, sizeof(struct disklabel)); 1751 memset(clp, 0, sizeof(struct cpu_disklabel)); 1752 /* 1753 * How to describe a drive with a variable # of sectors per 1754 * track (8..12) and variable rpm (300..550)? Apple came up 1755 * with ZBR in 1983! Un*x drive management sucks. 1756 */ 1757 lp->d_type = DTYPE_FLOPPY; 1758 lp->d_rpm = 300; 1759 lp->d_secsize = fd->currentType->sectorSize; 1760 lp->d_ntracks = fd->currentType->heads; 1761 lp->d_ncylinders = fd->currentType->tracks; 1762 lp->d_nsectors = fd->currentType->secPerTrack; 1763 lp->d_secpercyl = fd->currentType->secPerCyl; 1764 lp->d_secperunit = fd->currentType->secPerDisk; 1765 lp->d_interleave = fd->currentType->interleave; 1766 lp->d_trkseek = fd->currentType->stepRate; 1767 1768 strcpy(lp->d_typename, dktypenames[DTYPE_FLOPPY]); 1769 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1770 1771 lp->d_npartitions = fdType + 1; 1772 lp->d_partitions[fdType].p_offset = 0; 1773 lp->d_partitions[fdType].p_size = lp->d_secperunit; 1774 lp->d_partitions[fdType].p_fstype = FS_BSDFFS; 1775 lp->d_partitions[fdType].p_fsize = 512; 1776 lp->d_partitions[fdType].p_frag = 8; 1777 1778 lp->d_magic = DISKMAGIC; 1779 lp->d_magic2 = DISKMAGIC; 1780 lp->d_checksum = dkcksum(lp); 1781 /* 1782 * Call the generic disklabel extraction routine. If we don't 1783 * find a label on disk, keep our faked one. 1784 */ 1785 if (TRACE_OPEN) 1786 printf(" now calling readdisklabel()...\n"); 1787 1788 msg = readdisklabel(dev, fdstrategy, lp, clp); 1789 if (msg == NULL) { 1790 strncpy(lp->d_packname, "default label", 1791 sizeof(lp->d_packname)); /* XXX - ?? */ 1792 } 1793 #ifdef IWM_DEBUG 1794 else 1795 printf("iwm: %s.\n", msg); 1796 #endif 1797 if (TRACE_OPEN) 1798 fdPrintDiskLabel(lp); 1799 } 1800 1801 1802 1803 /* 1804 * initCylinderCache 1805 * 1806 * Allocate cylinder cache and set up pointers to sectors. 1807 */ 1808 static int 1809 initCylinderCache(fd) 1810 fd_softc_t *fd; 1811 { 1812 int i; 1813 int err; 1814 int secsize; 1815 1816 err = 0; 1817 secsize = fd->currentType->sectorSize; 1818 fd->cachedSide = 0; 1819 1820 fd->cbuf = (unsigned char *) malloc(IWM_MAX_GCR_SECTORS 1821 * secsize, M_DEVBUF, M_WAITOK); 1822 if (NULL == fd->cbuf) 1823 err = ENOMEM; 1824 else 1825 for (i=0; i < IWM_MAX_GCR_SECTORS; i++) { 1826 fd->w_slots[i].valid = 0; 1827 fd->w_slots[i].secbuf = NULL; 1828 1829 fd->r_slots[i].valid = 0; 1830 fd->r_slots[i].secbuf = fd->cbuf + i * secsize; 1831 } 1832 return err; 1833 } 1834 1835 1836 /* 1837 * invalidateCylinderCache 1838 * 1839 * Switching cylinders (tracks?) invalidates the read cache. 1840 */ 1841 static void 1842 invalidateCylinderCache(fd) 1843 fd_softc_t *fd; 1844 { 1845 int i; 1846 1847 fd->cachedSide = 0; 1848 for (i=0; i < IWM_MAX_GCR_SECTORS; i++) { 1849 fd->r_slots[i].valid = 0; 1850 } 1851 } 1852 1853 1854 /* 1855 * getFDType 1856 * 1857 * return pointer to disk format description 1858 */ 1859 static fdInfo_t * 1860 getFDType(unit) 1861 short unit; 1862 { 1863 int driveFlags; 1864 fdInfo_t *thisType; 1865 extern fdInfo_t fdTypes[]; 1866 1867 driveFlags = iwmCheckDrive(unit); 1868 /* 1869 * Drive flags are: Bit 0 - 1 = Drive is double sided 1870 * 1 - 1 = No disk inserted 1871 * 2 - 1 = Motor is off 1872 * 3 - 1 = Disk is writeable 1873 * 4 - 1 = Disk is DD (800/720K) 1874 * 31 - 1 = No drive / invalid drive # 1875 */ 1876 if (TRACE_CONFIG) { 1877 printf("iwm: Drive %d says 0x0%x (%d)\n", 1878 unit, driveFlags, driveFlags); 1879 } 1880 if (driveFlags < 0) 1881 thisType = NULL;/* no such drive */ 1882 else 1883 if (driveFlags & 0x01) 1884 thisType = &fdTypes[1]; /* double sided */ 1885 else 1886 thisType = &fdTypes[0]; /* single sided */ 1887 1888 return thisType; 1889 } 1890 1891 1892 /* 1893 * fdDeviceToType 1894 * 1895 * maps the minor device number (elsewhere: partition type) to 1896 * a corresponding disk format. 1897 * This is currently: 1898 * fdXa default (800K GCR) 1899 * fdXb 400K GCR 1900 * fdXc 800K GCR 1901 */ 1902 static fdInfo_t * 1903 fdDeviceToType(fd, dev) 1904 fd_softc_t *fd; 1905 dev_t dev; 1906 { 1907 int type; 1908 fdInfo_t *thisInfo; 1909 /* XXX This broke with egcs 1.0.2 */ 1910 /* extern fdInfo_t fdTypes[]; */ 1911 1912 type = minor(dev) % MAXPARTITIONS; /* 1,2,... */ 1913 if (type > sizeof(fdTypes) / sizeof(fdTypes[0])) 1914 thisInfo = NULL; 1915 else 1916 thisInfo = (type == 0) ? fd->defaultType : &fdTypes[type - 1]; 1917 return thisInfo; 1918 } 1919 1920 1921 /* 1922 * seek 1923 * 1924 * Step to given track; optionally restore to track zero before 1925 * and/or verify correct track. 1926 * Note that any necessary retries are done here. 1927 * We keep the current position on disk in a 'struct diskPosition'. 1928 */ 1929 static int 1930 seek(fd, style) 1931 fd_softc_t *fd; 1932 int style; 1933 { 1934 int state, done; 1935 int err, ierr; 1936 int steps; 1937 1938 diskPosition_t *loc; 1939 sectorHdr_t hdr; 1940 char action[32]; 1941 #ifndef _LKM 1942 iwm_softc_t *iwm = iwm_cd.cd_devs[0]; 1943 #endif 1944 1945 char *stateDesc[] = { 1946 "Init", 1947 "Seek", 1948 "Recalibrate", 1949 "Verify", 1950 "Exit" 1951 }; 1952 enum { 1953 state_Init = 0, 1954 state_Seek, 1955 state_Recalibrate, 1956 state_Verify, 1957 state_Exit 1958 }; 1959 /* XXX egcs */ 1960 done = err = ierr = 0; 1961 fd->seekRetries = 0; 1962 fd->verifyRetries = 0; 1963 1964 loc = &fd->pos; 1965 1966 state = state_Init; 1967 do { 1968 if (TRACE_STEP) 1969 printf(" seek state %d [%s].\n", 1970 state, stateDesc[state]); 1971 switch (state) { 1972 1973 case state_Init: 1974 if (TRACE_STEP) 1975 printf("Current track is %d, new track %d.\n", 1976 loc->oldTrack, loc->track); 1977 memset(&hdr, 0, sizeof(hdr)); 1978 err = ierr = 0; 1979 fd->seekRetries = 0; 1980 fd->verifyRetries = 0; 1981 state = (style == IWM_SEEK_RECAL) 1982 ? state_Recalibrate : state_Seek; 1983 done = 0; 1984 break; 1985 1986 case state_Recalibrate: 1987 ierr = iwmTrack00(); 1988 if (ierr == 0) { 1989 loc->oldTrack = 0; 1990 state = state_Seek; 1991 } else { 1992 strncpy(action, "Recalibrate (track 0)", 1993 sizeof(action)); 1994 state = state_Exit; 1995 } 1996 break; 1997 1998 case state_Seek: 1999 ierr = 0; 2000 steps = loc->track - loc->oldTrack; 2001 2002 if (steps != 0) 2003 ierr = iwmSeek(steps); 2004 if (ierr == 0) { 2005 /* No error or nothing to do */ 2006 state = (style == IWM_SEEK_VERIFY) 2007 ? state_Verify : state_Exit; 2008 } else { 2009 if (fd->seekRetries++ < iwm->maxRetries) 2010 state = state_Recalibrate; 2011 else { 2012 strncpy(action, "Seek retries", 2013 sizeof(action)); 2014 state = state_Exit; 2015 } 2016 } 2017 break; 2018 2019 case state_Verify: 2020 ierr = checkTrack(loc, TRACE_STEP); 2021 if (ierr == 0 && loc->track == hdr.track) 2022 state = state_Exit; 2023 else { 2024 if (fd->verifyRetries++ < iwm->maxRetries) 2025 state = state_Recalibrate; 2026 else { 2027 strncpy(action, "Verify retries", 2028 sizeof(action)); 2029 state = state_Exit; 2030 } 2031 } 2032 break; 2033 2034 case state_Exit: 2035 if (ierr == 0) { 2036 loc->oldTrack = loc->track; 2037 err = 0; 2038 /* Give the head some time to settle down */ 2039 delay(3000); 2040 } else { 2041 #ifdef DIAGNOSTIC 2042 printf(" seek() action \"%s\", err = %d.\n", 2043 action, ierr); 2044 #endif 2045 err = EIO; 2046 } 2047 done = 1; 2048 break; 2049 } 2050 } while (!done); 2051 return err; 2052 } 2053 2054 2055 /* 2056 * checkTrack 2057 * 2058 * After positioning, get a sector header for validation 2059 */ 2060 static int 2061 checkTrack(loc, debugFlag) 2062 diskPosition_t *loc; 2063 int debugFlag; 2064 { 2065 int spl; 2066 int iwmErr; 2067 sectorHdr_t hdr; 2068 2069 spl = spl6(); 2070 iwmSelectSide(loc->side); 2071 iwmErr = iwmReadSectHdr(&hdr); 2072 splx(spl); 2073 if (debugFlag) { 2074 printf("Seeked for %d, got at %d, Hdr read err %d.\n", 2075 loc->track, hdr.track, iwmErr); 2076 } 2077 return iwmErr; 2078 } 2079 2080 2081 /* Debugging stuff */ 2082 2083 static void 2084 hexDump(buf, len) 2085 u_char *buf; 2086 int len; 2087 { 2088 int i, j; 2089 u_char ch; 2090 2091 printf("\nDump %d from %p:\n", len, buf); 2092 i = j = 0; 2093 if (NULL != buf) do { 2094 printf("%04x: ", i); 2095 for (j = 0; j < 8; j++) 2096 printf("%02x ", buf[i + j]); 2097 printf(" "); 2098 for (j = 8; j < 16; j++) 2099 printf("%02x ", buf[i + j]); 2100 printf(" "); 2101 for (j = 0; j < 16; j++) { 2102 ch = buf[i + j]; 2103 if (ch > 31 && ch < 127) 2104 printf("%c", ch); 2105 else 2106 printf("."); 2107 } 2108 printf("\n"); 2109 i += 16; 2110 } while (len > i); 2111 } 2112 2113 2114 static void 2115 fdPrintDiskLabel(lp) 2116 struct disklabel *lp; 2117 { 2118 int i; 2119 2120 printf("iwm: Disklabel entries of current floppy.\n"); 2121 printf("\t d_type:\t%d (%s)\n", lp->d_type, 2122 dktypenames[lp->d_type]); 2123 printf("\t d_typename:\t%s\n", lp->d_typename); 2124 printf("\t d_packname:\t%s\n", lp->d_packname); 2125 2126 printf("\t d_secsize:\t%d\n", lp->d_secsize); 2127 printf("\t d_nsectors:\t%d\n", lp->d_nsectors); 2128 printf("\t d_ntracks:\t%d\n", lp->d_ntracks); 2129 printf("\t d_ncylinders:\t%d\n", lp->d_ncylinders); 2130 printf("\t d_secpercyl:\t%d\n", lp->d_secpercyl); 2131 printf("\t d_secperunit:\t%d\n", lp->d_secperunit); 2132 2133 printf("\t d_rpm: \t%d\n", lp->d_rpm); 2134 printf("\t d_interleave:\t%d\n", lp->d_interleave); 2135 printf("\t d_trkseek:\t%d [ms]\n", lp->d_trkseek); 2136 2137 printf(" d_npartitions:\t%d\n", lp->d_npartitions); 2138 for (i = 0; i < lp->d_npartitions; i++) { 2139 printf("\t d_partitions[%d].p_offset:\t%d\n", i, 2140 lp->d_partitions[i].p_offset); 2141 printf("\t d_partitions[%d].p_size:\t%d\n", i, 2142 lp->d_partitions[i].p_size); 2143 printf("\t d_partitions[%d].p_fstype:\t%d (%s)\n", i, 2144 lp->d_partitions[i].p_fstype, 2145 fstypenames[lp->d_partitions[i].p_fstype]); 2146 printf("\t d_partitions[%d].p_frag:\t%d\n", i, 2147 lp->d_partitions[i].p_frag); 2148 printf("\n"); 2149 } 2150 } 2151