1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Floppy Disk Controller Driver 29 * 30 * for the standard PC architecture using the Intel 8272A fdc. 31 * Note that motor control and drive select use a latch external 32 * to the fdc. 33 * 34 * This driver is EISA capable, and uses DMA buffer chaining if available. 35 * If this driver is attached to the ISA bus nexus (or if the EISA bus driver 36 * does not support DMA buffer chaining), then the bus driver must ensure 37 * that dma mapping (breakup) and dma engine requests are properly degraded. 38 */ 39 40 /* 41 * hack for bugid 1160621: 42 * workaround compiler optimization bug by turning on DEBUG 43 */ 44 #ifndef DEBUG 45 #define DEBUG 1 46 #endif 47 48 #include <sys/param.h> 49 #include <sys/buf.h> 50 #include <sys/ioctl.h> 51 #include <sys/uio.h> 52 #include <sys/open.h> 53 #include <sys/conf.h> 54 #include <sys/file.h> 55 #include <sys/cmn_err.h> 56 #include <sys/debug.h> 57 #include <sys/kmem.h> 58 #include <sys/stat.h> 59 60 #include <sys/autoconf.h> 61 #include <sys/dkio.h> 62 #include <sys/vtoc.h> 63 #include <sys/kstat.h> 64 65 #include <sys/fdio.h> 66 #include <sys/fdc.h> 67 #include <sys/i8272A.h> 68 #include <sys/fd_debug.h> 69 #include <sys/promif.h> 70 #include <sys/ddi.h> 71 #include <sys/sunddi.h> 72 73 /* 74 * bss (uninitialized data) 75 */ 76 static void *fdc_state_head; /* opaque handle top of state structs */ 77 static ddi_dma_attr_t fdc_dma_attr; 78 static ddi_device_acc_attr_t fdc_accattr = {DDI_DEVICE_ATTR_V0, 79 DDI_STRUCTURE_LE_ACC, DDI_STRICTORDER_ACC}; 80 81 /* 82 * Local static data 83 */ 84 #define OURUN_TRIES 12 85 static uchar_t rwretry = 4; 86 static uchar_t skretry = 3; 87 static uchar_t configurecmd[4] = {FO_CNFG, 0, 0x0F, 0}; 88 static uchar_t recalcmd[2] = {FO_RECAL, 0}; 89 static uchar_t senseintcmd = FO_SINT; 90 91 /* 92 * error handling 93 * 94 * for debugging, set rwretry and skretry = 1 95 * set fcerrlevel to 1 96 * set fcerrmask to 224 or 644 97 * 98 * after debug, set rwretry to 4, skretry to 3, and fcerrlevel to 5 99 * set fcerrmask to FDEM_ALL 100 * or remove the define DEBUG 101 */ 102 static uint_t fcerrmask = FDEM_ALL; 103 static int fcerrlevel = 6; 104 105 #define KIOIP KSTAT_INTR_PTR(fcp->c_intrstat) 106 107 108 static xlate_tbl_t drate_mfm[] = { 109 { 250, 2}, 110 { 300, 1}, 111 { 417, 0}, 112 { 500, 0}, 113 { 1000, 3}, 114 { 0, 0} 115 }; 116 117 static xlate_tbl_t sector_size[] = { 118 { 256, 1}, 119 { 512, 2}, 120 { 1024, 3}, 121 { 0, 2} 122 }; 123 124 static xlate_tbl_t motor_onbits[] = { 125 { 0, 0x10}, 126 { 1, 0x20}, 127 { 2, 0x40}, 128 { 3, 0x80}, 129 { 0, 0x80} 130 }; 131 132 static xlate_tbl_t step_rate[] = { 133 { 10, 0xF0}, /* for 500K data rate */ 134 { 20, 0xE0}, 135 { 30, 0xD0}, 136 { 40, 0xC0}, 137 { 50, 0xB0}, 138 { 60, 0xA0}, 139 { 70, 0x90}, 140 { 80, 0x80}, 141 { 90, 0x70}, 142 { 100, 0x60}, 143 { 110, 0x50}, 144 { 120, 0x40}, 145 { 130, 0x30}, 146 { 140, 0x20}, 147 { 150, 0x10}, 148 { 160, 0x00}, 149 { 0, 0x00} 150 }; 151 152 #ifdef notdef 153 static xlate_tbl_t head_unld[] = { 154 { 16, 0x1}, /* for 500K data rate */ 155 { 32, 0x2}, 156 { 48, 0x3}, 157 { 64, 0x4}, 158 { 80, 0x5}, 159 { 96, 0x6}, 160 { 112, 0x7}, 161 { 128, 0x8}, 162 { 144, 0x9}, 163 { 160, 0xA}, 164 { 176, 0xB}, 165 { 192, 0xC}, 166 { 208, 0xD}, 167 { 224, 0xE}, 168 { 240, 0xF}, 169 { 256, 0x0}, 170 { 0, 0x0} 171 }; 172 #endif 173 174 static struct fdcmdinfo { 175 char *cmdname; /* command name */ 176 uchar_t ncmdbytes; /* number of bytes of command */ 177 uchar_t nrsltbytes; /* number of bytes in result */ 178 uchar_t cmdtype; /* characteristics */ 179 } fdcmds[] = { 180 "", 0, 0, 0, /* - */ 181 "", 0, 0, 0, /* - */ 182 "read_track", 9, 7, 1, /* 2 */ 183 "specify", 3, 0, 3, /* 3 */ 184 "sense_drv_status", 2, 1, 3, /* 4 */ 185 "write", 9, 7, 1, /* 5 */ 186 "read", 9, 7, 1, /* 6 */ 187 "recalibrate", 2, 0, 2, /* 7 */ 188 "sense_int_status", 1, 2, 3, /* 8 */ 189 "write_del", 9, 7, 1, /* 9 */ 190 "read_id", 2, 7, 2, /* A */ 191 "", 0, 0, 0, /* - */ 192 "read_del", 9, 7, 1, /* C */ 193 "format_track", 10, 7, 1, /* D */ 194 "dump_reg", 1, 10, 4, /* E */ 195 "seek", 3, 0, 2, /* F */ 196 "version", 1, 1, 3, /* 10 */ 197 "", 0, 0, 0, /* - */ 198 "perp_mode", 2, 0, 3, /* 12 */ 199 "configure", 4, 0, 4, /* 13 */ 200 /* relative seek */ 201 }; 202 203 204 static int 205 fdc_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 206 static int get_ioaddr(dev_info_t *dip, int *ioaddr); 207 static int get_unit(dev_info_t *dip, int *cntrl_num); 208 209 struct bus_ops fdc_bus_ops = { 210 BUSO_REV, 211 nullbusmap, 212 0, /* ddi_intrspec_t (*bus_get_intrspec)(); */ 213 0, /* int (*bus_add_intrspec)(); */ 214 0, /* void (*bus_remove_intrspec)(); */ 215 i_ddi_map_fault, 216 ddi_dma_map, 217 ddi_dma_allochdl, 218 ddi_dma_freehdl, 219 ddi_dma_bindhdl, 220 ddi_dma_unbindhdl, 221 ddi_dma_flush, 222 ddi_dma_win, 223 ddi_dma_mctl, 224 fdc_bus_ctl, 225 ddi_bus_prop_op, 226 }; 227 228 static int fdc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 229 static int fdc_probe(dev_info_t *); 230 static int fdc_attach(dev_info_t *, ddi_attach_cmd_t); 231 static int fdc_detach(dev_info_t *, ddi_detach_cmd_t); 232 static int fdc_quiesce(dev_info_t *); 233 static int fdc_enhance_probe(struct fdcntlr *fcp); 234 235 struct dev_ops fdc_ops = { 236 DEVO_REV, /* devo_rev, */ 237 0, /* refcnt */ 238 fdc_getinfo, /* getinfo */ 239 nulldev, /* identify */ 240 fdc_probe, /* probe */ 241 fdc_attach, /* attach */ 242 fdc_detach, /* detach */ 243 nodev, /* reset */ 244 (struct cb_ops *)0, /* driver operations */ 245 &fdc_bus_ops, /* bus operations */ 246 NULL, /* power */ 247 fdc_quiesce, /* quiesce */ 248 }; 249 250 /* 251 * This is the loadable module wrapper. 252 */ 253 #include <sys/modctl.h> 254 255 extern struct mod_ops mod_driverops; 256 257 static struct modldrv modldrv = { 258 &mod_driverops, /* Type of module. This one is a driver */ 259 "Floppy Controller", /* Name of the module. */ 260 &fdc_ops, /* Driver ops vector */ 261 }; 262 263 static struct modlinkage modlinkage = { 264 MODREV_1, (void *)&modldrv, NULL 265 }; 266 267 int 268 _init(void) 269 { 270 int retval; 271 272 if ((retval = ddi_soft_state_init(&fdc_state_head, 273 sizeof (struct fdcntlr) + NFDUN * sizeof (struct fcu_obj), 0)) != 0) 274 return (retval); 275 276 if ((retval = mod_install(&modlinkage)) != 0) 277 ddi_soft_state_fini(&fdc_state_head); 278 return (retval); 279 } 280 281 int 282 _fini(void) 283 { 284 int retval; 285 286 if ((retval = mod_remove(&modlinkage)) != 0) 287 return (retval); 288 ddi_soft_state_fini(&fdc_state_head); 289 return (retval); 290 } 291 292 int 293 _info(struct modinfo *modinfop) 294 { 295 return (mod_info(&modlinkage, modinfop)); 296 } 297 298 299 int fdc_start(struct fcu_obj *); 300 int fdc_abort(struct fcu_obj *); 301 int fdc_getcap(struct fcu_obj *, char *, int); 302 int fdc_setcap(struct fcu_obj *, char *, int, int); 303 int fdc_dkinfo(struct fcu_obj *, struct dk_cinfo *); 304 int fdc_select(struct fcu_obj *, int, int); 305 int fdgetchng(struct fcu_obj *, int); 306 int fdresetchng(struct fcu_obj *, int); 307 int fdrecalseek(struct fcu_obj *, int, int, int); 308 int fdrw(struct fcu_obj *, int, int, int, int, int, caddr_t, uint_t); 309 int fdtrkformat(struct fcu_obj *, int, int, int, int); 310 int fdrawioctl(struct fcu_obj *, int, caddr_t); 311 312 static struct fcobjops fdc_iops = { 313 fdc_start, /* controller start */ 314 fdc_abort, /* controller abort */ 315 fdc_getcap, /* capability retrieval */ 316 fdc_setcap, /* capability establishment */ 317 fdc_dkinfo, /* get disk controller info */ 318 319 fdc_select, /* select / deselect unit */ 320 fdgetchng, /* get media change */ 321 fdresetchng, /* reset media change */ 322 fdrecalseek, /* recal / seek */ 323 NULL, /* read /write request (UNUSED) */ 324 fdrw, /* read /write sector */ 325 fdtrkformat, /* format track */ 326 fdrawioctl /* raw ioctl */ 327 }; 328 329 330 /* 331 * Function prototypes 332 */ 333 void encode(xlate_tbl_t *tablep, int val, uchar_t *rcode); 334 int decode(xlate_tbl_t *, int, int *); 335 static int fdc_propinit1(struct fdcntlr *, int); 336 static void fdc_propinit2(struct fdcntlr *, int); 337 void fdcquiesce(struct fdcntlr *); 338 int fdcsense_chng(struct fdcntlr *, int); 339 int fdcsense_drv(struct fdcntlr *, int); 340 int fdcsense_int(struct fdcntlr *, int *, int *); 341 int fdcspecify(struct fdcntlr *, int, int, int); 342 int fdcspdchange(struct fdcntlr *, struct fcu_obj *, int); 343 static int fdc_exec(struct fdcntlr *, int, int); 344 int fdcheckdisk(struct fdcntlr *, int); 345 static uint_t fdc_intr(caddr_t arg); 346 static void fdwatch(void *arg); 347 static void fdmotort(void *arg); 348 static int fdrecover(struct fdcntlr *); 349 static int fdc_motorsm(struct fcu_obj *, int, int); 350 static int fdc_statemach(struct fdcntlr *); 351 int fdc_docmd(struct fdcntlr *, uchar_t *, uchar_t); 352 int fdc_result(struct fdcntlr *, uchar_t *, uchar_t); 353 354 355 /* ARGSUSED */ 356 static int 357 fdc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 358 void *arg, void *result) 359 { 360 struct fdcntlr *fcp; 361 struct fcu_obj *fjp; 362 363 FCERRPRINT(FDEP_L0, FDEM_ATTA, 364 (CE_CONT, "fdc_bus_ctl: cmd= %x\n", ctlop)); 365 366 if ((fcp = ddi_get_driver_private(dip)) == NULL) 367 return (DDI_FAILURE); 368 369 switch (ctlop) { 370 371 case DDI_CTLOPS_REPORTDEV: 372 cmn_err(CE_CONT, "?%s%d at %s%d\n", 373 ddi_get_name(rdip), ddi_get_instance(rdip), 374 ddi_get_name(dip), ddi_get_instance(dip)); 375 FCERRPRINT(FDEP_L3, FDEM_ATTA, 376 (CE_WARN, "fdc_bus_ctl: report %s%d at %s%d", 377 ddi_get_name(rdip), ddi_get_instance(rdip), 378 ddi_get_name(dip), ddi_get_instance(dip))); 379 return (DDI_SUCCESS); 380 381 case DDI_CTLOPS_INITCHILD: 382 { 383 dev_info_t *udip = (dev_info_t *)arg; 384 int cntlr; 385 int len; 386 int unit; 387 char name[MAXNAMELEN]; 388 389 FCERRPRINT(FDEP_L3, FDEM_ATTA, 390 (CE_WARN, "fdc_bus_ctl: init child 0x%p", (void*)udip)); 391 cntlr = fcp->c_number; 392 393 len = sizeof (unit); 394 if (ddi_prop_op(DDI_DEV_T_ANY, udip, PROP_LEN_AND_VAL_BUF, 395 DDI_PROP_DONTPASS, "unit", (caddr_t)&unit, &len) 396 != DDI_PROP_SUCCESS || 397 cntlr != FDCTLR(unit) || 398 (fcp->c_unit[FDUNIT(unit)])->fj_dip) 399 return (DDI_NOT_WELL_FORMED); 400 401 (void) sprintf(name, "%d,%d", cntlr, FDUNIT(unit)); 402 ddi_set_name_addr(udip, name); 403 404 fjp = fcp->c_unit[FDUNIT(unit)]; 405 fjp->fj_unit = unit; 406 fjp->fj_dip = udip; 407 fjp->fj_ops = &fdc_iops; 408 fjp->fj_fdc = fcp; 409 fjp->fj_iblock = &fcp->c_iblock; 410 411 ddi_set_driver_private(udip, fjp); 412 413 return (DDI_SUCCESS); 414 } 415 case DDI_CTLOPS_UNINITCHILD: 416 { 417 dev_info_t *udip = (dev_info_t *)arg; 418 419 FCERRPRINT(FDEP_L3, FDEM_ATTA, 420 (CE_WARN, "fdc_bus_ctl: uninit child 0x%p", (void *)udip)); 421 fjp = ddi_get_driver_private(udip); 422 ddi_set_driver_private(udip, NULL); 423 fjp->fj_dip = NULL; 424 ddi_set_name_addr(udip, NULL); 425 return (DDI_SUCCESS); 426 } 427 default: 428 return (DDI_FAILURE); 429 } 430 } 431 432 /* ARGSUSED */ 433 static int 434 fdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 435 { 436 struct fdcntlr *fcp; 437 int rval; 438 439 switch (cmd) { 440 case DDI_INFO_DEVT2DEVINFO: 441 if (fcp = ddi_get_soft_state(fdc_state_head, (dev_t)arg)) { 442 *result = fcp->c_dip; 443 rval = DDI_SUCCESS; 444 break; 445 } else { 446 rval = DDI_FAILURE; 447 break; 448 } 449 case DDI_INFO_DEVT2INSTANCE: 450 *result = (void *)(uintptr_t)getminor((dev_t)arg); 451 rval = DDI_SUCCESS; 452 break; 453 default: 454 rval = DDI_FAILURE; 455 } 456 return (rval); 457 } 458 459 static int 460 fdc_probe(dev_info_t *dip) 461 { 462 int debug[2]; 463 int ioaddr; 464 int len; 465 uchar_t stat; 466 467 len = sizeof (debug); 468 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 469 DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) == 470 DDI_PROP_SUCCESS) { 471 fcerrlevel = debug[0]; 472 fcerrmask = (uint_t)debug[1]; 473 } 474 475 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_probe: dip %p", 476 (void*)dip)); 477 478 if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS) 479 return (DDI_PROBE_FAILURE); 480 481 stat = inb(ioaddr + FCR_MSR); 482 if ((stat & (MS_RQM | MS_DIO | MS_CB)) != MS_RQM && 483 (stat & ~MS_DIO) != MS_CB) 484 return (DDI_PROBE_FAILURE); 485 486 return (DDI_PROBE_SUCCESS); 487 } 488 489 /* ARGSUSED */ 490 static int 491 fdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 492 { 493 struct fdcntlr *fcp; 494 struct fcu_obj *fjp; 495 int cntlr_num, ctlr, unit; 496 int intr_set = 0; 497 int len; 498 char name[MAXNAMELEN]; 499 500 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_attach: dip %p", 501 (void*)dip)); 502 503 switch (cmd) { 504 case DDI_ATTACH: 505 if (ddi_getprop 506 (DDI_DEV_T_ANY, dip, 0, "ignore-hardware-nodes", 0)) { 507 len = sizeof (cntlr_num); 508 if (ddi_prop_op(DDI_DEV_T_ANY, dip, 509 PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "unit", 510 (caddr_t)&cntlr_num, &len) != DDI_PROP_SUCCESS) { 511 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, 512 "fdc_attach failed: dip %p", (void*)dip)); 513 return (DDI_FAILURE); 514 } 515 } else { 516 if (get_unit(dip, &cntlr_num) != DDI_SUCCESS) 517 return (DDI_FAILURE); 518 } 519 520 ctlr = ddi_get_instance(dip); 521 if (ddi_soft_state_zalloc(fdc_state_head, ctlr) != 0) 522 return (DDI_FAILURE); 523 fcp = ddi_get_soft_state(fdc_state_head, ctlr); 524 525 for (unit = 0, fjp = (struct fcu_obj *)(fcp+1); 526 unit < NFDUN; unit++) { 527 fcp->c_unit[unit] = fjp++; 528 } 529 fcp->c_dip = dip; 530 531 if (fdc_propinit1(fcp, cntlr_num) != DDI_SUCCESS) 532 goto no_attach; 533 534 /* get iblock cookie to initialize mutex used in the ISR */ 535 if (ddi_get_iblock_cookie(dip, (uint_t)0, &fcp->c_iblock) != 536 DDI_SUCCESS) { 537 cmn_err(CE_WARN, 538 "fdc_attach: cannot get iblock cookie"); 539 goto no_attach; 540 } 541 mutex_init(&fcp->c_lock, NULL, MUTEX_DRIVER, fcp->c_iblock); 542 intr_set = 1; 543 544 /* setup interrupt handler */ 545 if (ddi_add_intr(dip, (uint_t)0, NULL, 546 (ddi_idevice_cookie_t *)0, fdc_intr, (caddr_t)fcp) != 547 DDI_SUCCESS) { 548 cmn_err(CE_WARN, "fdc: cannot add intr\n"); 549 goto no_attach; 550 } 551 intr_set++; 552 553 /* 554 * acquire the DMA channel 555 * this assumes that the chnl is not shared; else allocate 556 * and free the chnl with each fdc request 557 */ 558 if (ddi_dmae_alloc(dip, fcp->c_dmachan, DDI_DMA_DONTWAIT, NULL) 559 != DDI_SUCCESS) { 560 cmn_err(CE_WARN, "fdc: cannot acquire dma%d\n", 561 fcp->c_dmachan); 562 goto no_attach; 563 } 564 (void) ddi_dmae_getattr(dip, &fdc_dma_attr); 565 fdc_dma_attr.dma_attr_align = MMU_PAGESIZE; 566 567 mutex_init(&fcp->c_dorlock, NULL, MUTEX_DRIVER, fcp->c_iblock); 568 cv_init(&fcp->c_iocv, NULL, CV_DRIVER, fcp->c_iblock); 569 sema_init(&fcp->c_selsem, 1, NULL, SEMA_DRIVER, NULL); 570 571 (void) sprintf(name, "fdc%d", ctlr); 572 fcp->c_intrstat = kstat_create("fdc", ctlr, name, 573 "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 574 if (fcp->c_intrstat) { 575 kstat_install(fcp->c_intrstat); 576 } 577 578 ddi_set_driver_private(dip, fcp); 579 580 /* 581 * reset the controller 582 */ 583 sema_p(&fcp->c_selsem); 584 mutex_enter(&fcp->c_lock); 585 fcp->c_csb.csb_xstate = FXS_RESET; 586 fcp->c_flags |= FCFLG_WAITING; 587 fdcquiesce(fcp); 588 589 /* first test for mode == Model 30 */ 590 fcp->c_mode = (inb(fcp->c_regbase + FCR_SRB) & 0x1c) ? 591 FDCMODE_AT : FDCMODE_30; 592 593 while (fcp->c_flags & FCFLG_WAITING) { 594 cv_wait(&fcp->c_iocv, &fcp->c_lock); 595 } 596 mutex_exit(&fcp->c_lock); 597 sema_v(&fcp->c_selsem); 598 599 fdc_propinit2(fcp, cntlr_num); 600 601 ddi_report_dev(dip); 602 return (DDI_SUCCESS); 603 604 case DDI_RESUME: 605 return (DDI_SUCCESS); 606 /* break; */ 607 608 default: 609 return (DDI_FAILURE); 610 } 611 612 no_attach: 613 if (intr_set) { 614 if (intr_set > 1) 615 ddi_remove_intr(dip, 0, fcp->c_iblock); 616 mutex_destroy(&fcp->c_lock); 617 } 618 ddi_soft_state_free(fdc_state_head, cntlr_num); 619 return (DDI_FAILURE); 620 } 621 622 static int 623 fdc_propinit1(struct fdcntlr *fcp, int cntlr) 624 { 625 dev_info_t *dip; 626 int len; 627 int value; 628 629 dip = fcp->c_dip; 630 len = sizeof (value); 631 632 if (get_ioaddr(dip, &value) != DDI_SUCCESS) 633 return (DDI_FAILURE); 634 635 fcp->c_regbase = (ushort_t)value; 636 637 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 638 DDI_PROP_DONTPASS, "dma-channels", (caddr_t)&value, &len) 639 != DDI_PROP_SUCCESS) { 640 cmn_err(CE_WARN, 641 "fdc_attach: Error, could not find a dma channel"); 642 return (DDI_FAILURE); 643 } 644 fcp->c_dmachan = (ushort_t)value; 645 fcp->c_number = cntlr; 646 return (DDI_SUCCESS); 647 } 648 649 /* ARGSUSED */ 650 static void 651 fdc_propinit2(struct fdcntlr *fcp, int cntlr) 652 { 653 dev_info_t *dip; 654 int ccr; 655 int len; 656 int value; 657 658 dip = fcp->c_dip; 659 len = sizeof (value); 660 661 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 662 DDI_PROP_DONTPASS, "chip", (caddr_t)&value, &len) 663 == DDI_PROP_SUCCESS) 664 fcp->c_chip = value; 665 else { 666 static uchar_t perpindcmd[2] = {FO_PERP, 0}; 667 static uchar_t versioncmd = FO_VRSN; 668 uchar_t result; 669 670 fcp->c_chip = i8272A; 671 (void) fdc_docmd(fcp, &versioncmd, 1); 672 /* 673 * Ignored return. If failed, warning was issued by fdc_docmd. 674 * fdc_results retrieves the controller/drive status 675 */ 676 if (!fdc_result(fcp, &result, 1) && result == 0x90) { 677 /* 678 * try a perpendicular_mode cmd to ensure 679 * that we really have an enhanced controller 680 */ 681 if (fdc_docmd(fcp, perpindcmd, 2) || 682 fdc_docmd(fcp, configurecmd, 4)) 683 /* 684 * perpindicular_mode will be rejected by 685 * older controllers; make sure we don't hang. 686 */ 687 (void) fdc_result(fcp, &result, 1); 688 /* 689 * Ignored return. If failed, warning was 690 * issued by fdc_result. 691 */ 692 else 693 /* enhanced type controller */ 694 695 if ((fcp->c_chip = fdc_enhance_probe(fcp)) == 0) 696 /* default enhanced cntlr */ 697 fcp->c_chip = i82077; 698 } 699 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 700 "chip", fcp->c_chip); 701 /* 702 * Ignoring return value because, for passed arguments, only 703 * DDI_SUCCESS is returned. 704 */ 705 } 706 if (fcp->c_chip >= i82077 && fcp->c_mode == FDCMODE_30 && 707 (inb(fcp->c_regbase + FCR_DIR) & 0x70) == 0) 708 for (ccr = 0; ccr <= (FCC_NOPREC | FCC_DRATE); ccr++) { 709 /* 710 * run through all the combinations of NOPREC and 711 * datarate selection, and see if they show up in the 712 * Model 30 DIR 713 */ 714 outb(fcp->c_regbase + FCR_CCR, ccr); 715 drv_usecwait(5); 716 if ((inb(fcp->c_regbase + FCR_DIR) & 717 (FCC_NOPREC | FCC_DRATE)) != ccr) { 718 fcp->c_mode = FDCMODE_AT; 719 break; 720 } 721 } 722 else 723 fcp->c_mode = FDCMODE_AT; 724 outb(fcp->c_regbase + FCR_CCR, 0); 725 } 726 727 /* ARGSUSED */ 728 static int 729 fdc_enhance_probe(struct fdcntlr *fcp) 730 { 731 static uchar_t nsccmd = FO_NSC; 732 uint_t ddic; 733 int retcode = 0; 734 uchar_t result; 735 uchar_t save; 736 737 /* 738 * Try to identify the enhanced floppy controller. 739 * This is required so that we can program the DENSEL output to 740 * control 3D mode (1.0 MB, 1.6 MB and 2.0 MB unformatted capacity, 741 * 720 KB, 1.2 MB, and 1.44 MB formatted capacity) 3.5" dual-speed 742 * floppy drives. Refer to bugid 1195155. 743 */ 744 745 (void) fdc_docmd(fcp, &nsccmd, 1); 746 /* 747 * Ignored return. If failed, warning was issued by fdc_docmd. 748 * fdc_results retrieves the controller/drive status 749 */ 750 if (!fdc_result(fcp, &result, 1) && result != S0_IVCMD) { 751 /* 752 * only enhanced National Semi PC8477 core 753 * should respond to this command 754 */ 755 if ((result & 0xf0) == 0x70) { 756 /* low 4 bits may change */ 757 fcp->c_flags |= FCFLG_3DMODE; 758 retcode = PC87322; 759 } else 760 cmn_err(CE_CONT, 761 "?fdc: unidentified, enhanced, National Semiconductor cntlr %x\n", result); 762 } else { 763 save = inb(fcp->c_regbase + FCR_SRA); 764 765 do { 766 /* probe for motherboard version of SMC cntlr */ 767 768 /* try to enable configuration mode */ 769 ddic = ddi_enter_critical(); 770 outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 771 outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 772 ddi_exit_critical(ddic); 773 774 outb(fcp->c_regbase + FCR_SRA, 0x0F); 775 if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 776 /* always expect 0 from config reg F */ 777 break; 778 outb(fcp->c_regbase + FCR_SRA, 0x0D); 779 if (inb(fcp->c_regbase + FCR_SRB) != 0x65) 780 /* expect 0x65 from config reg D */ 781 break; 782 outb(fcp->c_regbase + FCR_SRA, 0x0E); 783 result = inb(fcp->c_regbase + FCR_SRB); 784 if (result != 0x02) { 785 /* expect revision level 2 from config reg E */ 786 cmn_err(CE_CONT, 787 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 788 /* break; */ 789 } 790 fcp->c_flags |= FCFLG_3DMODE; 791 retcode = FDC37C665; 792 } while (retcode == 0); 793 outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 794 795 while (retcode == 0) { 796 /* probe for adapter version of SMC cntlr */ 797 ddic = ddi_enter_critical(); 798 outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 799 outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 800 ddi_exit_critical(ddic); 801 802 outb(fcp->c_regbase + FCR_SRA, 0x0F); 803 if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 804 /* always expect 0 from config reg F */ 805 break; 806 outb(fcp->c_regbase + FCR_SRA, 0x0D); 807 if (inb(fcp->c_regbase + FCR_SRB) != 0x66) 808 /* expect 0x66 from config reg D */ 809 break; 810 outb(fcp->c_regbase + FCR_SRA, 0x0E); 811 result = inb(fcp->c_regbase + FCR_SRB); 812 if (result != 0x02) { 813 /* expect revision level 2 from config reg E */ 814 cmn_err(CE_CONT, 815 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 816 /* break; */ 817 } 818 fcp->c_flags |= FCFLG_3DMODE; 819 retcode = FDC37C666; 820 } 821 outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 822 823 drv_usecwait(10); 824 outb(fcp->c_regbase + FCR_SRA, save); 825 } 826 return (retcode); 827 } 828 829 /* ARGSUSED */ 830 static int 831 fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 832 { 833 struct fdcntlr *fcp; 834 struct fcu_obj *fjp; 835 int unit; 836 int rval = 0; 837 838 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_detach: dip %p", 839 (void*)dip)); 840 841 fcp = ddi_get_driver_private(dip); 842 843 switch (cmd) { 844 case DDI_DETACH: 845 for (unit = 0; unit < NFDUN; unit++) 846 if ((fcp->c_unit[unit])->fj_dip) { 847 rval = EBUSY; 848 break; 849 } 850 kstat_delete(fcp->c_intrstat); 851 fcp->c_intrstat = NULL; 852 ddi_remove_intr(fcp->c_dip, 0, fcp->c_iblock); 853 if (ddi_dmae_release(fcp->c_dip, fcp->c_dmachan) != 854 DDI_SUCCESS) 855 cmn_err(CE_WARN, "fdc_detach: dma release failed, " 856 "dip %p, dmachan %x\n", 857 (void*)fcp->c_dip, fcp->c_dmachan); 858 ddi_prop_remove_all(fcp->c_dip); 859 ddi_set_driver_private(fcp->c_dip, NULL); 860 861 mutex_destroy(&fcp->c_lock); 862 mutex_destroy(&fcp->c_dorlock); 863 cv_destroy(&fcp->c_iocv); 864 sema_destroy(&fcp->c_selsem); 865 ddi_soft_state_free(fdc_state_head, ddi_get_instance(dip)); 866 break; 867 868 case DDI_SUSPEND: 869 /* 870 * Following code causes the fdc (floppy controller) 871 * to suspend as long as there are no floppy drives 872 * attached to it. 873 * At present the floppy driver does not support 874 * SUSPEND/RESUME. 875 * 876 * Check if any FD units are attached 877 * 878 * For now, SUSPEND/RESUME is not supported 879 * if a floppy drive is present. 880 * So if any FD unit is attached return DDI_FAILURE 881 */ 882 for (unit = 0; unit < NFDUN; unit++) { 883 fjp = fcp->c_unit[unit]; 884 if (fjp->fj_flags & FUNIT_DRVATCH) { 885 cmn_err(CE_WARN, 886 "fdc_detach: fd attached, failing SUSPEND"); 887 return (DDI_FAILURE); 888 } 889 } 890 891 cmn_err(CE_NOTE, "fdc_detach: SUSPEND fdc"); 892 893 rval = DDI_SUCCESS; 894 break; 895 896 default: 897 rval = EINVAL; 898 break; 899 } 900 return (rval); 901 } 902 903 904 /* ARGSUSED */ 905 int 906 fdc_start(struct fcu_obj *fjp) 907 { 908 return (ENOSYS); 909 } 910 911 int 912 fdc_abort(struct fcu_obj *fjp) 913 { 914 struct fdcntlr *fcp = fjp->fj_fdc; 915 int unit = fjp->fj_unit & 3; 916 917 FCERRPRINT(FDEP_L3, FDEM_RESE, (CE_WARN, "fdc_abort")); 918 if (fcp->c_curunit == unit) { 919 mutex_enter(&fcp->c_lock); 920 if (fcp->c_flags & FCFLG_WAITING) { 921 /* 922 * this can cause data corruption ! 923 */ 924 fdcquiesce(fcp); 925 fcp->c_csb.csb_xstate = FXS_RESET; 926 fcp->c_flags |= FCFLG_TIMEOUT; 927 if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != 928 DDI_SUCCESS) 929 cmn_err(CE_WARN, 930 "fdc_detach: dma release failed, " 931 "dip %p, dmachan %x\n", 932 (void*)fcp->c_dip, fcp->c_dmachan); 933 } 934 mutex_exit(&fcp->c_lock); 935 drv_usecwait(500); 936 return (DDI_SUCCESS); 937 } 938 return (DDI_FAILURE); 939 } 940 941 /* ARGSUSED */ 942 int 943 fdc_getcap(struct fcu_obj *fjp, char *a, int i) 944 { 945 return (ENOSYS); 946 } 947 948 /* ARGSUSED */ 949 int 950 fdc_setcap(struct fcu_obj *fjp, char *a, int i, int j) 951 { 952 return (ENOSYS); 953 } 954 955 int 956 fdc_dkinfo(struct fcu_obj *fjp, struct dk_cinfo *dcp) 957 { 958 struct fdcntlr *fcp = fjp->fj_fdc; 959 960 (void) strncpy((char *)&dcp->dki_cname, ddi_get_name(fcp->c_dip), 961 DK_DEVLEN); 962 dcp->dki_ctype = DKC_UNKNOWN; /* no code for generic PC/AT fdc */ 963 dcp->dki_flags = DKI_FMTTRK; 964 dcp->dki_addr = fcp->c_regbase; 965 dcp->dki_space = 0; 966 dcp->dki_prio = fcp->c_intprio; 967 dcp->dki_vec = fcp->c_intvec; 968 (void) strncpy((char *)&dcp->dki_dname, ddi_driver_name(fjp->fj_dip), 969 DK_DEVLEN); 970 dcp->dki_slave = fjp->fj_unit & 3; 971 dcp->dki_maxtransfer = maxphys / DEV_BSIZE; 972 return (DDI_SUCCESS); 973 } 974 975 /* 976 * on=> non-zero = select, 0 = de-select 977 */ 978 /* ARGSUSED */ 979 int 980 fdc_select(struct fcu_obj *fjp, int funit, int on) 981 { 982 struct fdcntlr *fcp = fjp->fj_fdc; 983 int unit = funit & 3; 984 985 if (on) { 986 /* possess controller */ 987 sema_p(&fcp->c_selsem); 988 FCERRPRINT(FDEP_L2, FDEM_DSEL, 989 (CE_NOTE, "fdc_select unit %d: on", funit)); 990 991 if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) { 992 fcp->c_curunit = unit; 993 fjp->fj_flags |= FUNIT_CHAROK; 994 if (fdcspecify(fcp, 995 fjp->fj_chars->fdc_transfer_rate, 996 fjp->fj_drive->fdd_steprate, 40)) 997 cmn_err(CE_WARN, 998 "fdc_select: controller setup rejected " 999 "fdcntrl %p transfer rate %x step rate %x" 1000 " head load time 40\n", (void*)fcp, 1001 fjp->fj_chars->fdc_transfer_rate, 1002 fjp->fj_drive->fdd_steprate); 1003 } 1004 1005 mutex_enter(&fcp->c_dorlock); 1006 1007 /* make sure drive is not selected in case we change speed */ 1008 fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | 1009 (~unit & FD_DRSEL); 1010 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1011 1012 (void) fdc_motorsm(fjp, FMI_STARTCMD, 1013 fjp->fj_drive->fdd_motoron); 1014 /* 1015 * Return value ignored - fdcmotort deals with failure. 1016 */ 1017 if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) { 1018 /* 3D drive requires 500 ms for speed change */ 1019 (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5); 1020 /* 1021 * Return value ignored - fdcmotort deals with failure. 1022 */ 1023 } 1024 1025 fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | (unit & FD_DRSEL); 1026 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1027 1028 mutex_exit(&fcp->c_dorlock); 1029 fcp->c_csb.csb_drive = (uchar_t)unit; 1030 } else { 1031 FCERRPRINT(FDEP_L2, FDEM_DSEL, 1032 (