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