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