1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Floppy Disk Controller Driver 31 * 32 * for the standard PC architecture using the Intel 8272A fdc. 33 * Note that motor control and drive select use a latch external 34 * to the fdc. 35 * 36 * This driver is EISA capable, and uses DMA buffer chaining if available. 37 * If this driver is attached to the ISA bus nexus (or if the EISA bus driver 38 * does not support DMA buffer chaining), then the bus driver must ensure 39 * that dma mapping (breakup) and dma engine requests are properly degraded. 40 */ 41 42 /* 43 * hack for bugid 1160621: 44 * workaround compiler optimization bug by turning on DEBUG 45 */ 46 #ifndef DEBUG 47 #define DEBUG 1 48 #endif 49 50 #include <sys/param.h> 51 #include <sys/buf.h> 52 #include <sys/ioctl.h> 53 #include <sys/uio.h> 54 #include <sys/open.h> 55 #include <sys/conf.h> 56 #include <sys/file.h> 57 #include <sys/cmn_err.h> 58 #include <sys/debug.h> 59 #include <sys/kmem.h> 60 #include <sys/stat.h> 61 62 #include <sys/autoconf.h> 63 #include <sys/dkio.h> 64 #include <sys/vtoc.h> 65 #include <sys/kstat.h> 66 67 #include <sys/fdio.h> 68 #include <sys/fdc.h> 69 #include <sys/i8272A.h> 70 #include <sys/fd_debug.h> 71 #include <sys/promif.h> 72 #include <sys/ddi.h> 73 #include <sys/sunddi.h> 74 75 /* 76 * bss (uninitialized data) 77 */ 78 static void *fdc_state_head; /* opaque handle top of state structs */ 79 static ddi_dma_attr_t fdc_dma_attr; 80 81 /* 82 * Local static data 83 */ 84 #define OURUN_TRIES 12 85 static uchar_t rwretry = 4; 86 static uchar_t skretry = 3; 87 static uchar_t configurecmd[4] = {FO_CNFG, 0, 0x0F, 0}; 88 static uchar_t recalcmd[2] = {FO_RECAL, 0}; 89 static uchar_t senseintcmd = FO_SINT; 90 91 /* 92 * error handling 93 * 94 * for debugging, set rwretry and skretry = 1 95 * set fcerrlevel to 1 96 * set fcerrmask to 224 or 644 97 * 98 * after debug, set rwretry to 4, skretry to 3, and fcerrlevel to 5 99 * set fcerrmask to FDEM_ALL 100 * or remove the define DEBUG 101 */ 102 static uint_t fcerrmask = FDEM_ALL; 103 static int fcerrlevel = 6; 104 105 #define KIOIP KSTAT_INTR_PTR(fcp->c_intrstat) 106 107 108 static xlate_tbl_t drate_mfm[] = { 109 { 250, 2}, 110 { 300, 1}, 111 { 417, 0}, 112 { 500, 0}, 113 { 1000, 3}, 114 { 0, 0} 115 }; 116 117 static xlate_tbl_t sector_size[] = { 118 { 256, 1}, 119 { 512, 2}, 120 { 1024, 3}, 121 { 0, 2} 122 }; 123 124 static xlate_tbl_t motor_onbits[] = { 125 { 0, 0x10}, 126 { 1, 0x20}, 127 { 2, 0x40}, 128 { 3, 0x80}, 129 { 0, 0x80} 130 }; 131 132 static xlate_tbl_t step_rate[] = { 133 { 10, 0xF0}, /* for 500K data rate */ 134 { 20, 0xE0}, 135 { 30, 0xD0}, 136 { 40, 0xC0}, 137 { 50, 0xB0}, 138 { 60, 0xA0}, 139 { 70, 0x90}, 140 { 80, 0x80}, 141 { 90, 0x70}, 142 { 100, 0x60}, 143 { 110, 0x50}, 144 { 120, 0x40}, 145 { 130, 0x30}, 146 { 140, 0x20}, 147 { 150, 0x10}, 148 { 160, 0x00}, 149 { 0, 0x00} 150 }; 151 152 #ifdef notdef 153 static xlate_tbl_t head_unld[] = { 154 { 16, 0x1}, /* for 500K data rate */ 155 { 32, 0x2}, 156 { 48, 0x3}, 157 { 64, 0x4}, 158 { 80, 0x5}, 159 { 96, 0x6}, 160 { 112, 0x7}, 161 { 128, 0x8}, 162 { 144, 0x9}, 163 { 160, 0xA}, 164 { 176, 0xB}, 165 { 192, 0xC}, 166 { 208, 0xD}, 167 { 224, 0xE}, 168 { 240, 0xF}, 169 { 256, 0x0}, 170 { 0, 0x0} 171 }; 172 #endif 173 174 static struct fdcmdinfo { 175 char *cmdname; /* command name */ 176 uchar_t ncmdbytes; /* number of bytes of command */ 177 uchar_t nrsltbytes; /* number of bytes in result */ 178 uchar_t cmdtype; /* characteristics */ 179 } fdcmds[] = { 180 "", 0, 0, 0, /* - */ 181 "", 0, 0, 0, /* - */ 182 "read_track", 9, 7, 1, /* 2 */ 183 "specify", 3, 0, 3, /* 3 */ 184 "sense_drv_status", 2, 1, 3, /* 4 */ 185 "write", 9, 7, 1, /* 5 */ 186 "read", 9, 7, 1, /* 6 */ 187 "recalibrate", 2, 0, 2, /* 7 */ 188 "sense_int_status", 1, 2, 3, /* 8 */ 189 "write_del", 9, 7, 1, /* 9 */ 190 "read_id", 2, 7, 2, /* A */ 191 "", 0, 0, 0, /* - */ 192 "read_del", 9, 7, 1, /* C */ 193 "format_track", 10, 7, 1, /* D */ 194 "dump_reg", 1, 10, 4, /* E */ 195 "seek", 3, 0, 2, /* F */ 196 "version", 1, 1, 3, /* 10 */ 197 "", 0, 0, 0, /* - */ 198 "perp_mode", 2, 0, 3, /* 12 */ 199 "configure", 4, 0, 4, /* 13 */ 200 /* relative seek */ 201 }; 202 203 204 static int 205 fdc_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 206 static int get_ioaddr(dev_info_t *dip, int *ioaddr); 207 static int get_unit(dev_info_t *dip, int *cntrl_num); 208 209 struct bus_ops fdc_bus_ops = { 210 BUSO_REV, 211 nullbusmap, 212 0, /* ddi_intrspec_t (*bus_get_intrspec)(); */ 213 0, /* int (*bus_add_intrspec)(); */ 214 0, /* void (*bus_remove_intrspec)(); */ 215 i_ddi_map_fault, 216 ddi_dma_map, 217 ddi_dma_allochdl, 218 ddi_dma_freehdl, 219 ddi_dma_bindhdl, 220 ddi_dma_unbindhdl, 221 ddi_dma_flush, 222 ddi_dma_win, 223 ddi_dma_mctl, 224 fdc_bus_ctl, 225 ddi_bus_prop_op, 226 }; 227 228 static int fdc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 229 static int fdc_probe(dev_info_t *); 230 static int fdc_attach(dev_info_t *, ddi_attach_cmd_t); 231 static int fdc_detach(dev_info_t *, ddi_detach_cmd_t); 232 static int fdc_enhance_probe(struct fdcntlr *fcp); 233 234 struct dev_ops fdc_ops = { 235 DEVO_REV, /* devo_rev, */ 236 0, /* refcnt */ 237 fdc_getinfo, /* getinfo */ 238 nulldev, /* identify */ 239 fdc_probe, /* probe */ 240 fdc_attach, /* attach */ 241 fdc_detach, /* detach */ 242 nodev, /* reset */ 243 (struct cb_ops *)0, /* driver operations */ 244 &fdc_bus_ops /* bus operations */ 245 }; 246 247 /* 248 * This is the loadable module wrapper. 249 */ 250 #include <sys/modctl.h> 251 252 extern struct mod_ops mod_driverops; 253 254 static struct modldrv modldrv = { 255 &mod_driverops, /* Type of module. This one is a driver */ 256 "Floppy Controller %I%", /* Name of the module. */ 257 &fdc_ops, /* Driver ops vector */ 258 }; 259 260 static struct modlinkage modlinkage = { 261 MODREV_1, (void *)&modldrv, NULL 262 }; 263 264 int 265 _init(void) 266 { 267 int retval; 268 269 if ((retval = ddi_soft_state_init(&fdc_state_head, 270 sizeof (struct fdcntlr) + NFDUN * sizeof (struct fcu_obj), 0)) != 0) 271 return (retval); 272 273 if ((retval = mod_install(&modlinkage)) != 0) 274 ddi_soft_state_fini(&fdc_state_head); 275 return (retval); 276 } 277 278 int 279 _fini(void) 280 { 281 int retval; 282 283 if ((retval = mod_remove(&modlinkage)) != 0) 284 return (retval); 285 ddi_soft_state_fini(&fdc_state_head); 286 return (retval); 287 } 288 289 int 290 _info(struct modinfo *modinfop) 291 { 292 return (mod_info(&modlinkage, modinfop)); 293 } 294 295 296 int fdc_start(struct fcu_obj *); 297 int fdc_abort(struct fcu_obj *); 298 int fdc_getcap(struct fcu_obj *, char *, int); 299 int fdc_setcap(struct fcu_obj *, char *, int, int); 300 int fdc_dkinfo(struct fcu_obj *, struct dk_cinfo *); 301 int fdc_select(struct fcu_obj *, int, int); 302 int fdgetchng(struct fcu_obj *, int); 303 int fdresetchng(struct fcu_obj *, int); 304 int fdrecalseek(struct fcu_obj *, int, int, int); 305 int fdrwbuf(struct fcu_obj *, int, int, int, int, int, struct buf *); 306 int fdrw(struct fcu_obj *, int, int, int, int, int, caddr_t, uint_t); 307 int fdtrkformat(struct fcu_obj *, int, int, int, int); 308 int fdrawioctl(struct fcu_obj *, int, caddr_t); 309 310 static struct fcobjops fdc_iops = { 311 fdc_start, /* controller start */ 312 fdc_abort, /* controller abort */ 313 fdc_getcap, /* capability retrieval */ 314 fdc_setcap, /* capability establishment */ 315 fdc_dkinfo, /* get disk controller info */ 316 317 fdc_select, /* select / deselect unit */ 318 fdgetchng, /* get media change */ 319 fdresetchng, /* reset media change */ 320 fdrecalseek, /* recal / seek */ 321 fdrwbuf, /* read /write request */ 322 fdrw, /* read /write sector */ 323 fdtrkformat, /* format track */ 324 fdrawioctl /* raw ioctl */ 325 }; 326 327 328 /* 329 * Function prototypes 330 */ 331 void encode(xlate_tbl_t *tablep, int val, uchar_t *rcode); 332 int decode(xlate_tbl_t *, int, int *); 333 static int fdc_propinit1(struct fdcntlr *, int); 334 static void fdc_propinit2(struct fdcntlr *, int); 335 void fdcquiesce(struct fdcntlr *); 336 int fdcsense_chng(struct fdcntlr *, int); 337 int fdcsense_drv(struct fdcntlr *, int); 338 int fdcsense_int(struct fdcntlr *, int *, int *); 339 int fdcspecify(struct fdcntlr *, int, int, int); 340 int fdcspdchange(struct fdcntlr *, struct fcu_obj *, int); 341 static int fdc_exec(struct fdcntlr *, int, int); 342 int fdcheckdisk(struct fdcntlr *, int); 343 static uint_t fdc_intr(caddr_t arg); 344 static void fdwatch(void *arg); 345 static void fdmotort(void *arg); 346 static int fdrecover(struct fdcntlr *); 347 static int fdc_motorsm(struct fcu_obj *, int, int); 348 static int fdc_statemach(struct fdcntlr *); 349 int fdc_docmd(struct fdcntlr *, uchar_t *, uchar_t); 350 int fdc_result(struct fdcntlr *, uchar_t *, uchar_t); 351 352 353 /* ARGSUSED */ 354 static int 355 fdc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 356 void *arg, void *result) 357 { 358 struct fdcntlr *fcp; 359 struct fcu_obj *fjp; 360 361 FCERRPRINT(FDEP_L0, FDEM_ATTA, 362 (CE_CONT, "fdc_bus_ctl: cmd= %x\n", ctlop)); 363 364 if ((fcp = ddi_get_driver_private(dip)) == NULL) 365 return (DDI_FAILURE); 366 367 switch (ctlop) { 368 369 case DDI_CTLOPS_REPORTDEV: 370 cmn_err(CE_CONT, "?%s%d at %s%d\n", 371 ddi_get_name(rdip), ddi_get_instance(rdip), 372 ddi_get_name(dip), ddi_get_instance(dip)); 373 FCERRPRINT(FDEP_L3, FDEM_ATTA, 374 (CE_WARN, "fdc_bus_ctl: report %s%d at %s%d", 375 ddi_get_name(rdip), ddi_get_instance(rdip), 376 ddi_get_name(dip), ddi_get_instance(dip))); 377 return (DDI_SUCCESS); 378 379 case DDI_CTLOPS_INITCHILD: 380 { 381 dev_info_t *udip = (dev_info_t *)arg; 382 int cntlr; 383 int len; 384 int unit; 385 char name[MAXNAMELEN]; 386 387 FCERRPRINT(FDEP_L3, FDEM_ATTA, 388 (CE_WARN, "fdc_bus_ctl: init child 0x%p", (void*)udip)); 389 cntlr = fcp->c_number; 390 391 len = sizeof (unit); 392 if (ddi_prop_op(DDI_DEV_T_ANY, udip, PROP_LEN_AND_VAL_BUF, 393 DDI_PROP_DONTPASS, "unit", (caddr_t)&unit, &len) 394 != DDI_PROP_SUCCESS || 395 cntlr != FDCTLR(unit) || 396 (fcp->c_unit[FDUNIT(unit)])->fj_dip) 397 return (DDI_NOT_WELL_FORMED); 398 399 (void) sprintf(name, "%d,%d", cntlr, FDUNIT(unit)); 400 ddi_set_name_addr(udip, name); 401 402 fjp = fcp->c_unit[FDUNIT(unit)]; 403 fjp->fj_unit = unit; 404 fjp->fj_dip = udip; 405 fjp->fj_ops = &fdc_iops; 406 fjp->fj_fdc = fcp; 407 fjp->fj_iblock = &fcp->c_iblock; 408 409 ddi_set_driver_private(udip, fjp); 410 411 return (DDI_SUCCESS); 412 } 413 case DDI_CTLOPS_UNINITCHILD: 414 { 415 dev_info_t *udip = (dev_info_t *)arg; 416 417 FCERRPRINT(FDEP_L3, FDEM_ATTA, 418 (CE_WARN, "fdc_bus_ctl: uninit child 0x%p", (void *)udip)); 419 fjp = ddi_get_driver_private(udip); 420 ddi_set_driver_private(udip, NULL); 421 fjp->fj_dip = NULL; 422 ddi_set_name_addr(udip, NULL); 423 return (DDI_SUCCESS); 424 } 425 default: 426 return (DDI_FAILURE); 427 } 428 } 429 430 /* ARGSUSED */ 431 static int 432 fdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 433 { 434 struct fdcntlr *fcp; 435 int rval; 436 437 switch (cmd) { 438 case DDI_INFO_DEVT2DEVINFO: 439 if (fcp = ddi_get_soft_state(fdc_state_head, (dev_t)arg)) { 440 *result = fcp->c_dip; 441 rval = DDI_SUCCESS; 442 break; 443 } else { 444 rval = DDI_FAILURE; 445 break; 446 } 447 case DDI_INFO_DEVT2INSTANCE: 448 *result = (void *)(uintptr_t)getminor((dev_t)arg); 449 rval = DDI_SUCCESS; 450 break; 451 default: 452 rval = DDI_FAILURE; 453 } 454 return (rval); 455 } 456 457 static int 458 fdc_probe(dev_info_t *dip) 459 { 460 int debug[2]; 461 int ioaddr; 462 int len; 463 uchar_t stat; 464 465 len = sizeof (debug); 466 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 467 DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) == 468 DDI_PROP_SUCCESS) { 469 fcerrlevel = debug[0]; 470 fcerrmask = (uint_t)debug[1]; 471 } 472 473 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_probe: dip %p", 474 (void*)dip)); 475 476 if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS) 477 return (DDI_PROBE_FAILURE); 478 479 stat = inb(ioaddr + FCR_MSR); 480 if ((stat & (MS_RQM | MS_DIO | MS_CB)) != MS_RQM && 481 (stat & ~MS_DIO) != MS_CB) 482 return (DDI_PROBE_FAILURE); 483 484 return (DDI_PROBE_SUCCESS); 485 } 486 487 /* ARGSUSED */ 488 static int 489 fdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 490 { 491 struct fdcntlr *fcp; 492 struct fcu_obj *fjp; 493 int cntlr_num, ctlr, unit; 494 int intr_set = 0; 495 int len; 496 char name[MAXNAMELEN]; 497 498 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_attach: dip %p", 499 (void*)dip)); 500 501 switch (cmd) { 502 case DDI_ATTACH: 503 if (ddi_getprop 504 (DDI_DEV_T_ANY, dip, 0, "ignore-hardware-nodes", 0)) { 505 len = sizeof (cntlr_num); 506 if (ddi_prop_op(DDI_DEV_T_ANY, dip, 507 PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "unit", 508 (caddr_t)&cntlr_num, &len) != DDI_PROP_SUCCESS) { 509 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, 510 "fdc_attach failed: dip %p", (void*)dip)); 511 return (DDI_FAILURE); 512 } 513 } else { 514 if (get_unit(dip, &cntlr_num) != DDI_SUCCESS) 515 return (DDI_FAILURE); 516 } 517 518 ctlr = ddi_get_instance(dip); 519 if (ddi_soft_state_zalloc(fdc_state_head, ctlr) != 0) 520 return (DDI_FAILURE); 521 fcp = ddi_get_soft_state(fdc_state_head, ctlr); 522 523 for (unit = 0, fjp = (struct fcu_obj *)(fcp+1); 524 unit < NFDUN; unit++) { 525 fcp->c_unit[unit] = fjp++; 526 } 527 fcp->c_dip = dip; 528 529 if (fdc_propinit1(fcp, cntlr_num) != DDI_SUCCESS) 530 goto no_attach; 531 532 /* get iblock cookie to initialize mutex used in the ISR */ 533 if (ddi_get_iblock_cookie(dip, (uint_t)0, &fcp->c_iblock) != 534 DDI_SUCCESS) { 535 cmn_err(CE_WARN, 536 "fdc_attach: cannot get iblock cookie"); 537 goto no_attach; 538 } 539 mutex_init(&fcp->c_lock, NULL, MUTEX_DRIVER, fcp->c_iblock); 540 intr_set = 1; 541 542 /* setup interrupt handler */ 543 if (ddi_add_intr(dip, (uint_t)0, NULL, 544 (ddi_idevice_cookie_t *)0, fdc_intr, (caddr_t)fcp) != 545 DDI_SUCCESS) { 546 cmn_err(CE_WARN, "fdc: cannot add intr\n"); 547 goto no_attach; 548 } 549 intr_set++; 550 551 /* 552 * acquire the DMA channel 553 * this assumes that the chnl is not shared; else allocate 554 * and free the chnl with each fdc request 555 */ 556 if (ddi_dmae_alloc(dip, fcp->c_dmachan, DDI_DMA_DONTWAIT, NULL) 557 != DDI_SUCCESS) { 558 cmn_err(CE_WARN, "fdc: cannot acquire dma%d\n", 559 fcp->c_dmachan); 560 goto no_attach; 561 } 562 (void) ddi_dmae_getattr(dip, &fdc_dma_attr); 563 564 mutex_init(&fcp->c_dorlock, NULL, MUTEX_DRIVER, fcp->c_iblock); 565 cv_init(&fcp->c_iocv, NULL, CV_DRIVER, fcp->c_iblock); 566 sema_init(&fcp->c_selsem, 1, NULL, SEMA_DRIVER, NULL); 567 568 (void) sprintf(name, "fdc%d", ctlr); 569 fcp->c_intrstat = kstat_create("fdc", ctlr, name, 570 "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 571 if (fcp->c_intrstat) { 572 kstat_install(fcp->c_intrstat); 573 } 574 575 ddi_set_driver_private(dip, fcp); 576 577 /* 578 * reset the controller 579 */ 580 sema_p(&fcp->c_selsem); 581 mutex_enter(&fcp->c_lock); 582 fcp->c_csb.csb_xstate = FXS_RESET; 583 fcp->c_flags |= FCFLG_WAITING; 584 fdcquiesce(fcp); 585 586 /* first test for mode == Model 30 */ 587 fcp->c_mode = (inb(fcp->c_regbase + FCR_SRB) & 0x1c) ? 588 FDCMODE_AT : FDCMODE_30; 589 590 while (fcp->c_flags & FCFLG_WAITING) { 591 cv_wait(&fcp->c_iocv, &fcp->c_lock); 592 } 593 mutex_exit(&fcp->c_lock); 594 sema_v(&fcp->c_selsem); 595 596 fdc_propinit2(fcp, cntlr_num); 597 598 ddi_report_dev(dip); 599 return (DDI_SUCCESS); 600 601 default: 602 return (DDI_FAILURE); 603 } 604 605 no_attach: 606 if (intr_set) { 607 if (intr_set > 1) 608 ddi_remove_intr(dip, 0, fcp->c_iblock); 609 mutex_destroy(&fcp->c_lock); 610 } 611 ddi_soft_state_free(fdc_state_head, cntlr_num); 612 return (DDI_FAILURE); 613 } 614 615 static int 616 fdc_propinit1(struct fdcntlr *fcp, int cntlr) 617 { 618 dev_info_t *dip; 619 int len; 620 int value; 621 622 dip = fcp->c_dip; 623 len = sizeof (value); 624 625 if (get_ioaddr(dip, &value) != DDI_SUCCESS) 626 return (DDI_FAILURE); 627 628 fcp->c_regbase = (ushort_t)value; 629 630 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 631 DDI_PROP_DONTPASS, "dma-channels", (caddr_t)&value, &len) 632 != DDI_PROP_SUCCESS) { 633 cmn_err(CE_WARN, 634 "fdc_attach: Error, could not find a dma channel"); 635 return (DDI_FAILURE); 636 } 637 fcp->c_dmachan = (ushort_t)value; 638 fcp->c_number = cntlr; 639 return (DDI_SUCCESS); 640 } 641 642 /* ARGSUSED */ 643 static void 644 fdc_propinit2(struct fdcntlr *fcp, int cntlr) 645 { 646 dev_info_t *dip; 647 int ccr; 648 int len; 649 int value; 650 651 dip = fcp->c_dip; 652 len = sizeof (value); 653 654 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 655 DDI_PROP_DONTPASS, "chip", (caddr_t)&value, &len) 656 == DDI_PROP_SUCCESS) 657 fcp->c_chip = value; 658 else { 659 static uchar_t perpindcmd[2] = {FO_PERP, 0}; 660 static uchar_t versioncmd = FO_VRSN; 661 uchar_t result; 662 663 fcp->c_chip = i8272A; 664 (void) fdc_docmd(fcp, &versioncmd, 1); 665 /* 666 * Ignored return. If failed, warning was issued by fdc_docmd. 667 * fdc_results retrieves the controller/drive status 668 */ 669 if (!fdc_result(fcp, &result, 1) && result == 0x90) { 670 /* 671 * try a perpendicular_mode cmd to ensure 672 * that we really have an enhanced controller 673 */ 674 if (fdc_docmd(fcp, perpindcmd, 2) || 675 fdc_docmd(fcp, configurecmd, 4)) 676 /* 677 * perpindicular_mode will be rejected by 678 * older controllers; make sure we don't hang. 679 */ 680 (void) fdc_result(fcp, &result, 1); 681 /* 682 * Ignored return. If failed, warning was 683 * issued by fdc_result. 684 */ 685 else 686 /* enhanced type controller */ 687 688 if ((fcp->c_chip = fdc_enhance_probe(fcp)) == 0) 689 /* default enhanced cntlr */ 690 fcp->c_chip = i82077; 691 } 692 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 693 "chip", fcp->c_chip); 694 /* 695 * Ignoring return value because, for passed arguments, only 696 * DDI_SUCCESS is returned. 697 */ 698 } 699 if (fcp->c_chip >= i82077 && fcp->c_mode == FDCMODE_30 && 700 (inb(fcp->c_regbase + FCR_DIR) & 0x70) == 0) 701 for (ccr = 0; ccr <= (FCC_NOPREC | FCC_DRATE); ccr++) { 702 /* 703 * run through all the combinations of NOPREC and 704 * datarate selection, and see if they show up in the 705 * Model 30 DIR 706 */ 707 outb(fcp->c_regbase + FCR_CCR, ccr); 708 drv_usecwait(5); 709 if ((inb(fcp->c_regbase + FCR_DIR) & 710 (FCC_NOPREC | FCC_DRATE)) != ccr) { 711 fcp->c_mode = FDCMODE_AT; 712 break; 713 } 714 } 715 else 716 fcp->c_mode = FDCMODE_AT; 717 outb(fcp->c_regbase + FCR_CCR, 0); 718 } 719 720 /* ARGSUSED */ 721 static int 722 fdc_enhance_probe(struct fdcntlr *fcp) 723 { 724 static uchar_t nsccmd = FO_NSC; 725 uint_t ddic; 726 int retcode = 0; 727 uchar_t result; 728 uchar_t save; 729 730 /* 731 * Try to identify the enhanced floppy controller. 732 * This is required so that we can program the DENSEL output to 733 * control 3D mode (1.0 MB, 1.6 MB and 2.0 MB unformatted capacity, 734 * 720 KB, 1.2 MB, and 1.44 MB formatted capacity) 3.5" dual-speed 735 * floppy drives. Refer to bugid 1195155. 736 */ 737 738 (void) fdc_docmd(fcp, &nsccmd, 1); 739 /* 740 * Ignored return. If failed, warning was issued by fdc_docmd. 741 * fdc_results retrieves the controller/drive status 742 */ 743 if (!fdc_result(fcp, &result, 1) && result != S0_IVCMD) { 744 /* 745 * only enhanced National Semi PC8477 core 746 * should respond to this command 747 */ 748 if ((result & 0xf0) == 0x70) { 749 /* low 4 bits may change */ 750 fcp->c_flags |= FCFLG_3DMODE; 751 retcode = PC87322; 752 } else 753 cmn_err(CE_CONT, 754 "?fdc: unidentified, enhanced, National Semiconductor cntlr %x\n", result); 755 } else { 756 save = inb(fcp->c_regbase + FCR_SRA); 757 758 do { 759 /* probe for motherboard version of SMC cntlr */ 760 761 /* try to enable configuration mode */ 762 ddic = ddi_enter_critical(); 763 outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 764 outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 765 ddi_exit_critical(ddic); 766 767 outb(fcp->c_regbase + FCR_SRA, 0x0F); 768 if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 769 /* always expect 0 from config reg F */ 770 break; 771 outb(fcp->c_regbase + FCR_SRA, 0x0D); 772 if (inb(fcp->c_regbase + FCR_SRB) != 0x65) 773 /* expect 0x65 from config reg D */ 774 break; 775 outb(fcp->c_regbase + FCR_SRA, 0x0E); 776 result = inb(fcp->c_regbase + FCR_SRB); 777 if (result != 0x02) { 778 /* expect revision level 2 from config reg E */ 779 cmn_err(CE_CONT, 780 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 781 /* break; */ 782 } 783 fcp->c_flags |= FCFLG_3DMODE; 784 retcode = FDC37C665; 785 } while (retcode == 0); 786 outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 787 788 while (retcode == 0) { 789 /* probe for adapter version of SMC cntlr */ 790 ddic = ddi_enter_critical(); 791 outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 792 outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 793 ddi_exit_critical(ddic); 794 795 outb(fcp->c_regbase + FCR_SRA, 0x0F); 796 if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 797 /* always expect 0 from config reg F */ 798 break; 799 outb(fcp->c_regbase + FCR_SRA, 0x0D); 800 if (inb(fcp->c_regbase + FCR_SRB) != 0x66) 801 /* expect 0x66 from config reg D */ 802 break; 803 outb(fcp->c_regbase + FCR_SRA, 0x0E); 804 result = inb(fcp->c_regbase + FCR_SRB); 805 if (result != 0x02) { 806 /* expect revision level 2 from config reg E */ 807 cmn_err(CE_CONT, 808 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 809 /* break; */ 810 } 811 fcp->c_flags |= FCFLG_3DMODE; 812 retcode = FDC37C666; 813 } 814 outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 815 816 drv_usecwait(10); 817 outb(fcp->c_regbase + FCR_SRA, save); 818 } 819 return (retcode); 820 } 821 822 /* ARGSUSED */ 823 static int 824 fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 825 { 826 struct fdcntlr *fcp; 827 int unit; 828 int rval = 0; 829 830 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_detach: dip %p", 831 (void*)dip)); 832 833 fcp = ddi_get_driver_private(dip); 834 835 switch (cmd) { 836 case DDI_DETACH: 837 for (unit = 0; unit < NFDUN; unit++) 838 if ((fcp->c_unit[unit])->fj_dip) { 839 rval = EBUSY; 840 break; 841 } 842 kstat_delete(fcp->c_intrstat); 843 fcp->c_intrstat = NULL; 844 ddi_remove_intr(fcp->c_dip, 0, fcp->c_iblock); 845 if (ddi_dmae_release(fcp->c_dip, fcp->c_dmachan) != 846 DDI_SUCCESS) 847 cmn_err(CE_WARN, "fdc_detach: dma release failed, " 848 "dip %p, dmachan %x\n", 849 (void*)fcp->c_dip, fcp->c_dmachan); 850 ddi_prop_remove_all(fcp->c_dip); 851 ddi_set_driver_private(fcp->c_dip, NULL); 852 853 mutex_destroy(&fcp->c_lock); 854 mutex_destroy(&fcp->c_dorlock); 855 cv_destroy(&fcp->c_iocv); 856 sema_destroy(&fcp->c_selsem); 857 ddi_soft_state_free(fdc_state_head, ddi_get_instance(dip)); 858 break; 859 default: 860 rval = EINVAL; 861 break; 862 } 863 return (rval); 864 } 865 866 867 /* ARGSUSED */ 868 int 869 fdc_start(struct fcu_obj *fjp) 870 { 871 return (ENOSYS); 872 } 873 874 int 875 fdc_abort(struct fcu_obj *fjp) 876 { 877 struct fdcntlr *fcp = fjp->fj_fdc; 878 int unit = fjp->fj_unit & 3; 879 880 FCERRPRINT(FDEP_L3, FDEM_RESE, (CE_WARN, "fdc_abort")); 881 if (fcp->c_curunit == unit) { 882 mutex_enter(&fcp->c_lock); 883 if (fcp->c_flags & FCFLG_WAITING) { 884 /* 885 * this can cause data corruption ! 886 */ 887 fdcquiesce(fcp); 888 fcp->c_csb.csb_xstate = FXS_RESET; 889 fcp->c_flags |= FCFLG_TIMEOUT; 890 if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != 891 DDI_SUCCESS) 892 cmn_err(CE_WARN, 893 "fdc_detach: dma release failed, " 894 "dip %p, dmachan %x\n", 895 (void*)fcp->c_dip, fcp->c_dmachan); 896 } 897 mutex_exit(&fcp->c_lock); 898 drv_usecwait(500); 899 return (DDI_SUCCESS); 900 } 901 return (DDI_FAILURE); 902 } 903 904 /* ARGSUSED */ 905 int 906 fdc_getcap(struct fcu_obj *fjp, char *a, int i) 907 { 908 return (ENOSYS); 909 } 910 911 /* ARGSUSED */ 912 int 913 fdc_setcap(struct fcu_obj *fjp, char *a, int i, int j) 914 { 915 return (ENOSYS); 916 } 917 918 int 919 fdc_dkinfo(struct fcu_obj *fjp, struct dk_cinfo *dcp) 920 { 921 struct fdcntlr *fcp = fjp->fj_fdc; 922 923 (void) strncpy((char *)&dcp->dki_cname, ddi_get_name(fcp->c_dip), 924 DK_DEVLEN); 925 dcp->dki_ctype = DKC_UNKNOWN; /* no code for generic PC/AT fdc */ 926 dcp->dki_flags = DKI_FMTTRK; 927 dcp->dki_addr = fcp->c_regbase; 928 dcp->dki_space = 0; 929 dcp->dki_prio = fcp->c_intprio; 930 dcp->dki_vec = fcp->c_intvec; 931 (void) strncpy((char *)&dcp->dki_dname, ddi_driver_name(fjp->fj_dip), 932 DK_DEVLEN); 933 dcp->dki_slave = fjp->fj_unit & 3; 934 dcp->dki_maxtransfer = maxphys / DEV_BSIZE; 935 return (DDI_SUCCESS); 936 } 937 938 /* 939 * on=> non-zero = select, 0 = de-select 940 */ 941 /* ARGSUSED */ 942 int 943 fdc_select(struct fcu_obj *fjp, int funit, int on) 944 { 945 struct fdcntlr *fcp = fjp->fj_fdc; 946 int unit = funit & 3; 947 948 if (on) { 949 /* possess controller */ 950 sema_p(&fcp->c_selsem); 951 FCERRPRINT(FDEP_L2, FDEM_DSEL, 952 (CE_NOTE, "fdc_select unit %d: on", funit)); 953 954 if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) { 955 fcp->c_curunit = unit; 956 fjp->fj_flags |= FUNIT_CHAROK; 957 if (fdcspecify(fcp, 958 fjp->fj_chars->fdc_transfer_rate, 959 fjp->fj_drive->fdd_steprate, 40)) 960 cmn_err(CE_WARN, 961 "fdc_select: controller setup rejected " 962 "fdcntrl %p transfer rate %x step rate %x" 963 " head load time 40\n", (void*)fcp, 964 fjp->fj_chars->fdc_transfer_rate, 965 fjp->fj_drive->fdd_steprate); 966 } 967 968 mutex_enter(&fcp->c_dorlock); 969 970 /* make sure drive is not selected in case we change speed */ 971 fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | 972 (~unit & FD_DRSEL); 973 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 974 975 (void) fdc_motorsm(fjp, FMI_STARTCMD, 976 fjp->fj_drive->fdd_motoron); 977 /* 978 * Return value ignored - fdcmotort deals with failure. 979 */ 980 if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) { 981 /* 3D drive requires 500 ms for speed change */ 982 (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5); 983 /* 984 * Return value ignored - fdcmotort deals with failure. 985 */ 986 } 987 988 fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | (unit & FD_DRSEL); 989 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 990 991 mutex_exit(&fcp->c_dorlock); 992 fcp->c_csb.csb_drive = (uchar_t)unit; 993 } else { 994 FCERRPRINT(FDEP_L2, FDEM_DSEL, 995 (CE_NOTE, "fdc_select unit %d: off", funit)); 996 997 mutex_enter(&fcp->c_dorlock); 998 999 fcp->c_digout |= FD_DRSEL; 1000 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1001 (void) fdc_motorsm(fjp, FMI_IDLECMD, 1002 fjp->fj_drive->fdd_motoroff); 1003 /* 1004 * Return value ignored - fdcmotort deals with failure. 1005 */ 1006 1007 mutex_exit(&fcp->c_dorlock); 1008 1009 /* give up controller */ 1010 sema_v(&fcp->c_selsem); 1011 } 1012 return (0); 1013 } 1014 1015 1016 int 1017 fdgetchng(struct fcu_obj *fjp, int funit) 1018 { 1019 if (fdcsense_drv(fjp->fj_fdc, funit & 3)) 1020 cmn_err(CE_WARN, "fdgetchng: write protect check failed\n"); 1021 return (fdcsense_chng(fjp->fj_fdc, funit & 3)); 1022 } 1023 1024 1025 int 1026 fdresetchng(struct fcu_obj *fjp, int funit) 1027 { 1028 struct fdcntlr *fcp = fjp->fj_fdc; 1029 int unit = funit & 3; 1030 int newcyl; /* where to seek for reset of DSKCHG */ 1031 1032 FCERRPRINT(FDEP_L2, FDEM_CHEK, (CE_NOTE, "fdmediachng unit %d", funit)); 1033 1034 if (fcp->c_curpcyl[unit]) 1035 newcyl = fcp->c_curpcyl[unit] - 1; 1036 else 1037 newcyl = 1; 1038 return (fdrecalseek(fjp, funit, newcyl, 0)); 1039 } 1040 1041 1042 /* 1043 * fdrecalseek 1044 */ 1045 int 1046 fdrecalseek(struct fcu_obj *fjp, int funit, int arg, int execflg) 1047 { 1048 struct fdcntlr *fcp = fjp->fj_fdc; 1049 struct fdcsb *csb; 1050 int unit = funit & 3; 1051 int rval; 1052 1053 FCERRPRINT(FDEP_L2, FDEM_RECA, (CE_NOTE, "fdrecalseek unit %d to %d", 1054 funit, arg)); 1055 1056 csb = &fcp->c_csb; 1057 csb->csb_cmd[1] = (uchar_t)unit; 1058 if (arg < 0) { /* is recal... */ 1059 *csb->csb_cmd = FO_RECAL; 1060 csb->csb_ncmds = 2; 1061 csb->csb_timer = 28; 1062 } else { 1063 *csb->csb_cmd = FO_SEEK; 1064 csb->csb_cmd[2] = (uchar_t)arg; 1065 csb->csb_ncmds = 3; 1066 csb->csb_timer = 10; 1067 } 1068 csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */ 1069 csb->csb_opflags = CSB_OFINRPT; 1070 csb->csb_maxretry = skretry; 1071 csb->csb_dmahandle = NULL; 1072 csb->csb_handle_bound = 0; 1073 csb->csb_dmacookiecnt = 0; 1074 csb->csb_dmacurrcookie = 0; 1075 csb->csb_dmawincnt = 0; 1076 csb->csb_dmacurrwin = 0; 1077 1078 /* send cmd off to fdc_exec */ 1079 if (rval = fdc_exec(fcp, 1, execflg)) 1080 goto out; 1081 1082 if (!(*csb->csb_rslt & S0_SEKEND) || 1083 (*csb->csb_rslt & S0_ICMASK) || 1084 ((*csb->csb_rslt & S0_ECHK) && arg < 0) || 1085 csb->csb_cmdstat) 1086 rval = ENODEV; 1087 1088 if (fdcsense_drv(fcp, unit)) 1089 cmn_err(CE_WARN, "fdgetchng: write protect check failed\n"); 1090 out: 1091 return (rval); 1092 } 1093 1094 1095 int 1096 fdrwbuf(struct fcu_obj *fjp, int funit, int rw, int cyl, int head, 1097 int sector, struct buf *bp) 1098 { 1099 struct fdcntlr *fcp = fjp->fj_fdc; 1100 struct fdcsb *csb; 1101 ddi_dma_attr_t dmaattr; 1102 uint_t dmar_flags = 0; 1103 int unit = funit & 3; 1104 int rval; 1105 1106 FCERRPRINT(FDEP_L2, FDEM_RW, (CE_NOTE, "fdrwbuf unit %d", funit)); 1107 1108 csb = &fcp->c_csb; 1109 if (rw) { 1110 dmar_flags = DDI_DMA_READ; 1111 csb->csb_opflags = CSB_OFDMARD | CSB_OFINRPT; 1112 *csb->csb_cmd = FO_MT | FO_MFM | FO_SK | FO_RDDAT; 1113 } else { /* write */ 1114 dmar_flags = DDI_DMA_WRITE; 1115 csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT; 1116 *csb->csb_cmd = FO_MT | FO_MFM | FO_WRDAT; 1117 } 1118 csb->csb_cmd[1] = (uchar_t)(unit | ((head & 0x1) << 2)); 1119 csb->csb_cmd[2] = (uchar_t)cyl; 1120 csb->csb_cmd[3] = (uchar_t)head; 1121 csb->csb_cmd[4] = (uchar_t)sector; 1122 encode(sector_size, fjp->fj_chars->fdc_sec_size, 1123 &csb->csb_cmd[5]); 1124 csb->csb_cmd[6] = fjp->fj_chars->fdc_secptrack; 1125 csb->csb_cmd[7] = fjp->fj_attr->fda_gapl; 1126 csb->csb_cmd[8] = 0xFF; 1127 1128 csb->csb_ncmds = 9; 1129 csb->csb_nrslts = 7; 1130 csb->csb_timer = 36; 1131 if (rw == FDRDONE) 1132 csb->csb_maxretry = 1; 1133 else 1134 csb->csb_maxretry = rwretry; 1135 1136 csb->csb_dmahandle = NULL; 1137 csb->csb_handle_bound = 0; 1138 csb->csb_dmacookiecnt = 0; 1139 csb->csb_dmacurrcookie = 0; 1140 csb->csb_dmawincnt = 0; 1141 csb->csb_dmacurrwin = 0; 1142 dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL); 1143 1144 dmaattr = fdc_dma_attr; 1145 dmaattr.dma_attr_granular = fjp->fj_chars->fdc_sec_size; 1146 if (ddi_dma_alloc_handle(fcp->c_dip, &dmaattr, DDI_DMA_SLEEP, 1147 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 1148 rval = EINVAL; 1149 goto out; 1150 } 1151 1152 rval = ddi_dma_buf_bind_handle(csb->csb_dmahandle, bp, dmar_flags, 1153 DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, &csb->csb_dmacookiecnt); 1154 1155 if (rval == DDI_DMA_MAPPED) { 1156 csb->csb_dmawincnt = 1; 1157 csb->csb_handle_bound = 1; 1158 } else if (rval == DDI_DMA_PARTIAL_MAP) { 1159 csb->csb_handle_bound = 1; 1160 if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != 1161 DDI_SUCCESS) { 1162 cmn_err(CE_WARN, "fdrwbuf: dma numwin failed\n"); 1163 rval = EINVAL; 1164 goto out; 1165 } 1166 } else { 1167 cmn_err(CE_WARN, 1168 "fdrwbuf: dma buf bind handle failed, rval = %d\n", 1169 rval); 1170 rval = EINVAL; 1171 goto out; 1172 } 1173 rval = fdc_exec(fcp, 1, 1); 1174 1175 out: 1176 if (csb->csb_dmahandle) { 1177 if (csb->csb_handle_bound) { 1178 if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 1179 DDI_SUCCESS) 1180 cmn_err(CE_WARN, "fdrwbuf: " 1181 "dma unbind handle failed\n"); 1182 csb->csb_handle_bound = 0; 1183 } 1184 ddi_dma_free_handle(&csb->csb_dmahandle); 1185 csb->csb_dmahandle = NULL; 1186 } 1187 return (rval); 1188 } 1189 1190 1191 /* 1192 * fdrw- used only for read/writing sectors into/from kernel buffers. 1193 */ 1194 int 1195 fdrw(struct fcu_obj *fjp, int funit, int rw, int cyl, int head, 1196 int sector, caddr_t bufp, uint_t len) 1197 { 1198 struct fdcntlr *fcp = fjp->fj_fdc; 1199 struct fdcsb *csb; 1200 ddi_dma_attr_t dmaattr; 1201 uint_t dmar_flags = 0; 1202 int unit = funit & 3; 1203 int rval; 1204 1205 FCERRPRINT(FDEP_L1, FDEM_RW, (CE_CONT, "fdrw unit %d\n", funit)); 1206 1207 csb = &fcp->c_csb; 1208 if (rw) { 1209 dmar_flags = DDI_DMA_READ; 1210 csb->csb_opflags = CSB_OFDMARD | CSB_OFINRPT; 1211 *csb->csb_cmd = FO_MT | FO_MFM | FO_SK | FO_RDDAT; 1212 } else { /* write */ 1213 dmar_flags = DDI_DMA_WRITE; 1214 csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT; 1215 *csb->csb_cmd = FO_MT | FO_MFM | FO_WRDAT; 1216 } 1217 csb->csb_cmd[1] = (uchar_t)(unit | ((head & 0x1) << 2)); 1218 csb->csb_cmd[2] = (uchar_t)cyl; 1219 csb->csb_cmd[3] = (uchar_t)head; 1220 csb->csb_cmd[4] = (uchar_t)sector; 1221 encode(sector_size, fjp->fj_chars->fdc_sec_size, 1222 &csb->csb_cmd[5]); 1223 csb->csb_cmd[6] = (uchar_t)max(fjp->fj_chars->fdc_secptrack, sector); 1224 csb->csb_cmd[7] = fjp->fj_attr->fda_gapl; 1225 csb->csb_cmd[8] = 0xFF; 1226 1227 csb->csb_ncmds = 9; 1228 csb->csb_nrslts = 7; 1229 csb->csb_timer = 36; 1230 if (rw == FDRDONE) 1231 csb->csb_maxretry = 1; 1232 else 1233 csb->csb_maxretry = rwretry; 1234 1235 csb->csb_dmahandle = NULL; 1236 csb->csb_handle_bound = 0; 1237 csb->csb_dmacookiecnt = 0; 1238 csb->csb_dmacurrcookie = 0; 1239 csb->csb_dmawincnt = 0; 1240 csb->csb_dmacurrwin = 0; 1241 dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL); 1242 1243 dmaattr = fdc_dma_attr; 1244 dmaattr.dma_attr_granular = fjp->fj_chars->fdc_sec_size; 1245 if (ddi_dma_alloc_handle(fcp->c_dip, &dmaattr, DDI_DMA_SLEEP, 1246 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 1247 rval = EINVAL; 1248 goto out; 1249 } 1250 1251 rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, bufp, len, 1252 dmar_flags, DDI_DMA_SLEEP, 0, 1253 &csb->csb_dmacookie, &csb->csb_dmacookiecnt); 1254 1255 if (rval == DDI_DMA_MAPPED) { 1256 csb->csb_dmawincnt = 1; 1257 csb->csb_handle_bound = 1; 1258 } else if (rval == DDI_DMA_PARTIAL_MAP) { 1259 csb->csb_handle_bound = 1; 1260 if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != 1261 DDI_SUCCESS) { 1262 cmn_err(CE_WARN, "fdrw: dma numwin failed\n"); 1263 rval = EINVAL; 1264 goto out; 1265 } 1266 } else { 1267 cmn_err(CE_WARN, 1268 "fdrw: dma addr bind handle failed, rval = %d\n", 1269 rval); 1270 rval = EINVAL; 1271 goto out; 1272 } 1273 rval = fdc_exec(fcp, 1, 1); 1274 1275 out: 1276 if (csb->csb_dmahandle) { 1277 if (csb->csb_handle_bound) { 1278 if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 1279 DDI_SUCCESS) 1280 cmn_err(CE_WARN, "fdrw: " 1281 "dma unbind handle failed\n"); 1282 csb->csb_handle_bound = 0; 1283 } 1284 ddi_dma_free_handle(&csb->csb_dmahandle); 1285 csb->csb_dmahandle = NULL; 1286 } 1287 return (rval); 1288 } 1289 1290 1291 int 1292 fdtrkformat(struct fcu_obj *fjp, int funit, int cyl, int head, int filldata) 1293 { 1294 struct fdcntlr *fcp = fjp->fj_fdc; 1295 struct fdcsb *csb; 1296 ddi_dma_attr_t dmaattr; 1297 int unit = funit & 3; 1298 int fmdatlen, lsector, lstart; 1299 int interleave, numsctr, offset, psector; 1300 uchar_t *dp; 1301 uchar_t *fmdatp; 1302 int rval; 1303 1304 FCERRPRINT(FDEP_L2, FDEM_FORM, 1305 (CE_NOTE, "fdformattrk unit %d cyl=%d, hd=%d", funit, cyl, head)); 1306 1307 csb = &fcp->c_csb; 1308 1309 csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT; 1310 1311 *csb->csb_cmd = FO_FRMT | FO_MFM; 1312 csb->csb_cmd[1] = (head << 2) | unit; 1313 encode(sector_size, fjp->fj_chars->fdc_sec_size, 1314 &csb->csb_cmd[2]); 1315 csb->csb_cmd[3] = numsctr = fjp->fj_chars->fdc_secptrack; 1316 csb->csb_cmd[4] = fjp->fj_attr->fda_gapf; 1317 csb->csb_cmd[5] = (uchar_t)filldata; 1318 1319 csb->csb_npcyl = (uchar_t)(cyl * fjp->fj_chars->fdc_steps); 1320 1321 csb->csb_dmahandle = NULL; 1322 csb->csb_handle_bound = 0; 1323 csb->csb_dmacookiecnt = 0; 1324 csb->csb_dmacurrcookie = 0; 1325 csb->csb_dmawincnt = 0; 1326 csb->csb_dmacurrwin = 0; 1327 csb->csb_ncmds = 6; 1328 csb->csb_nrslts = 7; 1329 csb->csb_timer = 32; 1330 csb->csb_maxretry = rwretry; 1331 1332 /* 1333 * just kmem_alloc space for format track cmd 1334 */ 1335 /* 1336 * NOTE: have to add size of fifo also - for dummy format action 1337 */ 1338 fmdatlen = 4 * numsctr; 1339 dp = fmdatp = kmem_alloc(fmdatlen, KM_SLEEP); 1340 1341 interleave = fjp->fj_attr->fda_intrlv; 1342 offset = (numsctr + interleave - 1) / interleave; 1343 for (psector = lstart = 1; 1344 psector <= numsctr; psector += interleave, lstart++) { 1345 for (lsector = lstart; lsector <= numsctr; lsector += offset) { 1346 *dp++ = (uchar_t)cyl; 1347 *dp++ = (uchar_t)head; 1348 *dp++ = (uchar_t)lsector; 1349 *dp++ = csb->csb_cmd[2]; 1350 } 1351 } 1352 1353 dmaattr = fdc_dma_attr; 1354 for (; dmaattr.dma_attr_granular < fmdatlen; 1355 dmaattr.dma_attr_granular <<= 1); 1356 1357 if (ddi_dma_alloc_handle(fcp->c_dip, &dmaattr, DDI_DMA_SLEEP, 1358 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 1359 rval = EINVAL; 1360 goto out; 1361 } 1362 1363 rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, 1364 (caddr_t)fmdatp, fmdatlen, 1365 DDI_DMA_WRITE | DDI_DMA_STREAMING | DDI_DMA_PARTIAL, 1366 DDI_DMA_SLEEP, 0, 1367 &csb->csb_dmacookie, &csb->csb_dmacookiecnt); 1368 1369 if (rval == DDI_DMA_MAPPED) { 1370 csb->csb_dmawincnt = 1; 1371 csb->csb_handle_bound = 1; 1372 } else if (rval == DDI_DMA_PARTIAL_MAP) { 1373 csb->csb_handle_bound = 1; 1374 if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != 1375 DDI_SUCCESS) { 1376 cmn_err(CE_WARN, "fdtrkformat: dma numwin failed\n"); 1377 rval = EINVAL; 1378 goto out; 1379 } 1380 } else { 1381 cmn_err(CE_WARN, 1382 "fdtrkformat: dma buf bind handle failed, rval = %d\n", 1383 rval); 1384 rval = EINVAL; 1385 goto out; 1386 } 1387 1388 rval = fdc_exec(fcp, 1, 1); 1389 out: 1390 if (csb->csb_dmahandle) { 1391 if (csb->csb_handle_bound) { 1392 if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 1393 DDI_SUCCESS) 1394 cmn_err(CE_WARN, "fdtrkformat: " 1395 "dma unbind handle failed\n"); 1396 csb->csb_handle_bound = 0; 1397 } 1398 ddi_dma_free_handle(&csb->csb_dmahandle); 1399 csb->csb_dmahandle = NULL; 1400 } 1401 kmem_free(fmdatp, fmdatlen); 1402 return (rval); 1403 } 1404 1405 /* ARGSUSED */ 1406 int 1407 fdrawioctl(struct fcu_obj *fjp, int funit, caddr_t arg) 1408 { 1409 struct fdcntlr *fcp = fjp->fj_fdc; 1410 struct fd_raw *fdrp = (struct fd_raw *)arg; 1411 struct fdcsb *csb; 1412 ddi_dma_attr_t dmaattr; 1413 uint_t dmar_flags = 0; 1414 int i; 1415 int change = 1; 1416 int sleep = 1; 1417 int rval = 0; 1418 int rval_exec = 0; 1419 1420 FCERRPRINT(FDEP_L2, FDEM_RAWI, 1421 (CE_NOTE, "fdrawioctl: cmd[0]=0x%x", fdrp->fdr_cmd[0])); 1422 1423 csb = &fcp->c_csb; 1424 1425 /* copy cmd bytes into csb */ 1426 for (i = 0; i <= fdrp->fdr_cnum; i++) 1427 csb->csb_cmd[i] = fdrp->fdr_cmd[i]; 1428 csb->csb_ncmds = (uchar_t)fdrp->fdr_cnum; 1429 1430 csb->csb_maxretry = 0; /* let the application deal with errors */ 1431 csb->csb_opflags = CSB_OFRAWIOCTL; 1432 csb->csb_nrslts = 0; 1433 csb->csb_timer = 50; 1434 1435 switch (fdrp->fdr_cmd[0] & 0x0f) { 1436 1437 case FO_SEEK: 1438 change = 0; 1439 /* FALLTHROUGH */ 1440 case FO_RECAL: 1441 csb->csb_opflags |= CSB_OFINRPT; 1442 break; 1443 1444 case FO_FRMT: 1445 csb->csb_npcyl = *(uchar_t *)(fdrp->fdr_addr) * 1446 fjp->fj_chars->fdc_steps; 1447 /* FALLTHROUGH */ 1448 case FO_WRDAT: 1449 case FO_WRDEL: 1450 csb->csb_opflags |= CSB_OFDMAWT | CSB_OFRESLT | CSB_OFINRPT; 1451 csb->csb_nrslts = 7; 1452 if (fdrp->fdr_nbytes == 0) 1453 return (EINVAL); 1454 dmar_flags = DDI_DMA_WRITE; 1455 break; 1456 1457 case FO_RDDAT: 1458 case FO_RDDEL: 1459 case FO_RDTRK: 1460 csb->csb_opflags |= CSB_OFDMARD | CSB_OFRESLT | CSB_OFINRPT; 1461 csb->csb_nrslts = 7; 1462 dmar_flags = DDI_DMA_READ; 1463 break; 1464 1465 case FO_RDID: 1466 csb->csb_opflags |= CSB_OFRESLT | CSB_OFINRPT; 1467 csb->csb_nrslts = 7; 1468 break; 1469 1470 case FO_SDRV: 1471 sleep = 0; 1472 csb->csb_nrslts = 1; 1473 break; 1474 1475 case FO_SINT: 1476 sleep = 0; 1477 change = 0; 1478 csb->csb_nrslts = 2; 1479 break; 1480 1481 case FO_SPEC: 1482 sleep = 0; 1483 change = 0; 1484 break; 1485 1486 default: 1487 return (EINVAL); 1488 } 1489 1490 csb->csb_dmahandle = NULL; 1491 csb->csb_handle_bound = 0; 1492 csb->csb_dmacookiecnt = 0; 1493 csb->csb_dmacurrcookie = 0; 1494 csb->csb_dmawincnt = 0; 1495 csb->csb_dmacurrwin = 0; 1496 1497 if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) { 1498 dmaattr = fdc_dma_attr; 1499 dmaattr.dma_attr_granular = fjp->fj_chars->fdc_sec_size; 1500 1501 if (ddi_dma_alloc_handle(fcp->c_dip, &dmaattr, DDI_DMA_SLEEP, 1502 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 1503 rval = EINVAL; 1504 goto out; 1505 } 1506 1507 dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL); 1508 rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, 1509 fdrp->fdr_addr, (uint_t)fdrp->fdr_nbytes, 1510 dmar_flags, DDI_DMA_SLEEP, 0, 1511 &csb->csb_dmacookie, &csb->csb_dmacookiecnt); 1512 1513 if (rval == DDI_DMA_MAPPED) { 1514 csb->csb_dmawincnt = 1; 1515 csb->csb_handle_bound = 1; 1516 } else if (rval == DDI_DMA_PARTIAL_MAP) { 1517 csb->csb_handle_bound = 1; 1518 if (ddi_dma_numwin(csb->csb_dmahandle, 1519 &csb->csb_dmawincnt) != DDI_SUCCESS) { 1520 cmn_err(CE_WARN, 1521 "fdrawioctl: dma numwin failed\n"); 1522 rval = EINVAL; 1523 goto out; 1524 } 1525 } else { 1526 cmn_err(CE_WARN, "fdrawioctl: " 1527 "dma buf bind handle failed, rval = %d\n", rval); 1528 rval = EINVAL; 1529 goto out; 1530 } 1531 } 1532 1533 FCERRPRINT(FDEP_L1, FDEM_RAWI, 1534 (CE_CONT, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmd[0], 1535 csb->csb_cmd[1], csb->csb_cmd[2], csb->csb_cmd[3], 1536 csb->csb_cmd[4], csb->csb_cmd[5], csb->csb_cmd[6], 1537 csb->csb_cmd[7], csb->csb_cmd[8], csb->csb_cmd[9])); 1538 FCERRPRINT(FDEP_L1, FDEM_RAWI, 1539 (CE_CONT, "nbytes: %x, opflags: %x, addr: %p, len: %x\n", 1540 csb->csb_ncmds, csb->csb_opflags, (void *)fdrp->fdr_addr, 1541 fdrp->fdr_nbytes)); 1542 1543 /* 1544 * Note that we ignore any error returns from fdexec. 1545 * This is the way the driver has been, and it may be 1546 * that the raw ioctl senders simply don't want to 1547 * see any errors returned in this fashion. 1548 */ 1549 1550 /* 1551 * VP/ix sense drive ioctl call checks for the error return. 1552 */ 1553 1554 rval_exec = fdc_exec(fcp, sleep, change); 1555 1556 FCERRPRINT(FDEP_L1, FDEM_RAWI, 1557 (CE_CONT, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0], 1558 csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3], 1559 csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6], 1560 csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9])); 1561 1562 /* copy results into fdr */ 1563 for (i = 0; i <= (int)csb->csb_nrslts; i++) 1564 fdrp->fdr_result[i] = csb->csb_rslt[i]; 1565 /* fdrp->fdr_nbytes = fdc->c_csb.csb_rlen; return resid */ 1566 1567 out: 1568 if (csb->csb_dmahandle) { 1569 if (csb->csb_handle_bound) { 1570 if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 1571 DDI_SUCCESS) 1572 cmn_err(CE_WARN, "fdrawioctl: " 1573 "dma unbind handle failed\n"); 1574 csb->csb_handle_bound = 0; 1575 } 1576 ddi_dma_free_handle(&csb->csb_dmahandle); 1577 csb->csb_dmahandle = NULL; 1578 } 1579 if ((fdrp->fdr_cmd[0] & 0x0f) == FO_SDRV) { 1580 return (rval_exec); 1581 } 1582 return (rval); 1583 } 1584 1585 void 1586 encode(xlate_tbl_t *tablep, int val, uchar_t *rcode) 1587 { 1588 do { 1589 if (tablep->value >= val) { 1590 *rcode = tablep->code; 1591 return; 1592 } 1593 } while ((++tablep)->value); 1594 *rcode = tablep->code; 1595 cmn_err(CE_WARN, "fdc encode failed, table %p val %x code %x\n", 1596 (void *)tablep, val, (uint_t)*rcode); 1597 } 1598 1599 int 1600 decode(xlate_tbl_t *tablep, int kode, int *rvalue) 1601 { 1602 do { 1603 if (tablep->code == kode) { 1604 *rvalue = tablep->value; 1605 return (0); 1606 } 1607 } while ((++tablep)->value); 1608 return (-1); 1609 } 1610 1611 1612 void 1613 fdcquiesce(struct fdcntlr *fcp) 1614 { 1615 int unit; 1616 1617 FCERRPRINT(FDEP_L2, FDEM_RESE, (CE_NOTE, "fdcquiesce fcp %p", 1618 (void*)fcp)); 1619 ASSERT(MUTEX_HELD(&fcp->c_lock)); 1620 1621 mutex_enter(&fcp->c_dorlock); 1622 1623 if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS) 1624 cmn_err(CE_WARN, "fdcquiesce: dmae stop failed, " 1625 "dip %p, dmachan %x\n", 1626 (void*)fcp->c_dip, fcp->c_dmachan); 1627 1628 fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE; 1629 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1630 drv_usecwait(20); 1631 fcp->c_digout |= FD_RSETZ; 1632 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1633 1634 mutex_exit(&fcp->c_dorlock); 1635 1636 /* count resets */ 1637 fcp->fdstats.reset++; 1638 fcp->c_curunit = -1; 1639 for (unit = 0; unit < NFDUN; unit++) 1640 fcp->c_curpcyl[unit] = -1; 1641 1642 if (fcp->c_chip >= i82077) { 1643 (void) fdc_docmd(fcp, configurecmd, 4); 1644 /* 1645 * Ignored return. If failed, warning was issued by fdc_docmd. 1646 */ 1647 } 1648 } 1649 1650 void 1651 fdcreadid(struct fdcntlr *fcp, struct fdcsb *csb) 1652 { 1653 static uchar_t readidcmd[2] = {FO_RDID | FO_MFM, 0}; 1654 1655 readidcmd[1] = csb->csb_cmd[1]; 1656 (void) fdc_docmd(fcp, readidcmd, 2); 1657 } 1658 1659 int 1660 fdcseek(struct fdcntlr *fcp, int unit, int cyl) 1661 { 1662 static uchar_t seekabscmd[3] = {FO_SEEK, 0, 0}; 1663 1664 FCERRPRINT(FDEP_L0, FDEM_RECA, (CE_CONT, "fdcseek unit %d to cyl %d\n", 1665 unit, cyl)); 1666 seekabscmd[1] = (uchar_t)unit; 1667 seekabscmd[2] = (uchar_t)cyl; 1668 return (fdc_docmd(fcp, seekabscmd, 3)); 1669 } 1670 1671 /* 1672 * Returns status of disk change line of selected drive. 1673 * = 0 means diskette is present 1674 * != 0 means diskette was removed and current state is unknown 1675 */ 1676 int 1677 fdcsense_chng(struct fdcntlr *fcp, int unit) 1678 { 1679 int digital_input; 1680 1681 FCERRPRINT(FDEP_L0, FDEM_SCHG, 1682 (CE_CONT, "fdcsense_chng unit %d\n", unit)); 1683 digital_input = inb(fcp->c_regbase + FCR_DIR); 1684 if (fcp->c_mode == FDCMODE_30) 1685 digital_input ^= FDI_DKCHG; 1686 return (digital_input & FDI_DKCHG); 1687 } 1688 1689 int 1690 fdcsense_drv(struct fdcntlr *fcp, int unit) 1691 { 1692 static uchar_t sensedrvcmd[2] = {FO_SDRV, 0}; 1693 uchar_t senser; 1694 int rval; 1695 1696 sensedrvcmd[1] = (uchar_t)unit; 1697 (void) fdc_docmd(fcp, sensedrvcmd, 2); 1698 /* 1699 * Ignored return. If failed, warning was issued by fdc_docmd. 1700 * fdc_results retrieves the controller/drive status 1701 */ 1702 if (rval = fdc_result(fcp, &senser, 1)) 1703 goto done; 1704 if (senser & S3_WPROT) 1705 fcp->c_unit[unit]->fj_flags |= FUNIT_WPROT; 1706 else 1707 fcp->c_unit[unit]->fj_flags &= ~FUNIT_WPROT; 1708 done: 1709 return (rval); 1710 } 1711 1712 int 1713 fdcsense_int(struct fdcntlr *fcp, int *unitp, int *cylp) 1714 { 1715 uchar_t senser[2]; 1716 int rval; 1717 1718 (void) fdc_docmd(fcp, &senseintcmd, 1); 1719 /* 1720 * Ignored return. If failed, warning was issued by fdc_docmd. 1721 * fdc_results retrieves the controller/drive status 1722 */ 1723 1724 if (!(rval = fdc_result(fcp, senser, 2))) { 1725 if ((*senser & (S0_IVCMD | S0_SEKEND | S0_ECHK)) != S0_SEKEND) 1726 rval = 1; 1727 if (unitp) 1728 *unitp = *senser & 3; 1729 if (cylp) 1730 *cylp = senser[1]; 1731 } 1732 return (rval); 1733 } 1734 1735 int 1736 fdcspecify(struct fdcntlr *fcp, int xferrate, int steprate, int hlt) 1737 { 1738 static uchar_t perpindcmd[2] = {FO_PERP, 0}; 1739 static uchar_t specifycmd[3] = {FO_SPEC, 0, 0}; 1740 1741 encode(drate_mfm, xferrate, &fcp->c_config); 1742 outb(fcp->c_regbase + FCR_CCR, fcp->c_config); 1743 1744 if (fcp->c_chip >= i82077) { 1745 /* 1746 * Use old style perpendicular mode command of 82077. 1747 */ 1748 if (xferrate == 1000) { 1749 /* Set GAP and WGATE */ 1750 perpindcmd[1] = 3; 1751 /* double step rate because xlate table is for 500Kb */ 1752 steprate <<= 1; 1753 hlt <<= 1; 1754 } else 1755 perpindcmd[1] = 0; 1756 (void) fdc_docmd(fcp, perpindcmd, 2); 1757 /* 1758 * Ignored return. If failed, warning was issued by fdc_docmd. 1759 */ 1760 } 1761 encode(step_rate, steprate, &fcp->c_hutsrt); 1762 specifycmd[1] = fcp->c_hutsrt |= 0x0F; /* use max head unload time */ 1763 hlt = (hlt >= 256) ? 0 : (hlt >> 1); /* encode head load time */ 1764 specifycmd[2] = fcp->c_hlt = hlt << 1; /* make room for DMA bit */ 1765 return (fdc_docmd(fcp, specifycmd, 3)); 1766 } 1767 1768 int 1769 fdcspdchange(struct fdcntlr *fcp, struct fcu_obj *fjp, int rpm) 1770 { 1771 int retcode = 0; 1772 uint_t ddic; 1773 uchar_t deselect = 0; 1774 uchar_t ds_code; 1775 uchar_t enable_code; 1776 uchar_t save; 1777 1778 if (((fcp->c_flags & FCFLG_DSOUT) == 0 && rpm <= fjp->fj_rotspd) || 1779 ((fcp->c_flags & FCFLG_DSOUT) && (fjp->fj_flags & FUNIT_3DMODE) && 1780 rpm > fjp->fj_rotspd)) { 1781 return (0); 1782 } 1783 1784 FCERRPRINT(FDEP_L1, FDEM_SCHG, 1785 (CE_CONT, "fdcspdchange: %d rpm\n", rpm)); 1786 ASSERT(MUTEX_HELD(&fcp->c_dorlock)); 1787 1788 switch (fcp->c_chip) { 1789 default: 1790 break; 1791 case i82077: 1792 break; 1793 1794 case PC87322: 1795 { 1796 uchar_t nscmodecmd[5] = {FO_MODE, 0x02, 0x00, 0xC8, 0x00}; 1797 1798 if (rpm > fjp->fj_rotspd) { 1799 nscmodecmd[3] ^= 0xC0; 1800 retcode = (fcp->c_flags ^ FCFLG_DSOUT) || 1801 (fjp->fj_flags ^ FUNIT_3DMODE); 1802 fcp->c_flags |= FCFLG_DSOUT; 1803 fjp->fj_flags |= FUNIT_3DMODE; 1804 } else { 1805 /* program DENSEL to default output */ 1806 fcp->c_flags &= ~FCFLG_DSOUT; 1807 retcode = fjp->fj_flags & FUNIT_3DMODE; 1808 fjp->fj_flags &= ~FUNIT_3DMODE; 1809 } 1810 if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) { 1811 /* de-select drive while changing speed */ 1812 deselect = fcp->c_digout ^ FD_DRSEL; 1813 outb(fcp->c_regbase + FCR_DOR, deselect); 1814 } 1815 1816 (void) fdc_docmd(fcp, nscmodecmd, 5); 1817 /* 1818 * Ignored return. If failed, warning was issued by fdc_docmd. 1819 */ 1820 break; 1821 } 1822 1823 case FDC37C665: 1824 enable_code = FSA_ENA5; 1825 goto SMC_config; 1826 1827 case FDC37C666: 1828 enable_code = FSA_ENA6; 1829 SMC_config: 1830 if (rpm > fjp->fj_rotspd) { 1831 /* force DENSEL output to active LOW */ 1832 ds_code = FSB_DSHI; 1833 retcode = (fcp->c_flags ^ FCFLG_DSOUT) || 1834 (fjp->fj_flags ^ FUNIT_3DMODE); 1835 fcp->c_flags |= FCFLG_DSOUT; 1836 fjp->fj_flags |= FUNIT_3DMODE; 1837 } else { 1838 /* program DENSEL to default output */ 1839 ds_code = 0; 1840 fcp->c_flags &= ~FCFLG_DSOUT; 1841 retcode = fjp->fj_flags & FUNIT_3DMODE; 1842 fjp->fj_flags &= ~FUNIT_3DMODE; 1843 } 1844 if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) { 1845 /* de-select drive while changing speed */ 1846 deselect = fcp->c_digout ^ FD_DRSEL; 1847 outb(fcp->c_regbase + FCR_DOR, deselect); 1848 } 1849 save = inb(fcp->c_regbase + FCR_SRA); 1850 1851 /* enter configuration mode */ 1852 ddic = ddi_enter_critical(); 1853 outb(fcp->c_regbase + FCR_SRA, enable_code); 1854 outb(fcp->c_regbase + FCR_SRA, enable_code); 1855 ddi_exit_critical(ddic); 1856 1857 outb(fcp->c_regbase + FCR_SRA, FSA_CR5); 1858 enable_code = inb(fcp->c_regbase + FCR_SRB) & FSB_DSDEF; 1859 /* update DENSEL mode bits */ 1860 outb(fcp->c_regbase + FCR_SRB, enable_code | ds_code); 1861 1862 /* exit configuration mode */ 1863 outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 1864 drv_usecwait(10); 1865 outb(fcp->c_regbase + FCR_SRA, save); 1866 break; 1867 } 1868 if (deselect) 1869 /* reselect drive */ 1870 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1871 return (retcode); 1872 } 1873 1874 static int 1875 fdc_motorsm(struct fcu_obj *fjp, int input, int timeval) 1876 { 1877 struct fdcntlr *fcp = fjp->fj_fdc; 1878 int unit = fjp->fj_unit & 3; 1879 int old_mstate; 1880 int rval = 0; 1881 uchar_t motorbit; 1882 1883 ASSERT(MUTEX_HELD(&fcp->c_dorlock)); 1884 old_mstate = fcp->c_mtrstate[unit]; 1885 encode(motor_onbits, unit, &motorbit); 1886 1887 switch (input) { 1888 case FMI_TIMER: /* timer expired */ 1889 fcp->c_motort[unit] = 0; 1890 switch (old_mstate) { 1891 case FMS_START: 1892 case FMS_DELAY: 1893 fcp->c_mtrstate[unit] = FMS_ON; 1894 break; 1895 case FMS_KILLST: 1896 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 1897 drv_usectohz(1000000)); 1898 fcp->c_mtrstate[unit] = FMS_IDLE; 1899 break; 1900 case FMS_IDLE: 1901 fcp->c_digout &= ~motorbit; 1902 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1903 fcp->c_mtrstate[unit] = FMS_OFF; 1904 fjp->fj_flags &= ~FUNIT_3DMODE; 1905 break; 1906 case 86: 1907 rval = -1; 1908 break; 1909 case FMS_OFF: 1910 case FMS_ON: 1911 default: 1912 rval = -2; 1913 } 1914 break; 1915 1916 case FMI_STARTCMD: /* start command */ 1917 switch (old_mstate) { 1918 case FMS_IDLE: 1919 fcp->c_mtrstate[unit] = 86; 1920 mutex_exit(&fcp->c_dorlock); 1921 (void) untimeout(fcp->c_motort[unit]); 1922 mutex_enter(&fcp->c_dorlock); 1923 fcp->c_motort[unit] = 0; 1924 fcp->c_mtrstate[unit] = FMS_ON; 1925 break; 1926 case FMS_OFF: 1927 fcp->c_digout |= motorbit; 1928 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1929 1930 /* start motor_spinup_timer */ 1931 ASSERT(timeval > 0); 1932 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 1933 drv_usectohz(100000 * timeval)); 1934 /* FALLTHROUGH */ 1935 case FMS_KILLST: 1936 fcp->c_mtrstate[unit] = FMS_START; 1937 break; 1938 default: 1939 rval = -2; 1940 } 1941 break; 1942 1943 case FMI_RSTARTCMD: /* restart command */ 1944 if (fcp->c_motort[unit] != 0) { 1945 fcp->c_mtrstate[unit] = 86; 1946 mutex_exit(&fcp->c_dorlock); 1947 (void) untimeout(fcp->c_motort[unit]); 1948 mutex_enter(&fcp->c_dorlock); 1949 } 1950 ASSERT(timeval > 0); 1951 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 1952 drv_usectohz(100000 * timeval)); 1953 fcp->c_mtrstate[unit] = FMS_START; 1954 break; 1955 1956 case FMI_DELAYCMD: /* delay command */ 1957 if (fcp->c_motort[unit] == 0) 1958 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 1959 drv_usectohz(15000)); 1960 fcp->c_mtrstate[unit] = FMS_DELAY; 1961 break; 1962 1963 case FMI_IDLECMD: /* idle command */ 1964 switch (old_mstate) { 1965 case FMS_DELAY: 1966 fcp->c_mtrstate[unit] = 86; 1967 mutex_exit(&fcp->c_dorlock); 1968 (void) untimeout(fcp->c_motort[unit]); 1969 mutex_enter(&fcp->c_dorlock); 1970 /* FALLTHROUGH */ 1971 case FMS_ON: 1972 ASSERT(timeval > 0); 1973 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 1974 drv_usectohz(100000 * timeval)); 1975 fcp->c_mtrstate[unit] = FMS_IDLE; 1976 break; 1977 case FMS_START: 1978 fcp->c_mtrstate[unit] = FMS_KILLST; 1979 break; 1980 default: 1981 rval = -2; 1982 } 1983 break; 1984 1985 default: 1986 rval = -3; 1987 } 1988 if (rval) { 1989 FCERRPRINT(FDEP_L4, FDEM_EXEC, (CE_WARN, 1990 "fdc_motorsm: unit %d bad input %d or bad state %d", 1991 (int)fjp->fj_unit, input, old_mstate)); 1992 #if 0 1993 cmn_err(CE_WARN, 1994 "fdc_motorsm: unit %d bad input %d or bad state %d\n", 1995 (int)fjp->fj_unit, input, old_mstate); 1996 fcp->c_mtrstate[unit] = FMS_OFF; 1997 if (fcp->c_motort[unit] != 0) { 1998 mutex_exit(&fcp->c_dorlock); 1999 (void) untimeout(fcp->c_motort[unit]); 2000 mutex_enter(&fcp->c_dorlock); 2001 fcp->c_motort[unit] = 0; 2002 } 2003 #endif 2004 } else 2005 FCERRPRINT(FDEP_L0, FDEM_EXEC, 2006 (CE_CONT, "fdc_motorsm unit %d: input %d, %d -> %d\n", 2007 (int)fjp->fj_unit, input, old_mstate, 2008 fcp->c_mtrstate[unit])); 2009 return (rval); 2010 } 2011 2012 /* 2013 * fdmotort 2014 * is called from timeout() when a motor timer has expired. 2015 */ 2016 static void 2017 fdmotort(void *arg) 2018 { 2019 struct fcu_obj *fjp = (struct fcu_obj *)arg; 2020 struct fdcntlr *fcp = fjp->fj_fdc; 2021 struct fdcsb *csb = &fcp->c_csb; 2022 int unit = fjp->fj_unit & 3; 2023 int mval; 2024 int newxstate = 0; 2025 2026 mutex_enter(&fcp->c_dorlock); 2027 mval = fdc_motorsm(fjp, FMI_TIMER, 0); 2028 mutex_exit(&fcp->c_dorlock); 2029 if (mval < 0) 2030 return; 2031 2032 mutex_enter(&fcp->c_lock); 2033 2034 if ((fcp->c_flags & FCFLG_WAITING) && 2035 fcp->c_mtrstate[unit] == FMS_ON && 2036 (csb->csb_xstate == FXS_MTRON || csb->csb_xstate == FXS_HDST || 2037 csb->csb_xstate == FXS_DKCHGX)) 2038 newxstate = fdc_statemach(fcp); 2039 if (newxstate == -1) { 2040 FCERRPRINT(FDEP_L3, FDEM_EXEC, 2041 (CE_WARN, 2042 "fdc_motort unit %d: motor ready but bad xstate", 2043 (int)fjp->fj_unit)); 2044 fcp->c_csb.csb_cmdstat = EIO; 2045 } 2046 if (newxstate == -1 || newxstate == FXS_END) { 2047 fcp->c_flags ^= FCFLG_WAITING; 2048 cv_signal(&fcp->c_iocv); 2049 } 2050 mutex_exit(&fcp->c_lock); 2051 } 2052 2053 /* 2054 * DMA interrupt service routine 2055 * 2056 * Called by EISA dma interrupt service routine when buffer chaining 2057 * is required. 2058 */ 2059 2060 ddi_dma_cookie_t * 2061 fdc_dmae_isr(struct fdcntlr *fcp) 2062 { 2063 struct fdcsb *csb = &fcp->c_csb; 2064 off_t off; 2065 size_t len; 2066 2067 if (csb->csb_dmahandle && !csb->csb_cmdstat) { 2068 if (++csb->csb_dmacurrcookie < csb->csb_dmacookiecnt) { 2069 ddi_dma_nextcookie(csb->csb_dmahandle, 2070 &csb->csb_dmacookie); 2071 return (&csb->csb_dmacookie); 2072 } else if (++csb->csb_dmacurrwin < csb->csb_dmawincnt) { 2073 if (ddi_dma_getwin(csb->csb_dmahandle, 2074 csb->csb_dmacurrwin, &off, &len, 2075 &csb->csb_dmacookie, 2076 &csb->csb_dmacookiecnt) != DDI_SUCCESS) { 2077 return (NULL); 2078 } 2079 csb->csb_dmacurrcookie = 0; 2080 return (&csb->csb_dmacookie); 2081 } 2082 } else 2083 cmn_err(CE_WARN, "fdc: unsolicited DMA interrupt\n"); 2084 return (NULL); 2085 } 2086 2087 2088 /* 2089 * returns: 2090 * 0 if all ok, 2091 * ENXIO - diskette not in drive 2092 * ETIMEDOUT - for immediate operations that timed out 2093 * EBUSY - if stupid chip is locked busy??? 2094 * ENOEXEC - for timeout during sending cmds to chip 2095 * 2096 * to sleep: set sleep 2097 * to check for disk changed: set change 2098 */ 2099 static int 2100 fdc_exec(struct fdcntlr *fcp, int sleep, int change) 2101 { 2102 struct ddi_dmae_req dmaereq; 2103 struct fcu_obj *fjp; 2104 struct fdcsb *csb; 2105 off_t off; 2106 size_t len; 2107 int unit; 2108 2109 mutex_enter(&fcp->c_lock); 2110 FCERRPRINT(FDEP_L0, FDEM_EXEC, 2111 (CE_CONT, "fdc_exec: sleep %x change %x\n", sleep, change)); 2112 csb = &fcp->c_csb; 2113 unit = csb->csb_drive; 2114 fjp = fcp->c_unit[unit]; 2115 2116 if (csb->csb_opflags & CSB_OFINRPT) { 2117 if (*csb->csb_cmd == FO_RECAL) 2118 csb->csb_npcyl = 0; 2119 else if ((*csb->csb_cmd & ~FO_MFM) != FO_FRMT) 2120 csb->csb_npcyl = 2121 csb->csb_cmd[2] * fjp->fj_chars->fdc_steps; 2122 csb->csb_xstate = FXS_START; 2123 } else 2124 csb->csb_xstate = FXS_DOIT; 2125 csb->csb_retrys = 0; 2126 csb->csb_ourtrys = 0; 2127 2128 if (csb->csb_dmahandle) { 2129 /* ensure that entire format xfer is in one cookie */ 2130 /* 2131 * The change from ddi_dma_buf/addr_setup() to 2132 * ddi_dma_buf/addr_bind_handle() has already loaded 2133 * the first DMA window and cookie. 2134 */ 2135 if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT && 2136 (4 * csb->csb_cmd[3]) != csb->csb_dmacookie.dmac_size) { 2137 mutex_exit(&fcp->c_lock); 2138 return (EINVAL); 2139 } 2140 } 2141 2142 retry: 2143 if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) { 2144 fcp->c_curunit = unit; 2145 fjp->fj_flags |= FUNIT_CHAROK; 2146 if (fjp->fj_chars->fdc_transfer_rate == 417) { 2147 /* XXX hack for fdformat */ 2148 /* fjp->fj_chars->fdc_transfer_rate == 500; */ 2149 fjp->fj_attr->fda_rotatespd = 360; 2150 } 2151 if (fdcspecify(fcp, fjp->fj_chars->fdc_transfer_rate, 2152 fjp->fj_drive->fdd_steprate, 40)) 2153 cmn_err(CE_WARN, 2154 "fdc_select: controller setup rejected " 2155 "fdcntrl %p transfer rate %x step rate %x " 2156 "head load time 40\n", (void*)fcp, 2157 fjp->fj_chars->fdc_transfer_rate, 2158 fjp->fj_drive->fdd_steprate); 2159 2160 mutex_enter(&fcp->c_dorlock); 2161 if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) { 2162 /* 3D drive requires 500 ms for speed change */ 2163 (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5); 2164 /* 2165 * Return value ignored - fdcmotort deals with failure. 2166 */ 2167 } 2168 mutex_exit(&fcp->c_dorlock); 2169 } 2170 2171 /* 2172 * If checking for disk_change is enabled 2173 * (i.e. not seeking in fdresetchng), 2174 * we sample the DSKCHG line to see if the diskette has wandered away. 2175 */ 2176 if (change && fdcsense_chng(fcp, unit)) { 2177 FCERRPRINT(FDEP_L3, FDEM_EXEC, 2178 (CE_WARN, "diskette %d changed!!!", csb->csb_drive)); 2179 fcp->c_unit[unit]->fj_flags |= FUNIT_CHANGED; 2180 /* 2181 * If the diskette is still gone... so are we, adios! 2182 */ 2183 if (fdcheckdisk(fcp, unit)) { 2184 mutex_exit(&fcp->c_lock); 2185 2186 /* VP/ix expects an EBUSY return here */ 2187 if (*csb->csb_cmd == FO_SDRV) { 2188 return (EBUSY); 2189 } 2190 return (ENXIO); 2191 } 2192 /* 2193 * delay to ensure that new diskette is up to speed 2194 */ 2195 mutex_enter(&fcp->c_dorlock); 2196 (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 2197 fjp->fj_drive->fdd_motoron); 2198 /* 2199 * Return value ignored - fdcmotort deals with failure. 2200 */ 2201 mutex_exit(&fcp->c_dorlock); 2202 } 2203 2204 /* 2205 * gather some statistics 2206 */ 2207 switch (csb->csb_cmd[0] & 0x1f) { 2208 case FO_RDDAT: 2209 fcp->fdstats.rd++; 2210 break; 2211 case FO_WRDAT: 2212 fcp->fdstats.wr++; 2213 break; 2214 case FO_RECAL: 2215 fcp->fdstats.recal++; 2216 break; 2217 case FO_FRMT: 2218 fcp->fdstats.form++; 2219 break; 2220 default: 2221 fcp->fdstats.other++; 2222 break; 2223 } 2224 2225 bzero(csb->csb_rslt, 10); 2226 csb->csb_cmdstat = 0; 2227 2228 if (csb->csb_dmahandle) { 2229 bzero(&dmaereq, sizeof (struct ddi_dmae_req)); 2230 dmaereq.der_command = (csb->csb_opflags & CSB_OFDMAWT) ? 2231 DMAE_CMD_WRITE : DMAE_CMD_READ; 2232 /* 2233 * setup for dma buffer chaining regardless of bus capability 2234 */ 2235 dmaereq.der_bufprocess = DMAE_BUF_CHAIN; 2236 dmaereq.proc = fdc_dmae_isr; 2237 dmaereq.procparms = (void *)fcp; 2238 if (ddi_dmae_prog(fcp->c_dip, &dmaereq, &csb->csb_dmacookie, 2239 fcp->c_dmachan) != DDI_SUCCESS) 2240 cmn_err(CE_WARN, "fdc_exec: dmae prog failed, " 2241 "dip %p, dmachan %x\n", 2242 (void*)fcp->c_dip, fcp->c_dmachan); 2243 } 2244 2245 if ((fdc_statemach(fcp) == FXS_DOWT) && !sleep) { 2246 /* 2247 * If the operation has no results - then just return 2248 */ 2249 if (!csb->csb_nrslts) { 2250 mutex_exit(&fcp->c_lock); 2251 return (0); 2252 } 2253 /* 2254 * this operation has no interrupt and an immediate result 2255 * so wait for the results and stuff them into the csb 2256 */ 2257 if (fdc_statemach(fcp) == -1) { 2258 mutex_exit(&fcp->c_lock); 2259 return (EIO); 2260 } 2261 } else { 2262 fcp->c_flags |= FCFLG_WAITING; 2263 /* 2264 * wait for completion interrupt 2265 */ 2266 while (fcp->c_flags & FCFLG_WAITING) { 2267 cv_wait(&fcp->c_iocv, &fcp->c_lock); 2268 } 2269 } 2270 2271 /* 2272 * See if there was an error detected, if so, fdrecover() 2273 * will check it out and say what to do. 2274 * 2275 * Don't do this, though, if this was the Sense Drive Status 2276 * or the Dump Registers command. 2277 */ 2278 if (csb->csb_cmdstat && *csb->csb_cmd != FO_SDRV) { 2279 /* if it can restarted OK, then do so, else return error */ 2280 if (fdrecover(fcp)) { 2281 mutex_exit(&fcp->c_lock); 2282 return (EIO); 2283 } 2284 /* ASSUMES that cmd is still intact in csb */ 2285 if (csb->csb_xstate == FXS_END) 2286 csb->csb_xstate = FXS_START; 2287 if (fdc_dma_attr.dma_attr_sgllen > 1 && csb->csb_dmahandle) { 2288 /* 2289 * restarted read/write operation requires 2290 * first DMA cookie of current window 2291 */ 2292 if (ddi_dma_getwin(csb->csb_dmahandle, 2293 csb->csb_dmacurrwin, &off, &len, 2294 &csb->csb_dmacookie, 2295 &csb->csb_dmacookiecnt) != DDI_SUCCESS) { 2296 2297 mutex_exit(&fcp->c_lock); 2298 return (EIO); 2299 } 2300 csb->csb_dmacurrcookie = 0; 2301 } 2302 goto retry; 2303 } 2304 /* things went ok */ 2305 mutex_exit(&fcp->c_lock); 2306 return (0); 2307 } 2308 2309 /* 2310 * fdcheckdisk 2311 * called by fdc_exec to check if the disk is still there - do a seek 2312 * then see if DSKCHG line went away; if so, diskette is in; else 2313 * it's (still) out. 2314 */ 2315 int 2316 fdcheckdisk(struct fdcntlr *fcp, int unit) 2317 { 2318 struct fdcsb *csb = &fcp->c_csb; 2319 int newcyl; /* where to seek for reset of DSKCHG */ 2320 int rval; 2321 enum fxstate save_xstate; 2322 uchar_t save_cmd, save_cd1, save_npcyl; 2323 2324 ASSERT(MUTEX_HELD(&fcp->c_lock)); 2325 FCERRPRINT(FDEP_L1, FDEM_CHEK, 2326 (CE_CONT, "fdcheckdisk unit %d\n", unit)); 2327 2328 if (fcp->c_curpcyl[unit]) 2329 newcyl = fcp->c_curpcyl[unit] - 1; 2330 else 2331 newcyl = 1; 2332 2333 save_cmd = *csb->csb_cmd; 2334 save_cd1 = csb->csb_cmd[1]; 2335 save_npcyl = csb->csb_npcyl; 2336 save_xstate = csb->csb_xstate; 2337 2338 *csb->csb_cmd = FO_SEEK; 2339 csb->csb_cmd[1] = (uchar_t)unit; 2340 csb->csb_npcyl = (uchar_t)newcyl; 2341 fcp->c_flags |= FCFLG_WAITING; 2342 2343 if (fcp->c_mtrstate[unit] != FMS_ON && fcp->c_motort[unit] != 0) 2344 /* 2345 * wait for motor to get up to speed, 2346 * and let motor_timer issue seek cmd 2347 */ 2348 csb->csb_xstate = FXS_DKCHGX; 2349 else { 2350 /* 2351 * motor is up to speed; issue seek cmd now 2352 */ 2353 csb->csb_xstate = FXS_SEEK; 2354 if (rval = fdcseek(fcp, unit, newcyl)) { 2355 /* 2356 * any recal/seek errors are too serious to attend to 2357 */ 2358 FCERRPRINT(FDEP_L3, FDEM_CHEK, 2359 (CE_WARN, "fdcheckdisk err %d", rval)); 2360 fcp->c_flags ^= FCFLG_WAITING; 2361 } 2362 } 2363 /* 2364 * wait for completion interrupt 2365 * XXX This should be backed up with a watchdog timer! 2366 */ 2367 while (fcp->c_flags & FCFLG_WAITING) { 2368 cv_wait(&fcp->c_iocv, &fcp->c_lock); 2369 } 2370 2371 /* 2372 * if disk change still asserted, no diskette in drive! 2373 */ 2374 if (rval = fdcsense_chng(fcp, unit)) { 2375 FCERRPRINT(FDEP_L3, FDEM_CHEK, 2376 (CE_WARN, "fdcheckdisk no disk %d", unit)); 2377 } 2378 2379 *csb->csb_cmd = save_cmd; 2380 csb->csb_cmd[1] = save_cd1; 2381 csb->csb_npcyl = save_npcyl; 2382 csb->csb_xstate = save_xstate; 2383 return (rval); 2384 } 2385 2386 static int 2387 fdrecover(struct fdcntlr *fcp) 2388 { 2389 struct fcu_obj *fjp; 2390 struct fdcsb *csb = &fcp->c_csb; 2391 int residual; 2392 int unit; 2393 char *failure; 2394 2395 FCERRPRINT(FDEP_L2, FDEM_RECO, 2396 (CE_NOTE, "fdrecover unit %d", csb->csb_drive)); 2397 2398 unit = csb->csb_drive; 2399 fjp = fcp->c_unit[unit]; 2400 if (fcp->c_flags & FCFLG_TIMEOUT) { 2401 fcp->c_flags ^= FCFLG_TIMEOUT; 2402 csb->csb_rslt[1] |= 0x08; 2403 FCERRPRINT(FDEP_L3, FDEM_RECO, 2404 (CE_WARN, "fd unit %d: %s timed out", csb->csb_drive, 2405 fdcmds[*csb->csb_cmd & 0x1f].cmdname)); 2406 } 2407 2408 if (csb->csb_status & S0_SEKEND) 2409 fcp->c_curpcyl[unit] = -1; 2410 2411 switch (csb->csb_oldxs) { 2412 case FXS_RCAL: /* recalibrate */ 2413 case FXS_SEEK: /* seek */ 2414 case FXS_RESET: /* cntlr reset */ 2415 FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN, 2416 "fd unit %d: %s error: st0=0x%x pcn=%d", csb->csb_drive, 2417 fdcmds[*csb->csb_cmd & 0x1f].cmdname, 2418 *csb->csb_rslt, csb->csb_rslt[1])); 2419 if (csb->csb_retrys++ < skretry && 2420 !(csb->csb_opflags & CSB_OFRAWIOCTL)) 2421 return (0); 2422 break; 2423 2424 case FXS_RDID: /* read ID */ 2425 if (!(csb->csb_status & S0_SEKEND)) 2426 csb->csb_xstate = FXS_HDST; 2427 /* FALLTHROUGH */ 2428 case FXS_DOIT: /* original operation */ 2429 case FXS_DOWT: /* waiting on operation */ 2430 if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) { 2431 if (ddi_dmae_getcnt(fcp->c_dip, fcp->c_dmachan, 2432 &residual) != DDI_SUCCESS) 2433 cmn_err(CE_WARN, 2434 "fdc_recover: dmae getcnt failed, " 2435 "dip %p dmachan %x residual %x\n", 2436 (void*)fcp->c_dip, fcp->c_dmachan, 2437 residual); 2438 FCERRPRINT(FDEP_L2, FDEM_RECO, 2439 (CE_NOTE, "fd unit %d: %s error: dma count=0x%lx residual=0x%x", 2440 csb->csb_drive, 2441 fdcmds[*csb->csb_cmd & 0x1f].cmdname, 2442 csb->csb_dmacookie.dmac_size, residual)); 2443 } 2444 if (csb->csb_rslt[1] == S1_OVRUN) 2445 /* 2446 * handle retries of over/underrun 2447 * with a secondary retry counter 2448 */ 2449 if (++csb->csb_ourtrys <= OURUN_TRIES) { 2450 FCERRPRINT(FDEP_L2, FDEM_RECO, 2451 (CE_NOTE, "fd unit %d: %s error: over/under-run", 2452 csb->csb_drive, fdcmds[*csb->csb_cmd & 0x1f].cmdname)); 2453 return (0); 2454 } else 2455 /* 2456 * count 1 set of over/underruns 2457 * as 1 primary retry effort 2458 */ 2459 csb->csb_ourtrys = 0; 2460 2461 if ((fjp->fj_flags & (FUNIT_UNLABELED | FUNIT_LABELOK)) && 2462 !(csb->csb_opflags & CSB_OFRAWIOCTL)) { 2463 /* 2464 * device is open so keep trying and 2465 * gather statistics on errors 2466 */ 2467 if (csb->csb_rslt[1] & S1_CRCER) 2468 fcp->fdstats.de++; 2469 if (csb->csb_rslt[1] & S1_OVRUN) 2470 fcp->fdstats.run++; 2471 if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK)) 2472 fcp->fdstats.bfmt++; 2473 if (csb->csb_rslt[1] & 0x08) 2474 fcp->fdstats.to++; 2475 2476 /* 2477 * if we have not run out of retries, return 0 2478 */ 2479 if (csb->csb_retrys++ < csb->csb_maxretry && 2480 (*csb->csb_cmd & ~FO_MFM) != FO_FRMT) { 2481 if (csb->csb_opflags & 2482 (CSB_OFDMARD | CSB_OFDMAWT)) { 2483 FCERRPRINT(FDEP_L4, FDEM_RECO, 2484 (CE_WARN, "fd unit %d: %s error: st0=0x%x st1=0x%x st2=0x%x", 2485 csb->csb_drive, 2486 fdcmds[*csb->csb_cmd & 0x1f].cmdname, 2487 *csb->csb_rslt, csb->csb_rslt[1], 2488 csb->csb_rslt[2])); 2489 } 2490 if ((csb->csb_retrys & 1) && 2491 csb->csb_xstate == FXS_END) 2492 csb->csb_xstate = FXS_DOIT; 2493 else if (csb->csb_retrys == 3) 2494 csb->csb_xstate = FXS_RESTART; 2495 return (0); 2496 } 2497 if (csb->csb_rslt[1] & S1_CRCER) 2498 failure = "crc error"; 2499 else if (csb->csb_rslt[1] & S1_OVRUN) 2500 failure = "over/under-run"; 2501 else if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK)) 2502 failure = "bad format"; 2503 else if (csb->csb_rslt[1] & 0x08) 2504 failure = "timeout"; 2505 else 2506 failure = "failed"; 2507 cmn_err(CE_NOTE, "!fd unit %d: %s %s (%x %x %x)", 2508 csb->csb_drive, 2509 fdcmds[*csb->csb_cmd & 0x1f].cmdname, failure, 2510 *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2]); 2511 } else { 2512 FCERRPRINT(FDEP_L2, FDEM_RECO, 2513 (CE_NOTE, "fd unit %d: %s failed (%x %x %x)", 2514 csb->csb_drive, 2515 fdcmds[*csb->csb_cmd & 0x1f].cmdname, 2516 *csb->csb_rslt, csb->csb_rslt[1], 2517 csb->csb_rslt[2])); 2518 } 2519 break; 2520 2521 default: 2522 FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN, 2523 "fd unit %d: %s failed: st0=0x%x st1=0x%x st2=0x%x", 2524 csb->csb_drive, fdcmds[*csb->csb_cmd & 0x1f].cmdname, 2525 *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2])); 2526 break; 2527 } 2528 return (1); 2529 } 2530 2531 2532 /* Autovector Interrupt Entry Point */ 2533 /* ARGSUSED */ 2534 static uint_t 2535 fdc_intr(caddr_t arg) 2536 { 2537 struct fdcntlr *fcp = (struct fdcntlr *)arg; 2538 struct fdcsb *csb; 2539 off_t off; 2540 size_t blklen; 2541 int drive; 2542 int newstate; 2543 int pendstate; 2544 int rval = DDI_DMA_DONE; 2545 int state; 2546 int maxspin = 10; 2547 2548 csb = &fcp->c_csb; 2549 2550 mutex_enter(&fcp->c_lock); 2551 /* 2552 * Wait for the RQM bit to be set, or until we've tested it 2553 * a bunch of times (which may imply this isn't our interrupt). 2554 */ 2555 state = inb(fcp->c_regbase + FCR_MSR); 2556 pendstate = state & (MS_RQM | MS_DIO | MS_CB); 2557 while (((pendstate & MS_RQM) == 0) && (maxspin-- > 0)) { 2558 /* Small pause in between reading the status port */ 2559 drv_usecwait(10); 2560 /* Reread the status port */ 2561 state = inb(fcp->c_regbase + FCR_MSR); 2562 pendstate = state & (MS_RQM | MS_DIO | MS_CB); 2563 } 2564 FCERRPRINT(FDEP_L0, FDEM_INTR, 2565 (CE_CONT, "fdc_intr unit %d: xstate=%d MSR=0x%x\n", 2566 csb->csb_drive, csb->csb_xstate, state)); 2567 2568 /* 2569 * If there is an operation outstanding AND the controller is ready 2570 * to receive a command or send us the result of a command (OR if the 2571 * controller is ready to accept a new command), AND if 2572 * someone has been waiting for a command to finish AND (if no unit 2573 * is BUSY OR if the unit that we're waiting for is BUSY (i.e. it's in 2574 * the middle of a seek/recalibrate)) then this interrupt is for us. 2575 */ 2576 if ((pendstate == (MS_RQM | MS_DIO | MS_CB) || pendstate == MS_RQM) && 2577 (fcp->c_flags & FCFLG_WAITING) && 2578 (!(state & 0x0f) || ((1 << csb->csb_drive) & state))) { 2579 /* 2580 * Remove one of the conditions for entering this code. 2581 * The state_machine will release the c_lock if it 2582 * calls untimeout() 2583 */ 2584 fcp->c_flags ^= FCFLG_WAITING; 2585 2586 if ((newstate = fdc_statemach(fcp)) == -1) { 2587 /* restore waiting flag */ 2588 fcp->c_flags |= FCFLG_WAITING; 2589 mutex_exit(&fcp->c_lock); 2590 return (DDI_INTR_CLAIMED); 2591 } 2592 2593 if (fcp->c_intrstat) 2594 KIOIP->intrs[KSTAT_INTR_HARD]++; 2595 if (newstate == FXS_END) { 2596 2597 if (csb->csb_dmahandle && !csb->csb_cmdstat && 2598 /* 2599 * read/write operation may have multiple DMA 2600 * cookies: process next one 2601 */ 2602 ((csb->csb_dmacurrcookie < 2603 (csb->csb_dmacookiecnt - 1)) || 2604 (csb->csb_dmacurrwin) < (csb->csb_dmawincnt - 1))) { 2605 /* 2606 * read/write operation requires another 2607 * DMA cookie: process next one 2608 */ 2609 2610 if (++csb->csb_dmacurrcookie < 2611 csb->csb_dmacookiecnt) { 2612 ddi_dma_nextcookie(csb->csb_dmahandle, 2613 &csb->csb_dmacookie); 2614 } else if (++csb->csb_dmacurrwin < 2615 csb->csb_dmawincnt) { 2616 if (ddi_dma_getwin(csb->csb_dmahandle, 2617 csb->csb_dmacurrwin, &off, &blklen, 2618 &csb->csb_dmacookie, 2619 &csb->csb_dmacookiecnt) != 2620 DDI_SUCCESS) { 2621 cmn_err(CE_WARN, 2622 "fdc_intr: " 2623 "dma getwin failed\n"); 2624 } 2625 csb->csb_dmacurrcookie = 0; 2626 } 2627 2628 if (ddi_dmae_prog(fcp->c_dip, NULL, 2629 &csb->csb_dmacookie, fcp->c_dmachan) != 2630 DDI_SUCCESS) 2631 cmn_err(CE_WARN, 2632 "fdc_intr: dmae prog failed, " 2633 "dip %p dmachannel %x\n", 2634 (void*)fcp->c_dip, 2635 fcp->c_dmachan); 2636 2637 /* 2638 * status of last operation has disk 2639 * address for continuation 2640 */ 2641 csb->csb_cmd[2] = csb->csb_rslt[3]; 2642 csb->csb_cmd[3] = csb->csb_rslt[4]; 2643 csb->csb_cmd[4] = csb->csb_rslt[5]; 2644 csb->csb_cmd[1] = (csb->csb_cmd[1] & ~0x04) | 2645 (csb->csb_cmd[3] << 2); 2646 2647 csb->csb_xstate = FXS_START; 2648 (void) fdc_statemach(fcp); 2649 /* 2650 * Ignored return. If failed, warning already 2651 * posted. Returned state irrelevant. 2652 */ 2653 /* restore waiting flag */ 2654 fcp->c_flags |= FCFLG_WAITING; 2655 goto fi_exit; 2656 } 2657 if (rval != DDI_DMA_DONE) 2658 csb->csb_cmdstat = EIO; 2659 /* 2660 * somebody's waiting for completion of fdcntlr/csb, 2661 * wake them 2662 */ 2663 cv_signal(&fcp->c_iocv); 2664 } 2665 else 2666 /* restore waiting flag */ 2667 fcp->c_flags |= FCFLG_WAITING; 2668 fi_exit: 2669 mutex_exit(&fcp->c_lock); 2670 return (DDI_INTR_CLAIMED); 2671 } 2672 2673 if (state & MS_RQM) { 2674 (void) fdcsense_int(fcp, &drive, NULL); 2675 /* 2676 * Ignored return - senser state already saved 2677 */ 2678 FCERRPRINT(FDEP_L4, FDEM_INTR, 2679 (CE_WARN, "fdc_intr unit %d: nobody sleeping 0x%x", 2680 drive, state)); 2681 } else { 2682 FCERRPRINT(FDEP_L4, FDEM_INTR, 2683 (CE_WARN, "fdc_intr: nobody sleeping on %d 0x%x", 2684 csb->csb_drive, state)); 2685 } 2686 /* 2687 * This should probably be protected, but, what the 2688 * heck...the cost isn't worth the accuracy for this 2689 * statistic. 2690 */ 2691 if (fcp->c_intrstat) 2692 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 2693 mutex_exit(&fcp->c_lock); 2694 return (DDI_INTR_UNCLAIMED); 2695 } 2696 2697 /* 2698 * fdwatch 2699 * is called from timeout() when a floppy operation timer has expired. 2700 */ 2701 static void 2702 fdwatch(void *arg) 2703 { 2704 struct fdcntlr *fcp = (struct fdcntlr *)arg; 2705 struct fdcsb *csb; 2706 2707 mutex_enter(&fcp->c_lock); 2708 2709 if (fcp->c_timeid == 0) { 2710 /* 2711 * fdc_intr got here first, ergo, no timeout condition.. 2712 */ 2713 mutex_exit(&fcp->c_lock); 2714 return; 2715 } 2716 2717 if (fcp->c_flags & FCFLG_WAITING) { 2718 if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS) 2719 cmn_err(CE_WARN, "fdwatch: dmae stop failed, " 2720 "dip %p, dmachan %x\n", 2721 (void*)fcp->c_dip, fcp->c_dmachan); 2722 csb = &fcp->c_csb; 2723 FCERRPRINT(FDEP_L3, FDEM_WATC, 2724 (CE_WARN, "fdcwatch unit %d: xstate = %d", 2725 csb->csb_drive, csb->csb_xstate)); 2726 drv_usecwait(50); 2727 2728 if (inb(fcp->c_regbase + FCR_MSR) != MS_RQM) { 2729 /* 2730 * cntlr is still busy, so reset it 2731 */ 2732 csb->csb_xstate = FXS_KILL; 2733 (void) fdc_statemach(fcp); 2734 /* 2735 * Ignored return. If failed, warning already 2736 * posted. Returned state irrelevant. 2737 */ 2738 } else { 2739 csb->csb_xstate = FXS_END; 2740 fcp->c_timeid = 0; 2741 fcp->c_flags ^= FCFLG_WAITING; 2742 cv_signal(&fcp->c_iocv); 2743 } 2744 csb->csb_cmdstat = EIO; 2745 fcp->c_flags |= FCFLG_TIMEOUT; 2746 } else { 2747 FCERRPRINT(FDEP_L4, FDEM_INTR, 2748 (CE_WARN, "fdcwatch: not sleeping for unit %d", 2749 fcp->c_csb.csb_drive)); 2750 } 2751 if (fcp->c_intrstat) 2752 KIOIP->intrs[KSTAT_INTR_WATCHDOG]++; 2753 mutex_exit(&fcp->c_lock); 2754 } 2755 2756 2757 static int 2758 fdc_statemach(struct fdcntlr *fcp) 2759 { 2760 struct fcu_obj *fjp; 2761 struct fdcsb *csb = &fcp->c_csb; 2762 int backoff; 2763 clock_t time; 2764 int unit; 2765 2766 ASSERT(MUTEX_HELD(&fcp->c_lock)); 2767 2768 unit = csb->csb_drive; 2769 fjp = fcp->c_unit[unit]; 2770 2771 csb->csb_oldxs = csb->csb_xstate; 2772 switch (csb->csb_xstate) { 2773 2774 case FXS_START: /* start of operation */ 2775 ASSERT(fcp->c_timeid == 0); 2776 time = drv_usectohz(100000 * (unsigned int)csb->csb_timer); 2777 if (time == 0) 2778 time = drv_usectohz(2000000); 2779 fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 2780 2781 if (fcp->c_mtrstate[unit] == FMS_START) { 2782 /* 2783 * wait for motor to get up to speed 2784 */ 2785 csb->csb_xstate = FXS_MTRON; 2786 break; 2787 } 2788 /* FALLTHROUGH */ 2789 2790 case FXS_MTRON: /* motor is at speed */ 2791 if (fcp->c_mtrstate[unit] != FMS_ON) { 2792 /* how did we get here ?? */ 2793 cmn_err(CE_WARN, "fdc: selected but motor off"); 2794 return (-1); 2795 } 2796 if (fcp->c_curpcyl[unit] != -1 && *csb->csb_cmd != FO_RECAL) 2797 goto nxs_seek; 2798 recalcmd[1] = (uchar_t)unit; 2799 if (fdc_docmd(fcp, recalcmd, 2) == -1) { 2800 /* cntlr did not accept command bytes */ 2801 fdcquiesce(fcp); 2802 csb->csb_cmdstat = EIO; 2803 csb->csb_xstate = FXS_RESET; 2804 break; 2805 } 2806 fcp->c_sekdir[unit] = 0; 2807 csb->csb_xstate = FXS_RCAL; 2808 break; 2809 2810 case FXS_RCAL: /* forced recalibrate is complete */ 2811 #if 0 /* #ifdef _VPIX */ 2812 /* WARNING: this code breaks SPARC compatibility */ 2813 if (csb->csb_opflags & CSB_OFRAWIOCTL && 2814 *csb->csb_cmd == FO_RECAL) { 2815 fcp->c_curpcyl[unit] = 0; 2816 csb->csb_status = 0; 2817 goto nxs_cmpl; 2818 } 2819 #endif 2820 (void) fdc_docmd(fcp, &senseintcmd, 1); 2821 /* 2822 * Ignored return. If failed, warning was issued by fdc_docmd. 2823 * fdc_results retrieves the controller/drive status 2824 */ 2825 (void) fdc_result(fcp, csb->csb_rslt, 2); 2826 /* 2827 * Ignored return. If failed, warning was issued by fdc_result. 2828 * Actual results checked below 2829 */ 2830 if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 2831 (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) { 2832 FCERRPRINT(FDEP_L3, FDEM_EXEC, 2833 (CE_WARN, "fdc_statemach unit %d: recal result %x", 2834 csb->csb_drive, *csb->csb_rslt)); 2835 fdcquiesce(fcp); 2836 csb->csb_cmdstat = EIO; 2837 csb->csb_xstate = FXS_RESET; 2838 break; 2839 } 2840 if (unit != (*csb->csb_rslt & 3) || csb->csb_rslt[1]) { 2841 csb->csb_status = S0_SEKEND; 2842 goto nxs_cmpl; 2843 } 2844 fcp->c_curpcyl[unit] = csb->csb_rslt[1]; 2845 if (*csb->csb_cmd == FO_RECAL) 2846 goto nxs_cmpl; 2847 nxs_seek: 2848 if (*csb->csb_cmd != FO_SEEK && 2849 csb->csb_npcyl == fcp->c_curpcyl[unit]) 2850 goto nxs_doit; 2851 fcp->c_sekdir[unit] = csb->csb_npcyl - fcp->c_curpcyl[unit]; 2852 /* FALLTHROUGH */ 2853 2854 case FXS_DKCHGX: /* reset Disk-Change latch */ 2855 (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl); 2856 /* 2857 * Ignored return. If command rejected, warnig already posted 2858 * by fdc_docmd(). 2859 */ 2860 csb->csb_xstate = FXS_SEEK; 2861 break; 2862 2863 case FXS_RESTART: /* special restart of read/write operation */ 2864 ASSERT(fcp->c_timeid == 0); 2865 time = drv_usectohz(100000 * csb->csb_timer); 2866 if (time == 0) 2867 time = drv_usectohz(2000000); 2868 fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 2869 2870 if (fcp->c_mtrstate[unit] != FMS_ON) { 2871 cmn_err(CE_WARN, "fdc: selected but motor off"); 2872 return (-1); 2873 } 2874 if ((csb->csb_npcyl == 0 || fcp->c_sekdir[unit] >= 0) && 2875 (int)csb->csb_cmd[2] < (fjp->fj_chars->fdc_ncyl - 1)) 2876 backoff = csb->csb_npcyl + 1; 2877 else 2878 backoff = csb->csb_npcyl - 1; 2879 (void) fdcseek(fcp, csb->csb_cmd[1], backoff); 2880 /* 2881 * Ignored return. If command rejected, warnig already posted 2882 * by fdc_docmd(). 2883 */ 2884 csb->csb_xstate = FXS_RESEEK; 2885 break; 2886 2887 case FXS_RESEEK: /* seek to backoff-cyl complete */ 2888 (void) fdc_docmd(fcp, &senseintcmd, 1); 2889 /* 2890 * Ignored return. If failed, warning was issued by fdc_docmd. 2891 * fdc_results retrieves the controller/drive status 2892 */ 2893 (void) fdc_result(fcp, csb->csb_rslt, 2); 2894 /* 2895 * Ignored return. If failed, warning was issued by fdc_result. 2896 * Actual results checked below 2897 */ 2898 if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 2899 (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) 2900 goto nxs_cmpl; 2901 (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl); 2902 /* 2903 * Ignored return. If command rejected, warnig already posted 2904 * by fdc_docmd(). 2905 */ 2906 csb->csb_xstate = FXS_SEEK; 2907 break; 2908 2909 case FXS_SEEK: /* seek complete */ 2910 #if 0 /* #ifdef _VPIX */ 2911 /* WARNING: this code breaks SPARC compatibility and */ 2912 /* rawioctls in fdformat */ 2913 if (csb->csb_opflags & CSB_OFRAWIOCTL) { 2914 fcp->c_curpcyl[unit] = csb->csb_npcyl; 2915 csb->csb_status = 0; 2916 goto nxs_cmpl; 2917 } 2918 #endif 2919 (void) fdc_docmd(fcp, &senseintcmd, 1); 2920 /* 2921 * Ignored return. If failed, warning was issued by fdc_docmd. 2922 * fdc_results retrieves the controller/drive status 2923 */ 2924 (void) fdc_result(fcp, csb->csb_rslt, 2); 2925 /* 2926 * Ignored return. If failed, warning was issued by fdc_result. 2927 * Actual results checked below 2928 */ 2929 if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 2930 (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) 2931 goto nxs_cmpl; 2932 if (unit != (*csb->csb_rslt & 3) || 2933 csb->csb_rslt[1] != csb->csb_npcyl) { 2934 csb->csb_status = S0_SEKEND; 2935 goto nxs_cmpl; 2936 }; 2937 fcp->c_curpcyl[unit] = csb->csb_rslt[1]; 2938 /* use motor_timer to delay for head settle */ 2939 mutex_enter(&fcp->c_dorlock); 2940 (void) fdc_motorsm(fjp, FMI_DELAYCMD, 2941 fjp->fj_drive->fdd_headsettle / 1000); 2942 /* 2943 * Return value ignored - fdcmotort deals with failure. 2944 */ 2945 mutex_exit(&fcp->c_dorlock); 2946 csb->csb_xstate = FXS_HDST; 2947 break; 2948 2949 case FXS_HDST: /* head settle */ 2950 if (*csb->csb_cmd == FO_SEEK) 2951 goto nxs_cmpl; 2952 if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT) 2953 goto nxs_doit; 2954 fdcreadid(fcp, csb); 2955 csb->csb_xstate = FXS_RDID; 2956 break; 2957 2958 case FXS_RDID: /* read ID complete */ 2959 (void) fdc_result(fcp, csb->csb_rslt, 7); 2960 /* 2961 * Ignored return. If failed, warning was issued by fdc_result. 2962 * Actual results checked below 2963 */ 2964 if ((csb->csb_status = (*csb->csb_rslt & 2965 (S0_ICMASK | S0_ECHK | S0_NOTRDY))) != 0) 2966 goto nxs_cmpl; 2967 if (csb->csb_cmd[2] != csb->csb_rslt[3]) { 2968 /* at wrong logical cylinder */ 2969 csb->csb_status = S0_SEKEND; 2970 goto nxs_cmpl; 2971 }; 2972 goto nxs_doit; 2973 2974 case FXS_DOIT: /* do original operation */ 2975 ASSERT(fcp->c_timeid == 0); 2976 time = drv_usectohz(100000 * csb->csb_timer); 2977 if (time == 0) 2978 time = drv_usectohz(2000000); 2979 fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 2980 nxs_doit: 2981 if (fdc_docmd(fcp, csb->csb_cmd, csb->csb_ncmds) == -1) { 2982 /* cntlr did not accept command bytes */ 2983 fdcquiesce(fcp); 2984 csb->csb_xstate = FXS_RESET; 2985 csb->csb_cmdstat = EIO; 2986 break; 2987 } 2988 csb->csb_xstate = FXS_DOWT; 2989 break; 2990 2991 case FXS_DOWT: /* operation complete */ 2992 (void) fdc_result(fcp, csb->csb_rslt, csb->csb_nrslts); 2993 /* 2994 * Ignored return. If failed, warning was issued by fdc_result. 2995 * Actual results checked below. 2996 */ 2997 if (*csb->csb_cmd == FO_SDRV) { 2998 csb->csb_status = 2999 (*csb->csb_rslt ^ (S3_DRRDY | S3_2SIDE)) & 3000 ~(S3_HEAD | S3_UNIT); 3001 } else { 3002 csb->csb_status = *csb->csb_rslt & 3003 (S0_ICMASK | S0_ECHK | S0_NOTRDY); 3004 } 3005 nxs_cmpl: 3006 if (csb->csb_status) 3007 csb->csb_cmdstat = EIO; 3008 csb->csb_xstate = FXS_END; 3009 3010 /* remove watchdog timer if armed and not already triggered */ 3011 if (fcp->c_timeid != 0) { 3012 timeout_id_t timeid; 3013 timeid = fcp->c_timeid; 3014 fcp->c_timeid = 0; 3015 mutex_exit(&fcp->c_lock); 3016 (void) untimeout(timeid); 3017 mutex_enter(&fcp->c_lock); 3018 } 3019 break; 3020 3021 case FXS_KILL: /* quiesce cntlr by reset */ 3022 fdcquiesce(fcp); 3023 fcp->c_timeid = timeout(fdwatch, (void *)fcp, 3024 drv_usectohz(2000000)); 3025 csb->csb_xstate = FXS_RESET; 3026 break; 3027 3028 case FXS_RESET: /* int from reset */ 3029 for (unit = 0; unit < NFDUN; unit++) { 3030 (void) fdcsense_int(fcp, NULL, NULL); 3031 fcp->c_curpcyl[unit] = -1; 3032 } 3033 if (fcp->c_timeid != 0) { 3034 timeout_id_t timeid; 3035 timeid = fcp->c_timeid; 3036 fcp->c_timeid = 0; 3037 mutex_exit(&fcp->c_lock); 3038 (void) untimeout(timeid); 3039 mutex_enter(&fcp->c_lock); 3040 } 3041 csb->csb_xstate = FXS_END; 3042 break; 3043 3044 default: 3045 cmn_err(CE_WARN, "fdc: statemach, unknown state"); 3046 return (-1); 3047 } 3048 FCERRPRINT(FDEP_L1, FDEM_EXEC, 3049 (CE_CONT, "fdc_statemach unit %d: %d -> %d\n", 3050 csb->csb_drive, csb->csb_oldxs, csb->csb_xstate)); 3051 return (csb->csb_xstate); 3052 } 3053 3054 3055 /* 3056 * routine to program a command into the floppy disk controller. 3057 */ 3058 int 3059 fdc_docmd(struct fdcntlr *fcp, uchar_t *oplistp, uchar_t count) 3060 { 3061 int ntries; 3062 3063 ASSERT(count >= 1); 3064 FCERRPRINT(FDEP_L0, FDEM_EXEC, 3065 (CE_CONT, "fdc_docmd: %x %x %x %x %x %x %x %x %x\n", 3066 oplistp[0], oplistp[1], oplistp[2], oplistp[3], oplistp[4], 3067 oplistp[5], oplistp[6], oplistp[7], oplistp[8])); 3068 3069 do { 3070 ntries = FDC_RQM_RETRY; 3071 do { 3072 if ((inb(fcp->c_regbase + FCR_MSR) & (MS_RQM|MS_DIO)) 3073 == MS_RQM) 3074 break; 3075 else 3076 drv_usecwait(1); 3077 } while (--ntries); 3078 if (ntries == 0) { 3079 FCERRPRINT(FDEP_L3, FDEM_EXEC, 3080 (CE_WARN, "fdc_docmd: ctlr not ready")); 3081 return (-1); 3082 } 3083 outb(fcp->c_regbase + FCR_DATA, *oplistp++); 3084 drv_usecwait(16); /* See comment in fdc_result() */ 3085 } while (--count); 3086 return (0); 3087 } 3088 3089 3090 /* 3091 * Routine to return controller/drive status information. 3092 * The diskette-controller data-register is read the 3093 * requested number of times and the results are placed in 3094 * consecutive memory locations starting at the passed 3095 * address. 3096 */ 3097 int 3098 fdc_result(struct fdcntlr *fcp, uchar_t *rsltp, uchar_t rcount) 3099 { 3100 int ntries; 3101 uchar_t *abresultp = rsltp; 3102 uchar_t stat; 3103 int laxative = 7; 3104 3105 ntries = 10 * FDC_RQM_RETRY; 3106 do { 3107 do { 3108 if ((inb(fcp->c_regbase + FCR_MSR) & 3109 (MS_RQM | MS_DIO)) == (MS_RQM | MS_DIO)) 3110 break; 3111 else 3112 drv_usecwait(10); 3113 } while (--ntries); 3114 if (!ntries) { 3115 FCERRPRINT(FDEP_L3, FDEM_EXEC, 3116 (CE_WARN, "fdc_result: ctlr not ready")); 3117 return (-2); 3118 } 3119 *rsltp++ = inb(fcp->c_regbase + FCR_DATA); 3120 3121 /* 3122 * The PRM suggests waiting for 14.5 us. 3123 * Adding a bit more to cover the case of bad calibration 3124 * of drv_usecwait(). 3125 */ 3126 drv_usecwait(16); 3127 ntries = FDC_RQM_RETRY; 3128 } while (--rcount); 3129 while ((inb(fcp->c_regbase + FCR_MSR) & MS_CB) && laxative--) { 3130 FCERRPRINT(FDEP_L3, FDEM_EXEC, 3131 (CE_WARN, "fdc_result: ctlr still busy")); 3132 /* 3133 * try to complete Result phase by purging 3134 * result bytes queued for reading 3135 */ 3136 *abresultp = S0_IVCMD; 3137 do { 3138 stat = inb(fcp->c_regbase + FCR_MSR) & 3139 (MS_RQM | MS_DIO); 3140 if (stat == MS_RQM) { 3141 /* 3142 * Result phase is complete 3143 * but did we get the results corresponding to 3144 * the command we think we executed? 3145 */ 3146 return (-1); 3147 } 3148 if (stat == (MS_RQM | MS_DIO)) 3149 break; 3150 else 3151 drv_usecwait(10); 3152 } while (--ntries); 3153 if (!ntries || !laxative) { 3154 FCERRPRINT(FDEP_L3, FDEM_EXEC, 3155 (CE_WARN, 3156 "fdc_result: ctlr still busy and not ready")); 3157 return (-3); 3158 } 3159 (void) inb(fcp->c_regbase + FCR_DATA); 3160 3161 drv_usecwait(16); /* See comment above */ 3162 ntries = FDC_RQM_RETRY; 3163 } 3164 return (0); 3165 } 3166 3167 /* 3168 * Function: get_unit() 3169 * 3170 * Assumptions: ioaddr is either 0x3f0 or 0x370 3171 */ 3172 static int 3173 get_unit(dev_info_t *dip, int *cntrl_num) 3174 { 3175 int ioaddr; 3176 3177 if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS) 3178 return (DDI_FAILURE); 3179 3180 switch (ioaddr) { 3181 case 0x3f0: 3182 *cntrl_num = 0; 3183 break; 3184 3185 case 0x370: 3186 *cntrl_num = 1; 3187 break; 3188 3189 default: 3190 return (DDI_FAILURE); 3191 } 3192 return (DDI_SUCCESS); 3193 } 3194 3195 static int 3196 get_ioaddr(dev_info_t *dip, int *ioaddr) 3197 { 3198 int reglen, nregs, i; 3199 int status = DDI_FAILURE; 3200 struct { 3201 int bustype; 3202 int base; 3203 int size; 3204 } *reglist; 3205 3206 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3207 "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { 3208 cmn_err(CE_WARN, "fdc: reg property not found"); 3209 return (DDI_FAILURE); 3210 } 3211 3212 nregs = reglen / sizeof (*reglist); 3213 for (i = 0; i < nregs; i++) { 3214 if (reglist[i].bustype == 1) { 3215 *ioaddr = reglist[i].base; 3216 status = DDI_SUCCESS; 3217 break; 3218 } 3219 } 3220 kmem_free(reglist, reglen); 3221 3222 if (status == DDI_SUCCESS) { 3223 if (*ioaddr == 0x3f2 || *ioaddr == 0x372) { 3224 /* 3225 * Some BIOS's (ASUS is one) don't include first 3226 * two IO ports in the floppy controller resources. 3227 */ 3228 3229 *ioaddr -= 2; /* step back to 0x3f0 or 0x370 */ 3230 3231 /* 3232 * It would be nice to update the regs property as well 3233 * so device pathname contains 3f0 instead of 3f2, but 3234 * updating the regs now won't have this effect as that 3235 * component of the device pathname has already been 3236 * constructed by the ISA nexus driver. 3237 * 3238 * reglist[i].base -= 2; 3239 * reglist[i].size += 2; 3240 * dev = makedevice(ddi_driver_major(dip), 0); 3241 * ddi_prop_update_int_array(dev, dip, "reg", 3242 * (int *)reglist, reglen / sizeof (int)); 3243 */ 3244 } 3245 } 3246 3247 return (status); 3248 } 3249