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