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