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