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