17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52df1fe9cSrandyf * Common Development and Distribution License (the "License"). 62df1fe9cSrandyf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Floppy Disk Controller Driver 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * for the standard PC architecture using the Intel 8272A fdc. 317c478bd9Sstevel@tonic-gate * Note that motor control and drive select use a latch external 327c478bd9Sstevel@tonic-gate * to the fdc. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * This driver is EISA capable, and uses DMA buffer chaining if available. 357c478bd9Sstevel@tonic-gate * If this driver is attached to the ISA bus nexus (or if the EISA bus driver 367c478bd9Sstevel@tonic-gate * does not support DMA buffer chaining), then the bus driver must ensure 377c478bd9Sstevel@tonic-gate * that dma mapping (breakup) and dma engine requests are properly degraded. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 417c478bd9Sstevel@tonic-gate * hack for bugid 1160621: 427c478bd9Sstevel@tonic-gate * workaround compiler optimization bug by turning on DEBUG 437c478bd9Sstevel@tonic-gate */ 447c478bd9Sstevel@tonic-gate #ifndef DEBUG 457c478bd9Sstevel@tonic-gate #define DEBUG 1 467c478bd9Sstevel@tonic-gate #endif 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <sys/param.h> 497c478bd9Sstevel@tonic-gate #include <sys/buf.h> 507c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 517c478bd9Sstevel@tonic-gate #include <sys/uio.h> 527c478bd9Sstevel@tonic-gate #include <sys/open.h> 537c478bd9Sstevel@tonic-gate #include <sys/conf.h> 547c478bd9Sstevel@tonic-gate #include <sys/file.h> 557c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 567c478bd9Sstevel@tonic-gate #include <sys/debug.h> 577c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 587c478bd9Sstevel@tonic-gate #include <sys/stat.h> 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 617c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 627c478bd9Sstevel@tonic-gate #include <sys/vtoc.h> 637c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <sys/fdio.h> 667c478bd9Sstevel@tonic-gate #include <sys/fdc.h> 677c478bd9Sstevel@tonic-gate #include <sys/i8272A.h> 687c478bd9Sstevel@tonic-gate #include <sys/fd_debug.h> 697c478bd9Sstevel@tonic-gate #include <sys/promif.h> 707c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 717c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * bss (uninitialized data) 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate static void *fdc_state_head; /* opaque handle top of state structs */ 777c478bd9Sstevel@tonic-gate static ddi_dma_attr_t fdc_dma_attr; 783dda9c1fSmrj static ddi_device_acc_attr_t fdc_accattr = {DDI_DEVICE_ATTR_V0, 793dda9c1fSmrj DDI_STRUCTURE_LE_ACC, DDI_STRICTORDER_ACC}; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Local static data 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate #define OURUN_TRIES 12 857c478bd9Sstevel@tonic-gate static uchar_t rwretry = 4; 867c478bd9Sstevel@tonic-gate static uchar_t skretry = 3; 877c478bd9Sstevel@tonic-gate static uchar_t configurecmd[4] = {FO_CNFG, 0, 0x0F, 0}; 887c478bd9Sstevel@tonic-gate static uchar_t recalcmd[2] = {FO_RECAL, 0}; 897c478bd9Sstevel@tonic-gate static uchar_t senseintcmd = FO_SINT; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * error handling 937c478bd9Sstevel@tonic-gate * 947c478bd9Sstevel@tonic-gate * for debugging, set rwretry and skretry = 1 957c478bd9Sstevel@tonic-gate * set fcerrlevel to 1 967c478bd9Sstevel@tonic-gate * set fcerrmask to 224 or 644 977c478bd9Sstevel@tonic-gate * 987c478bd9Sstevel@tonic-gate * after debug, set rwretry to 4, skretry to 3, and fcerrlevel to 5 997c478bd9Sstevel@tonic-gate * set fcerrmask to FDEM_ALL 1007c478bd9Sstevel@tonic-gate * or remove the define DEBUG 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate static uint_t fcerrmask = FDEM_ALL; 1037c478bd9Sstevel@tonic-gate static int fcerrlevel = 6; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate #define KIOIP KSTAT_INTR_PTR(fcp->c_intrstat) 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static xlate_tbl_t drate_mfm[] = { 1097c478bd9Sstevel@tonic-gate { 250, 2}, 1107c478bd9Sstevel@tonic-gate { 300, 1}, 1117c478bd9Sstevel@tonic-gate { 417, 0}, 1127c478bd9Sstevel@tonic-gate { 500, 0}, 1137c478bd9Sstevel@tonic-gate { 1000, 3}, 1147c478bd9Sstevel@tonic-gate { 0, 0} 1157c478bd9Sstevel@tonic-gate }; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate static xlate_tbl_t sector_size[] = { 1187c478bd9Sstevel@tonic-gate { 256, 1}, 1197c478bd9Sstevel@tonic-gate { 512, 2}, 1207c478bd9Sstevel@tonic-gate { 1024, 3}, 1217c478bd9Sstevel@tonic-gate { 0, 2} 1227c478bd9Sstevel@tonic-gate }; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static xlate_tbl_t motor_onbits[] = { 1257c478bd9Sstevel@tonic-gate { 0, 0x10}, 1267c478bd9Sstevel@tonic-gate { 1, 0x20}, 1277c478bd9Sstevel@tonic-gate { 2, 0x40}, 1287c478bd9Sstevel@tonic-gate { 3, 0x80}, 1297c478bd9Sstevel@tonic-gate { 0, 0x80} 1307c478bd9Sstevel@tonic-gate }; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate static xlate_tbl_t step_rate[] = { 1337c478bd9Sstevel@tonic-gate { 10, 0xF0}, /* for 500K data rate */ 1347c478bd9Sstevel@tonic-gate { 20, 0xE0}, 1357c478bd9Sstevel@tonic-gate { 30, 0xD0}, 1367c478bd9Sstevel@tonic-gate { 40, 0xC0}, 1377c478bd9Sstevel@tonic-gate { 50, 0xB0}, 1387c478bd9Sstevel@tonic-gate { 60, 0xA0}, 1397c478bd9Sstevel@tonic-gate { 70, 0x90}, 1407c478bd9Sstevel@tonic-gate { 80, 0x80}, 1417c478bd9Sstevel@tonic-gate { 90, 0x70}, 1427c478bd9Sstevel@tonic-gate { 100, 0x60}, 1437c478bd9Sstevel@tonic-gate { 110, 0x50}, 1447c478bd9Sstevel@tonic-gate { 120, 0x40}, 1457c478bd9Sstevel@tonic-gate { 130, 0x30}, 1467c478bd9Sstevel@tonic-gate { 140, 0x20}, 1477c478bd9Sstevel@tonic-gate { 150, 0x10}, 1487c478bd9Sstevel@tonic-gate { 160, 0x00}, 1497c478bd9Sstevel@tonic-gate { 0, 0x00} 1507c478bd9Sstevel@tonic-gate }; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate #ifdef notdef 1537c478bd9Sstevel@tonic-gate static xlate_tbl_t head_unld[] = { 1547c478bd9Sstevel@tonic-gate { 16, 0x1}, /* for 500K data rate */ 1557c478bd9Sstevel@tonic-gate { 32, 0x2}, 1567c478bd9Sstevel@tonic-gate { 48, 0x3}, 1577c478bd9Sstevel@tonic-gate { 64, 0x4}, 1587c478bd9Sstevel@tonic-gate { 80, 0x5}, 1597c478bd9Sstevel@tonic-gate { 96, 0x6}, 1607c478bd9Sstevel@tonic-gate { 112, 0x7}, 1617c478bd9Sstevel@tonic-gate { 128, 0x8}, 1627c478bd9Sstevel@tonic-gate { 144, 0x9}, 1637c478bd9Sstevel@tonic-gate { 160, 0xA}, 1647c478bd9Sstevel@tonic-gate { 176, 0xB}, 1657c478bd9Sstevel@tonic-gate { 192, 0xC}, 1667c478bd9Sstevel@tonic-gate { 208, 0xD}, 1677c478bd9Sstevel@tonic-gate { 224, 0xE}, 1687c478bd9Sstevel@tonic-gate { 240, 0xF}, 1697c478bd9Sstevel@tonic-gate { 256, 0x0}, 1707c478bd9Sstevel@tonic-gate { 0, 0x0} 1717c478bd9Sstevel@tonic-gate }; 1727c478bd9Sstevel@tonic-gate #endif 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate static struct fdcmdinfo { 1757c478bd9Sstevel@tonic-gate char *cmdname; /* command name */ 1767c478bd9Sstevel@tonic-gate uchar_t ncmdbytes; /* number of bytes of command */ 1777c478bd9Sstevel@tonic-gate uchar_t nrsltbytes; /* number of bytes in result */ 1787c478bd9Sstevel@tonic-gate uchar_t cmdtype; /* characteristics */ 1797c478bd9Sstevel@tonic-gate } fdcmds[] = { 1807c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1817c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1827c478bd9Sstevel@tonic-gate "read_track", 9, 7, 1, /* 2 */ 1837c478bd9Sstevel@tonic-gate "specify", 3, 0, 3, /* 3 */ 1847c478bd9Sstevel@tonic-gate "sense_drv_status", 2, 1, 3, /* 4 */ 1857c478bd9Sstevel@tonic-gate "write", 9, 7, 1, /* 5 */ 1867c478bd9Sstevel@tonic-gate "read", 9, 7, 1, /* 6 */ 1877c478bd9Sstevel@tonic-gate "recalibrate", 2, 0, 2, /* 7 */ 1887c478bd9Sstevel@tonic-gate "sense_int_status", 1, 2, 3, /* 8 */ 1897c478bd9Sstevel@tonic-gate "write_del", 9, 7, 1, /* 9 */ 1907c478bd9Sstevel@tonic-gate "read_id", 2, 7, 2, /* A */ 1917c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1927c478bd9Sstevel@tonic-gate "read_del", 9, 7, 1, /* C */ 1937c478bd9Sstevel@tonic-gate "format_track", 10, 7, 1, /* D */ 1947c478bd9Sstevel@tonic-gate "dump_reg", 1, 10, 4, /* E */ 1957c478bd9Sstevel@tonic-gate "seek", 3, 0, 2, /* F */ 1967c478bd9Sstevel@tonic-gate "version", 1, 1, 3, /* 10 */ 1977c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1987c478bd9Sstevel@tonic-gate "perp_mode", 2, 0, 3, /* 12 */ 1997c478bd9Sstevel@tonic-gate "configure", 4, 0, 4, /* 13 */ 2007c478bd9Sstevel@tonic-gate /* relative seek */ 2017c478bd9Sstevel@tonic-gate }; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate static int 2057c478bd9Sstevel@tonic-gate fdc_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 2067c478bd9Sstevel@tonic-gate static int get_ioaddr(dev_info_t *dip, int *ioaddr); 2077c478bd9Sstevel@tonic-gate static int get_unit(dev_info_t *dip, int *cntrl_num); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate struct bus_ops fdc_bus_ops = { 2107c478bd9Sstevel@tonic-gate BUSO_REV, 2117c478bd9Sstevel@tonic-gate nullbusmap, 2127c478bd9Sstevel@tonic-gate 0, /* ddi_intrspec_t (*bus_get_intrspec)(); */ 2137c478bd9Sstevel@tonic-gate 0, /* int (*bus_add_intrspec)(); */ 2147c478bd9Sstevel@tonic-gate 0, /* void (*bus_remove_intrspec)(); */ 2157c478bd9Sstevel@tonic-gate i_ddi_map_fault, 2167c478bd9Sstevel@tonic-gate ddi_dma_map, 2177c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 2187c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 2197c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 2207c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 2217c478bd9Sstevel@tonic-gate ddi_dma_flush, 2227c478bd9Sstevel@tonic-gate ddi_dma_win, 2237c478bd9Sstevel@tonic-gate ddi_dma_mctl, 2247c478bd9Sstevel@tonic-gate fdc_bus_ctl, 2257c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 2267c478bd9Sstevel@tonic-gate }; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate static int fdc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 2297c478bd9Sstevel@tonic-gate static int fdc_probe(dev_info_t *); 2307c478bd9Sstevel@tonic-gate static int fdc_attach(dev_info_t *, ddi_attach_cmd_t); 2317c478bd9Sstevel@tonic-gate static int fdc_detach(dev_info_t *, ddi_detach_cmd_t); 232*19397407SSherry Moore static int fdc_quiesce(dev_info_t *); 2337c478bd9Sstevel@tonic-gate static int fdc_enhance_probe(struct fdcntlr *fcp); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate struct dev_ops fdc_ops = { 2367c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 2377c478bd9Sstevel@tonic-gate 0, /* refcnt */ 2387c478bd9Sstevel@tonic-gate fdc_getinfo, /* getinfo */ 2397c478bd9Sstevel@tonic-gate nulldev, /* identify */ 2407c478bd9Sstevel@tonic-gate fdc_probe, /* probe */ 2417c478bd9Sstevel@tonic-gate fdc_attach, /* attach */ 2427c478bd9Sstevel@tonic-gate fdc_detach, /* detach */ 2437c478bd9Sstevel@tonic-gate nodev, /* reset */ 2447c478bd9Sstevel@tonic-gate (struct cb_ops *)0, /* driver operations */ 245*19397407SSherry Moore &fdc_bus_ops, /* bus operations */ 246*19397407SSherry Moore NULL, /* power */ 247*19397407SSherry Moore fdc_quiesce, /* quiesce */ 2487c478bd9Sstevel@tonic-gate }; 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * This is the loadable module wrapper. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 2587c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 259*19397407SSherry Moore "Floppy Controller", /* Name of the module. */ 2607c478bd9Sstevel@tonic-gate &fdc_ops, /* Driver ops vector */ 2617c478bd9Sstevel@tonic-gate }; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 2647c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 2657c478bd9Sstevel@tonic-gate }; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate int 2687c478bd9Sstevel@tonic-gate _init(void) 2697c478bd9Sstevel@tonic-gate { 2707c478bd9Sstevel@tonic-gate int retval; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate if ((retval = ddi_soft_state_init(&fdc_state_head, 2737c478bd9Sstevel@tonic-gate sizeof (struct fdcntlr) + NFDUN * sizeof (struct fcu_obj), 0)) != 0) 2747c478bd9Sstevel@tonic-gate return (retval); 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate if ((retval = mod_install(&modlinkage)) != 0) 2777c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&fdc_state_head); 2787c478bd9Sstevel@tonic-gate return (retval); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate int 2827c478bd9Sstevel@tonic-gate _fini(void) 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate int retval; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate if ((retval = mod_remove(&modlinkage)) != 0) 2877c478bd9Sstevel@tonic-gate return (retval); 2887c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&fdc_state_head); 2897c478bd9Sstevel@tonic-gate return (retval); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate int 2937c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2947c478bd9Sstevel@tonic-gate { 2957c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate int fdc_start(struct fcu_obj *); 3007c478bd9Sstevel@tonic-gate int fdc_abort(struct fcu_obj *); 3017c478bd9Sstevel@tonic-gate int fdc_getcap(struct fcu_obj *, char *, int); 3027c478bd9Sstevel@tonic-gate int fdc_setcap(struct fcu_obj *, char *, int, int); 3037c478bd9Sstevel@tonic-gate int fdc_dkinfo(struct fcu_obj *, struct dk_cinfo *); 3047c478bd9Sstevel@tonic-gate int fdc_select(struct fcu_obj *, int, int); 3057c478bd9Sstevel@tonic-gate int fdgetchng(struct fcu_obj *, int); 3067c478bd9Sstevel@tonic-gate int fdresetchng(struct fcu_obj *, int); 3077c478bd9Sstevel@tonic-gate int fdrecalseek(struct fcu_obj *, int, int, int); 3087c478bd9Sstevel@tonic-gate int fdrw(struct fcu_obj *, int, int, int, int, int, caddr_t, uint_t); 3097c478bd9Sstevel@tonic-gate int fdtrkformat(struct fcu_obj *, int, int, int, int); 3107c478bd9Sstevel@tonic-gate int fdrawioctl(struct fcu_obj *, int, caddr_t); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate static struct fcobjops fdc_iops = { 3137c478bd9Sstevel@tonic-gate fdc_start, /* controller start */ 3147c478bd9Sstevel@tonic-gate fdc_abort, /* controller abort */ 3157c478bd9Sstevel@tonic-gate fdc_getcap, /* capability retrieval */ 3167c478bd9Sstevel@tonic-gate fdc_setcap, /* capability establishment */ 3177c478bd9Sstevel@tonic-gate fdc_dkinfo, /* get disk controller info */ 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate fdc_select, /* select / deselect unit */ 3207c478bd9Sstevel@tonic-gate fdgetchng, /* get media change */ 3217c478bd9Sstevel@tonic-gate fdresetchng, /* reset media change */ 3227c478bd9Sstevel@tonic-gate fdrecalseek, /* recal / seek */ 3233dda9c1fSmrj NULL, /* read /write request (UNUSED) */ 3247c478bd9Sstevel@tonic-gate fdrw, /* read /write sector */ 3257c478bd9Sstevel@tonic-gate fdtrkformat, /* format track */ 3267c478bd9Sstevel@tonic-gate fdrawioctl /* raw ioctl */ 3277c478bd9Sstevel@tonic-gate }; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * Function prototypes 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate void encode(xlate_tbl_t *tablep, int val, uchar_t *rcode); 3347c478bd9Sstevel@tonic-gate int decode(xlate_tbl_t *, int, int *); 3357c478bd9Sstevel@tonic-gate static int fdc_propinit1(struct fdcntlr *, int); 3367c478bd9Sstevel@tonic-gate static void fdc_propinit2(struct fdcntlr *, int); 3377c478bd9Sstevel@tonic-gate void fdcquiesce(struct fdcntlr *); 3387c478bd9Sstevel@tonic-gate int fdcsense_chng(struct fdcntlr *, int); 3397c478bd9Sstevel@tonic-gate int fdcsense_drv(struct fdcntlr *, int); 3407c478bd9Sstevel@tonic-gate int fdcsense_int(struct fdcntlr *, int *, int *); 3417c478bd9Sstevel@tonic-gate int fdcspecify(struct fdcntlr *, int, int, int); 3427c478bd9Sstevel@tonic-gate int fdcspdchange(struct fdcntlr *, struct fcu_obj *, int); 3437c478bd9Sstevel@tonic-gate static int fdc_exec(struct fdcntlr *, int, int); 3447c478bd9Sstevel@tonic-gate int fdcheckdisk(struct fdcntlr *, int); 3457c478bd9Sstevel@tonic-gate static uint_t fdc_intr(caddr_t arg); 3467c478bd9Sstevel@tonic-gate static void fdwatch(void *arg); 3477c478bd9Sstevel@tonic-gate static void fdmotort(void *arg); 3487c478bd9Sstevel@tonic-gate static int fdrecover(struct fdcntlr *); 3497c478bd9Sstevel@tonic-gate static int fdc_motorsm(struct fcu_obj *, int, int); 3507c478bd9Sstevel@tonic-gate static int fdc_statemach(struct fdcntlr *); 3517c478bd9Sstevel@tonic-gate int fdc_docmd(struct fdcntlr *, uchar_t *, uchar_t); 3527c478bd9Sstevel@tonic-gate int fdc_result(struct fdcntlr *, uchar_t *, uchar_t); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3567c478bd9Sstevel@tonic-gate static int 3577c478bd9Sstevel@tonic-gate fdc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 3587c478bd9Sstevel@tonic-gate void *arg, void *result) 3597c478bd9Sstevel@tonic-gate { 3607c478bd9Sstevel@tonic-gate struct fdcntlr *fcp; 3617c478bd9Sstevel@tonic-gate struct fcu_obj *fjp; 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_ATTA, 3647c478bd9Sstevel@tonic-gate (CE_CONT, "fdc_bus_ctl: cmd= %x\n", ctlop)); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate if ((fcp = ddi_get_driver_private(dip)) == NULL) 3677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate switch (ctlop) { 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 3727c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s%d at %s%d\n", 3737c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 3747c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip)); 3757c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, 3767c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_bus_ctl: report %s%d at %s%d", 3777c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 3787c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip))); 3797c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate dev_info_t *udip = (dev_info_t *)arg; 3847c478bd9Sstevel@tonic-gate int cntlr; 3857c478bd9Sstevel@tonic-gate int len; 3867c478bd9Sstevel@tonic-gate int unit; 3877c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, 3907c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_bus_ctl: init child 0x%p", (void*)udip)); 3917c478bd9Sstevel@tonic-gate cntlr = fcp->c_number; 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate len = sizeof (unit); 3947c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, udip, PROP_LEN_AND_VAL_BUF, 3957c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit", (caddr_t)&unit, &len) 3967c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS || 3977c478bd9Sstevel@tonic-gate cntlr != FDCTLR(unit) || 3987c478bd9Sstevel@tonic-gate (fcp->c_unit[FDUNIT(unit)])->fj_dip) 3997c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate (void) sprintf(name, "%d,%d", cntlr, FDUNIT(unit)); 4027c478bd9Sstevel@tonic-gate ddi_set_name_addr(udip, name); 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate fjp = fcp->c_unit[FDUNIT(unit)]; 4057c478bd9Sstevel@tonic-gate fjp->fj_unit = unit; 4067c478bd9Sstevel@tonic-gate fjp->fj_dip = udip; 4077c478bd9Sstevel@tonic-gate fjp->fj_ops = &fdc_iops; 4087c478bd9Sstevel@tonic-gate fjp->fj_fdc = fcp; 4097c478bd9Sstevel@tonic-gate fjp->fj_iblock = &fcp->c_iblock; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate ddi_set_driver_private(udip, fjp); 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate dev_info_t *udip = (dev_info_t *)arg; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, 4207c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_bus_ctl: uninit child 0x%p", (void *)udip)); 4217c478bd9Sstevel@tonic-gate fjp = ddi_get_driver_private(udip); 4227c478bd9Sstevel@tonic-gate ddi_set_driver_private(udip, NULL); 4237c478bd9Sstevel@tonic-gate fjp->fj_dip = NULL; 4247c478bd9Sstevel@tonic-gate ddi_set_name_addr(udip, NULL); 4257c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate default: 4287c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4337c478bd9Sstevel@tonic-gate static int 4347c478bd9Sstevel@tonic-gate fdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate struct fdcntlr *fcp; 4377c478bd9Sstevel@tonic-gate int rval; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate switch (cmd) { 4407c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 4417c478bd9Sstevel@tonic-gate if (fcp = ddi_get_soft_state(fdc_state_head, (dev_t)arg)) { 4427c478bd9Sstevel@tonic-gate *result = fcp->c_dip; 4437c478bd9Sstevel@tonic-gate rval = DDI_SUCCESS; 4447c478bd9Sstevel@tonic-gate break; 4457c478bd9Sstevel@tonic-gate } else { 4467c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 4477c478bd9Sstevel@tonic-gate break; 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 4507c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)getminor((dev_t)arg); 4517c478bd9Sstevel@tonic-gate rval = DDI_SUCCESS; 4527c478bd9Sstevel@tonic-gate break; 4537c478bd9Sstevel@tonic-gate default: 4547c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate return (rval); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate static int 4607c478bd9Sstevel@tonic-gate fdc_probe(dev_info_t *dip) 4617c478bd9Sstevel@tonic-gate { 4627c478bd9Sstevel@tonic-gate int debug[2]; 4637c478bd9Sstevel@tonic-gate int ioaddr; 4647c478bd9Sstevel@tonic-gate int len; 4657c478bd9Sstevel@tonic-gate uchar_t stat; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate len = sizeof (debug); 4687c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 4697c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) == 4707c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) { 4717c478bd9Sstevel@tonic-gate fcerrlevel = debug[0]; 4727c478bd9Sstevel@tonic-gate fcerrmask = (uint_t)debug[1]; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_probe: dip %p", 4767c478bd9Sstevel@tonic-gate (void*)dip)); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS) 4797c478bd9Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate stat = inb(ioaddr + FCR_MSR); 4827c478bd9Sstevel@tonic-gate if ((stat & (MS_RQM | MS_DIO | MS_CB)) != MS_RQM && 4837c478bd9Sstevel@tonic-gate (stat & ~MS_DIO) != MS_CB) 4847c478bd9Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4907c478bd9Sstevel@tonic-gate static int 4917c478bd9Sstevel@tonic-gate fdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4927c478bd9Sstevel@tonic-gate { 4937c478bd9Sstevel@tonic-gate struct fdcntlr *fcp; 4947c478bd9Sstevel@tonic-gate struct fcu_obj *fjp; 4957c478bd9Sstevel@tonic-gate int cntlr_num, ctlr, unit; 4967c478bd9Sstevel@tonic-gate int intr_set = 0; 4977c478bd9Sstevel@tonic-gate int len; 4987c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_attach: dip %p", 5017c478bd9Sstevel@tonic-gate (void*)dip)); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate switch (cmd) { 5047c478bd9Sstevel@tonic-gate case DDI_ATTACH: 5057c478bd9Sstevel@tonic-gate if (ddi_getprop 5067c478bd9Sstevel@tonic-gate (DDI_DEV_T_ANY, dip, 0, "ignore-hardware-nodes", 0)) { 5077c478bd9Sstevel@tonic-gate len = sizeof (cntlr_num); 5087c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, 5097c478bd9Sstevel@tonic-gate PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "unit", 5107c478bd9Sstevel@tonic-gate (caddr_t)&cntlr_num, &len) != DDI_PROP_SUCCESS) { 5117c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, 5127c478bd9Sstevel@tonic-gate "fdc_attach failed: dip %p", (void*)dip)); 5137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate } else { 5167c478bd9Sstevel@tonic-gate if (get_unit(dip, &cntlr_num) != DDI_SUCCESS) 5177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate ctlr = ddi_get_instance(dip); 5217c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(fdc_state_head, ctlr) != 0) 5227c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5237c478bd9Sstevel@tonic-gate fcp = ddi_get_soft_state(fdc_state_head, ctlr); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate for (unit = 0, fjp = (struct fcu_obj *)(fcp+1); 5267c478bd9Sstevel@tonic-gate unit < NFDUN; unit++) { 5277c478bd9Sstevel@tonic-gate fcp->c_unit[unit] = fjp++; 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate fcp->c_dip = dip; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if (fdc_propinit1(fcp, cntlr_num) != DDI_SUCCESS) 5327c478bd9Sstevel@tonic-gate goto no_attach; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* get iblock cookie to initialize mutex used in the ISR */ 5357c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, (uint_t)0, &fcp->c_iblock) != 5367c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 5377c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5387c478bd9Sstevel@tonic-gate "fdc_attach: cannot get iblock cookie"); 5397c478bd9Sstevel@tonic-gate goto no_attach; 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate mutex_init(&fcp->c_lock, NULL, MUTEX_DRIVER, fcp->c_iblock); 5427c478bd9Sstevel@tonic-gate intr_set = 1; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate /* setup interrupt handler */ 5457c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, (uint_t)0, NULL, 5467c478bd9Sstevel@tonic-gate (ddi_idevice_cookie_t *)0, fdc_intr, (caddr_t)fcp) != 5477c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 5487c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: cannot add intr\n"); 5497c478bd9Sstevel@tonic-gate goto no_attach; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate intr_set++; 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * acquire the DMA channel 5557c478bd9Sstevel@tonic-gate * this assumes that the chnl is not shared; else allocate 5567c478bd9Sstevel@tonic-gate * and free the chnl with each fdc request 5577c478bd9Sstevel@tonic-gate */ 5587c478bd9Sstevel@tonic-gate if (ddi_dmae_alloc(dip, fcp->c_dmachan, DDI_DMA_DONTWAIT, NULL) 5597c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 5607c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: cannot acquire dma%d\n", 5617c478bd9Sstevel@tonic-gate fcp->c_dmachan); 5627c478bd9Sstevel@tonic-gate goto no_attach; 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate (void) ddi_dmae_getattr(dip, &fdc_dma_attr); 5653dda9c1fSmrj fdc_dma_attr.dma_attr_align = MMU_PAGESIZE; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate mutex_init(&fcp->c_dorlock, NULL, MUTEX_DRIVER, fcp->c_iblock); 5687c478bd9Sstevel@tonic-gate cv_init(&fcp->c_iocv, NULL, CV_DRIVER, fcp->c_iblock); 5697c478bd9Sstevel@tonic-gate sema_init(&fcp->c_selsem, 1, NULL, SEMA_DRIVER, NULL); 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate (void) sprintf(name, "fdc%d", ctlr); 5727c478bd9Sstevel@tonic-gate fcp->c_intrstat = kstat_create("fdc", ctlr, name, 5737c478bd9Sstevel@tonic-gate "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 5747c478bd9Sstevel@tonic-gate if (fcp->c_intrstat) { 5757c478bd9Sstevel@tonic-gate kstat_install(fcp->c_intrstat); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, fcp); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * reset the controller 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate sema_p(&fcp->c_selsem); 5847c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 5857c478bd9Sstevel@tonic-gate fcp->c_csb.csb_xstate = FXS_RESET; 5867c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 5877c478bd9Sstevel@tonic-gate fdcquiesce(fcp); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* first test for mode == Model 30 */ 5907c478bd9Sstevel@tonic-gate fcp->c_mode = (inb(fcp->c_regbase + FCR_SRB) & 0x1c) ? 5917c478bd9Sstevel@tonic-gate FDCMODE_AT : FDCMODE_30; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate while (fcp->c_flags & FCFLG_WAITING) { 5947c478bd9Sstevel@tonic-gate cv_wait(&fcp->c_iocv, &fcp->c_lock); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 5977c478bd9Sstevel@tonic-gate sema_v(&fcp->c_selsem); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate fdc_propinit2(fcp, cntlr_num); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 6027c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6037c478bd9Sstevel@tonic-gate 6042df1fe9cSrandyf case DDI_RESUME: 6052df1fe9cSrandyf return (DDI_SUCCESS); 6062df1fe9cSrandyf /* break; */ 6072df1fe9cSrandyf 6087c478bd9Sstevel@tonic-gate default: 6097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate no_attach: 6137c478bd9Sstevel@tonic-gate if (intr_set) { 6147c478bd9Sstevel@tonic-gate if (intr_set > 1) 6157c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, fcp->c_iblock); 6167c478bd9Sstevel@tonic-gate mutex_destroy(&fcp->c_lock); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate ddi_soft_state_free(fdc_state_head, cntlr_num); 6197c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate static int 6237c478bd9Sstevel@tonic-gate fdc_propinit1(struct fdcntlr *fcp, int cntlr) 6247c478bd9Sstevel@tonic-gate { 6257c478bd9Sstevel@tonic-gate dev_info_t *dip; 6267c478bd9Sstevel@tonic-gate int len; 6277c478bd9Sstevel@tonic-gate int value; 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate dip = fcp->c_dip; 6307c478bd9Sstevel@tonic-gate len = sizeof (value); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate if (get_ioaddr(dip, &value) != DDI_SUCCESS) 6337c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate fcp->c_regbase = (ushort_t)value; 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 6387c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "dma-channels", (caddr_t)&value, &len) 6397c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 6407c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6417c478bd9Sstevel@tonic-gate "fdc_attach: Error, could not find a dma channel"); 6427c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate fcp->c_dmachan = (ushort_t)value; 6457c478bd9Sstevel@tonic-gate fcp->c_number = cntlr; 6467c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6507c478bd9Sstevel@tonic-gate static void 6517c478bd9Sstevel@tonic-gate fdc_propinit2(struct fdcntlr *fcp, int cntlr) 6527c478bd9Sstevel@tonic-gate { 6537c478bd9Sstevel@tonic-gate dev_info_t *dip; 6547c478bd9Sstevel@tonic-gate int ccr; 6557c478bd9Sstevel@tonic-gate int len; 6567c478bd9Sstevel@tonic-gate int value; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate dip = fcp->c_dip; 6597c478bd9Sstevel@tonic-gate len = sizeof (value); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 6627c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "chip", (caddr_t)&value, &len) 6637c478bd9Sstevel@tonic-gate == DDI_PROP_SUCCESS) 6647c478bd9Sstevel@tonic-gate fcp->c_chip = value; 6657c478bd9Sstevel@tonic-gate else { 6667c478bd9Sstevel@tonic-gate static uchar_t perpindcmd[2] = {FO_PERP, 0}; 6677c478bd9Sstevel@tonic-gate static uchar_t versioncmd = FO_VRSN; 6687c478bd9Sstevel@tonic-gate uchar_t result; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate fcp->c_chip = i8272A; 6717c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, &versioncmd, 1); 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 6747c478bd9Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate if (!fdc_result(fcp, &result, 1) && result == 0x90) { 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * try a perpendicular_mode cmd to ensure 6797c478bd9Sstevel@tonic-gate * that we really have an enhanced controller 6807c478bd9Sstevel@tonic-gate */ 6817c478bd9Sstevel@tonic-gate if (fdc_docmd(fcp, perpindcmd, 2) || 6827c478bd9Sstevel@tonic-gate fdc_docmd(fcp, configurecmd, 4)) 6837c478bd9Sstevel@tonic-gate /* 6847c478bd9Sstevel@tonic-gate * perpindicular_mode will be rejected by 6857c478bd9Sstevel@tonic-gate * older controllers; make sure we don't hang. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate (void) fdc_result(fcp, &result, 1); 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was 6907c478bd9Sstevel@tonic-gate * issued by fdc_result. 6917c478bd9Sstevel@tonic-gate */ 6927c478bd9Sstevel@tonic-gate else 6937c478bd9Sstevel@tonic-gate /* enhanced type controller */ 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate if ((fcp->c_chip = fdc_enhance_probe(fcp)) == 0) 6967c478bd9Sstevel@tonic-gate /* default enhanced cntlr */ 6977c478bd9Sstevel@tonic-gate fcp->c_chip = i82077; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 7007c478bd9Sstevel@tonic-gate "chip", fcp->c_chip); 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Ignoring return value because, for passed arguments, only 7037c478bd9Sstevel@tonic-gate * DDI_SUCCESS is returned. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate if (fcp->c_chip >= i82077 && fcp->c_mode == FDCMODE_30 && 7077c478bd9Sstevel@tonic-gate (inb(fcp->c_regbase + FCR_DIR) & 0x70) == 0) 7087c478bd9Sstevel@tonic-gate for (ccr = 0; ccr <= (FCC_NOPREC | FCC_DRATE); ccr++) { 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * run through all the combinations of NOPREC and 7117c478bd9Sstevel@tonic-gate * datarate selection, and see if they show up in the 7127c478bd9Sstevel@tonic-gate * Model 30 DIR 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_CCR, ccr); 7157c478bd9Sstevel@tonic-gate drv_usecwait(5); 7167c478bd9Sstevel@tonic-gate if ((inb(fcp->c_regbase + FCR_DIR) & 7177c478bd9Sstevel@tonic-gate (FCC_NOPREC | FCC_DRATE)) != ccr) { 7187c478bd9Sstevel@tonic-gate fcp->c_mode = FDCMODE_AT; 7197c478bd9Sstevel@tonic-gate break; 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate else 7237c478bd9Sstevel@tonic-gate fcp->c_mode = FDCMODE_AT; 7247c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_CCR, 0); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7287c478bd9Sstevel@tonic-gate static int 7297c478bd9Sstevel@tonic-gate fdc_enhance_probe(struct fdcntlr *fcp) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate static uchar_t nsccmd = FO_NSC; 7327c478bd9Sstevel@tonic-gate uint_t ddic; 7337c478bd9Sstevel@tonic-gate int retcode = 0; 7347c478bd9Sstevel@tonic-gate uchar_t result; 7357c478bd9Sstevel@tonic-gate uchar_t save; 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * Try to identify the enhanced floppy controller. 7397c478bd9Sstevel@tonic-gate * This is required so that we can program the DENSEL output to 7407c478bd9Sstevel@tonic-gate * control 3D mode (1.0 MB, 1.6 MB and 2.0 MB unformatted capacity, 7417c478bd9Sstevel@tonic-gate * 720 KB, 1.2 MB, and 1.44 MB formatted capacity) 3.5" dual-speed 7427c478bd9Sstevel@tonic-gate * floppy drives. Refer to bugid 1195155. 7437c478bd9Sstevel@tonic-gate */ 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, &nsccmd, 1); 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 7487c478bd9Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 7497c478bd9Sstevel@tonic-gate */ 7507c478bd9Sstevel@tonic-gate if (!fdc_result(fcp, &result, 1) && result != S0_IVCMD) { 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * only enhanced National Semi PC8477 core 7537c478bd9Sstevel@tonic-gate * should respond to this command 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate if ((result & 0xf0) == 0x70) { 7567c478bd9Sstevel@tonic-gate /* low 4 bits may change */ 7577c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_3DMODE; 7587c478bd9Sstevel@tonic-gate retcode = PC87322; 7597c478bd9Sstevel@tonic-gate } else 7607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 7617c478bd9Sstevel@tonic-gate "?fdc: unidentified, enhanced, National Semiconductor cntlr %x\n", result); 7627c478bd9Sstevel@tonic-gate } else { 7637c478bd9Sstevel@tonic-gate save = inb(fcp->c_regbase + FCR_SRA); 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate do { 7667c478bd9Sstevel@tonic-gate /* probe for motherboard version of SMC cntlr */ 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate /* try to enable configuration mode */ 7697c478bd9Sstevel@tonic-gate ddic = ddi_enter_critical(); 7707c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 7717c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 7727c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0F); 7757c478bd9Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 7767c478bd9Sstevel@tonic-gate /* always expect 0 from config reg F */ 7777c478bd9Sstevel@tonic-gate break; 7787c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0D); 7797c478bd9Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x65) 7807c478bd9Sstevel@tonic-gate /* expect 0x65 from config reg D */ 7817c478bd9Sstevel@tonic-gate break; 7827c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0E); 7837c478bd9Sstevel@tonic-gate result = inb(fcp->c_regbase + FCR_SRB); 7847c478bd9Sstevel@tonic-gate if (result != 0x02) { 7857c478bd9Sstevel@tonic-gate /* expect revision level 2 from config reg E */ 7867c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 7877c478bd9Sstevel@tonic-gate "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 7887c478bd9Sstevel@tonic-gate /* break; */ 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_3DMODE; 7917c478bd9Sstevel@tonic-gate retcode = FDC37C665; 7927c478bd9Sstevel@tonic-gate } while (retcode == 0); 7937c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate while (retcode == 0) { 7967c478bd9Sstevel@tonic-gate /* probe for adapter version of SMC cntlr */ 7977c478bd9Sstevel@tonic-gate ddic = ddi_enter_critical(); 7987c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 7997c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 8007c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0F); 8037c478bd9Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 8047c478bd9Sstevel@tonic-gate /* always expect 0 from config reg F */ 8057c478bd9Sstevel@tonic-gate break; 8067c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0D); 8077c478bd9Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x66) 8087c478bd9Sstevel@tonic-gate /* expect 0x66 from config reg D */ 8097c478bd9Sstevel@tonic-gate break; 8107c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0E); 8117c478bd9Sstevel@tonic-gate result = inb(fcp->c_regbase + FCR_SRB); 8127c478bd9Sstevel@tonic-gate if (result != 0x02) { 8137c478bd9Sstevel@tonic-gate /* expect revision level 2 from config reg E */ 8147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 8157c478bd9Sstevel@tonic-gate "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 8167c478bd9Sstevel@tonic-gate /* break; */ 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_3DMODE; 8197c478bd9Sstevel@tonic-gate retcode = FDC37C666; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate drv_usecwait(10); 8247c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, save); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate return (retcode); 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8307c478bd9Sstevel@tonic-gate static int 8317c478bd9Sstevel@tonic-gate fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 8327c478bd9Sstevel@tonic-gate { 8337c478bd9Sstevel@tonic-gate struct fdcntlr *fcp; 8342df1fe9cSrandyf struct fcu_obj *fjp; 8357c478bd9Sstevel@tonic-gate int unit; 8367c478bd9Sstevel@tonic-gate int rval = 0; 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_detach: dip %p", 8397c478bd9Sstevel@tonic-gate (void*)dip)); 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate fcp = ddi_get_driver_private(dip); 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate switch (cmd) { 8447c478bd9Sstevel@tonic-gate case DDI_DETACH: 8457c478bd9Sstevel@tonic-gate for (unit = 0; unit < NFDUN; unit++) 8467c478bd9Sstevel@tonic-gate if ((fcp->c_unit[unit])->fj_dip) { 8477c478bd9Sstevel@tonic-gate rval = EBUSY; 8487c478bd9Sstevel@tonic-gate break; 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate kstat_delete(fcp->c_intrstat); 8517c478bd9Sstevel@tonic-gate fcp->c_intrstat = NULL; 8527c478bd9Sstevel@tonic-gate ddi_remove_intr(fcp->c_dip, 0, fcp->c_iblock); 8537c478bd9Sstevel@tonic-gate if (ddi_dmae_release(fcp->c_dip, fcp->c_dmachan) != 8547c478bd9Sstevel@tonic-gate DDI_SUCCESS) 8557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc_detach: dma release failed, " 8567c478bd9Sstevel@tonic-gate "dip %p, dmachan %x\n", 8577c478bd9Sstevel@tonic-gate (void*)fcp->c_dip, fcp->c_dmachan); 8587c478bd9Sstevel@tonic-gate ddi_prop_remove_all(fcp->c_dip); 8597c478bd9Sstevel@tonic-gate ddi_set_driver_private(fcp->c_dip, NULL); 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate mutex_destroy(&fcp->c_lock); 8627c478bd9Sstevel@tonic-gate mutex_destroy(&fcp->c_dorlock); 8637c478bd9Sstevel@tonic-gate cv_destroy(&fcp->c_iocv); 8647c478bd9Sstevel@tonic-gate sema_destroy(&fcp->c_selsem); 8657c478bd9Sstevel@tonic-gate ddi_soft_state_free(fdc_state_head, ddi_get_instance(dip)); 8667c478bd9Sstevel@tonic-gate break; 8672df1fe9cSrandyf 8682df1fe9cSrandyf case DDI_SUSPEND: 8692df1fe9cSrandyf /* 8702df1fe9cSrandyf * Following code causes the fdc (floppy controller) 8712df1fe9cSrandyf * to suspend as long as there are no floppy drives 8722df1fe9cSrandyf * attached to it. 8732df1fe9cSrandyf * At present the floppy driver does not support 8742df1fe9cSrandyf * SUSPEND/RESUME. 8752df1fe9cSrandyf * 8762df1fe9cSrandyf * Check if any FD units are attached 8772df1fe9cSrandyf * 8782df1fe9cSrandyf * For now, SUSPEND/RESUME is not supported 8792df1fe9cSrandyf * if a floppy drive is present. 8802df1fe9cSrandyf * So if any FD unit is attached return DDI_FAILURE 8812df1fe9cSrandyf */ 8822df1fe9cSrandyf for (unit = 0; unit < NFDUN; unit++) { 8832df1fe9cSrandyf fjp = fcp->c_unit[unit]; 8842df1fe9cSrandyf if (fjp->fj_flags & FUNIT_DRVATCH) { 8852df1fe9cSrandyf cmn_err(CE_WARN, 8862df1fe9cSrandyf "fdc_detach: fd attached, failing SUSPEND"); 8872df1fe9cSrandyf return (DDI_FAILURE); 8882df1fe9cSrandyf } 8892df1fe9cSrandyf } 8902df1fe9cSrandyf 8912df1fe9cSrandyf cmn_err(CE_NOTE, "fdc_detach: SUSPEND fdc"); 8922df1fe9cSrandyf 8932df1fe9cSrandyf rval = DDI_SUCCESS; 8942df1fe9cSrandyf break; 8952df1fe9cSrandyf 8967c478bd9Sstevel@tonic-gate default: 8977c478bd9Sstevel@tonic-gate rval = EINVAL; 8987c478bd9Sstevel@tonic-gate break; 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate return (rval); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9057c478bd9Sstevel@tonic-gate int 9067c478bd9Sstevel@tonic-gate fdc_start(struct fcu_obj *fjp) 9077c478bd9Sstevel@tonic-gate { 9087c478bd9Sstevel@tonic-gate return (ENOSYS); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate int 9127c478bd9Sstevel@tonic-gate fdc_abort(struct fcu_obj *fjp) 9137c478bd9Sstevel@tonic-gate { 9147c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 9157c478bd9Sstevel@tonic-gate int unit = fjp->fj_unit & 3; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_RESE, (CE_WARN, "fdc_abort")); 9187c478bd9Sstevel@tonic-gate if (fcp->c_curunit == unit) { 9197c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 9207c478bd9Sstevel@tonic-gate if (fcp->c_flags & FCFLG_WAITING) { 9217c478bd9Sstevel@tonic-gate /* 9227c478bd9Sstevel@tonic-gate * this can cause data corruption ! 9237c478bd9Sstevel@tonic-gate */ 9247c478bd9Sstevel@tonic-gate fdcquiesce(fcp); 9257c478bd9Sstevel@tonic-gate fcp->c_csb.csb_xstate = FXS_RESET; 9267c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_TIMEOUT; 9277c478bd9Sstevel@tonic-gate if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != 9287c478bd9Sstevel@tonic-gate DDI_SUCCESS) 9297c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 9307c478bd9Sstevel@tonic-gate "fdc_detach: dma release failed, " 9317c478bd9Sstevel@tonic-gate "dip %p, dmachan %x\n", 9327c478bd9Sstevel@tonic-gate (void*)fcp->c_dip, fcp->c_dmachan); 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 9357c478bd9Sstevel@tonic-gate drv_usecwait(500); 9367c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9427c478bd9Sstevel@tonic-gate int 9437c478bd9Sstevel@tonic-gate fdc_getcap(struct fcu_obj *fjp, char *a, int i) 9447c478bd9Sstevel@tonic-gate { 9457c478bd9Sstevel@tonic-gate return (ENOSYS); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9497c478bd9Sstevel@tonic-gate int 9507c478bd9Sstevel@tonic-gate fdc_setcap(struct fcu_obj *fjp, char *a, int i, int j) 9517c478bd9Sstevel@tonic-gate { 9527c478bd9Sstevel@tonic-gate return (ENOSYS); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate int 9567c478bd9Sstevel@tonic-gate fdc_dkinfo(struct fcu_obj *fjp, struct dk_cinfo *dcp) 9577c478bd9Sstevel@tonic-gate { 9587c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate (void) strncpy((char *)&dcp->dki_cname, ddi_get_name(fcp->c_dip), 9617c478bd9Sstevel@tonic-gate DK_DEVLEN); 9627c478bd9Sstevel@tonic-gate dcp->dki_ctype = DKC_UNKNOWN; /* no code for generic PC/AT fdc */ 9637c478bd9Sstevel@tonic-gate dcp->dki_flags = DKI_FMTTRK; 9647c478bd9Sstevel@tonic-gate dcp->dki_addr = fcp->c_regbase; 9657c478bd9Sstevel@tonic-gate dcp->dki_space = 0; 9667c478bd9Sstevel@tonic-gate dcp->dki_prio = fcp->c_intprio; 9677c478bd9Sstevel@tonic-gate dcp->dki_vec = fcp->c_intvec; 9687c478bd9Sstevel@tonic-gate (void) strncpy((char *)&dcp->dki_dname, ddi_driver_name(fjp->fj_dip), 9697c478bd9Sstevel@tonic-gate DK_DEVLEN); 9707c478bd9Sstevel@tonic-gate dcp->dki_slave = fjp->fj_unit & 3; 9717c478bd9Sstevel@tonic-gate dcp->dki_maxtransfer = maxphys / DEV_BSIZE; 9727c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* 9767c478bd9Sstevel@tonic-gate * on=> non-zero = select, 0 = de-select 9777c478bd9Sstevel@tonic-gate */ 9787c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9797c478bd9Sstevel@tonic-gate int 9807c478bd9Sstevel@tonic-gate fdc_select(struct fcu_obj *fjp, int funit, int on) 9817c478bd9Sstevel@tonic-gate { 9827c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 9837c478bd9Sstevel@tonic-gate int unit = funit & 3; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate if (on) { 9867c478bd9Sstevel@tonic-gate /* possess controller */ 9877c478bd9Sstevel@tonic-gate sema_p(&fcp->c_selsem); 9887c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_DSEL, 9897c478bd9Sstevel@tonic-gate (CE_NOTE, "fdc_select unit %d: on", funit)); 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) { 9927c478bd9Sstevel@tonic-gate fcp->c_curunit = unit; 9937c478bd9Sstevel@tonic-gate fjp->fj_flags |= FUNIT_CHAROK; 9947c478bd9Sstevel@tonic-gate if (fdcspecify(fcp, 9957c478bd9Sstevel@tonic-gate fjp->fj_chars->fdc_transfer_rate, 9967c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_steprate, 40)) 9977c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 9987c478bd9Sstevel@tonic-gate "fdc_select: controller setup rejected " 9997c478bd9Sstevel@tonic-gate "fdcntrl %p transfer rate %x step rate %x" 10007c478bd9Sstevel@tonic-gate " head load time 40\n", (void*)fcp, 10017c478bd9Sstevel@tonic-gate fjp->fj_chars->fdc_transfer_rate, 10027c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_steprate); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* make sure drive is not selected in case we change speed */ 10087c478bd9Sstevel@tonic-gate fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | 10097c478bd9Sstevel@tonic-gate (~unit & FD_DRSEL); 10107c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_STARTCMD, 10137c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_motoron); 10147c478bd9Sstevel@tonic-gate /* 10157c478bd9Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) { 10187c478bd9Sstevel@tonic-gate /* 3D drive requires 500 ms for speed change */ 10197c478bd9Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5); 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | (unit & FD_DRSEL); 10267c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 10297c478bd9Sstevel@tonic-gate fcp->c_csb.csb_drive = (uchar_t)unit; 10307c478bd9Sstevel@tonic-gate } else { 10317c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_DSEL, 10327c478bd9Sstevel@tonic-gate (CE_NOTE, "fdc_select unit %d: off", funit)); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate fcp->c_digout |= FD_DRSEL; 10377c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 10387c478bd9Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_IDLECMD, 10397c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_motoroff); 10407c478bd9Sstevel@tonic-gate /* 10417c478bd9Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 10427c478bd9Sstevel@tonic-gate */ 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate /* give up controller */ 10477c478bd9Sstevel@tonic-gate sema_v(&fcp->c_selsem); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate return (0); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate int 10547c478bd9Sstevel@tonic-gate fdgetchng(struct fcu_obj *fjp, int funit) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate if (fdcsense_drv(fjp->fj_fdc, funit & 3)) 10577c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdgetchng: write protect check failed\n"); 10587c478bd9Sstevel@tonic-gate return (fdcsense_chng(fjp->fj_fdc, funit & 3)); 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate int 10637c478bd9Sstevel@tonic-gate fdresetchng(struct fcu_obj *fjp, int funit) 10647c478bd9Sstevel@tonic-gate { 10657c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 10667c478bd9Sstevel@tonic-gate int unit = funit & 3; 10677c478bd9Sstevel@tonic-gate int newcyl; /* where to seek for reset of DSKCHG */ 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_CHEK, (CE_NOTE, "fdmediachng unit %d", funit)); 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate if (fcp->c_curpcyl[unit]) 10727c478bd9Sstevel@tonic-gate newcyl = fcp->c_curpcyl[unit] - 1; 10737c478bd9Sstevel@tonic-gate else 10747c478bd9Sstevel@tonic-gate newcyl = 1; 10757c478bd9Sstevel@tonic-gate return (fdrecalseek(fjp, funit, newcyl, 0)); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * fdrecalseek 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate int 10837c478bd9Sstevel@tonic-gate fdrecalseek(struct fcu_obj *fjp, int funit, int arg, int execflg) 10847c478bd9Sstevel@tonic-gate { 10857c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 10867c478bd9Sstevel@tonic-gate struct fdcsb *csb; 10877c478bd9Sstevel@tonic-gate int unit = funit & 3; 10887c478bd9Sstevel@tonic-gate int rval; 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECA, (CE_NOTE, "fdrecalseek unit %d to %d", 10917c478bd9Sstevel@tonic-gate funit, arg)); 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate csb = &fcp->c_csb; 10947c478bd9Sstevel@tonic-gate csb->csb_cmd[1] = (uchar_t)unit; 10957c478bd9Sstevel@tonic-gate if (arg < 0) { /* is recal... */ 10967c478bd9Sstevel@tonic-gate *csb->csb_cmd = FO_RECAL; 10977c478bd9Sstevel@tonic-gate csb->csb_ncmds = 2; 10987c478bd9Sstevel@tonic-gate csb->csb_timer = 28; 10997c478bd9Sstevel@tonic-gate } else { 11007c478bd9Sstevel@tonic-gate *csb->csb_cmd = FO_SEEK; 11017c478bd9Sstevel@tonic-gate csb->csb_cmd[2] = (uchar_t)arg; 11027c478bd9Sstevel@tonic-gate csb->csb_ncmds = 3; 11037c478bd9Sstevel@tonic-gate csb->csb_timer = 10; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */ 11067c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFINRPT; 11077c478bd9Sstevel@tonic-gate csb->csb_maxretry = skretry; 11087c478bd9Sstevel@tonic-gate csb->csb_dmahandle = NULL; 11097c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 0; 11107c478bd9Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 11117c478bd9Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 11127c478bd9Sstevel@tonic-gate csb->csb_dmawincnt = 0; 11137c478bd9Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate /* send cmd off to fdc_exec */ 11167c478bd9Sstevel@tonic-gate if (rval = fdc_exec(fcp, 1, execflg)) 11177c478bd9Sstevel@tonic-gate goto out; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate if (!(*csb->csb_rslt & S0_SEKEND) || 11207c478bd9Sstevel@tonic-gate (*csb->csb_rslt & S0_ICMASK) || 11217c478bd9Sstevel@tonic-gate ((*csb->csb_rslt & S0_ECHK) && arg < 0) || 11227c478bd9Sstevel@tonic-gate csb->csb_cmdstat) 11237c478bd9Sstevel@tonic-gate rval = ENODEV; 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate if (fdcsense_drv(fcp, unit)) 11267c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdgetchng: write protect check failed\n"); 11277c478bd9Sstevel@tonic-gate out: 11287c478bd9Sstevel@tonic-gate return (rval); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate /* 11337c478bd9Sstevel@tonic-gate * fdrw- used only for read/writing sectors into/from kernel buffers. 11347c478bd9Sstevel@tonic-gate */ 11357c478bd9Sstevel@tonic-gate int 11367c478bd9Sstevel@tonic-gate fdrw(struct fcu_obj *fjp, int funit, int rw, int cyl, int head, 11377c478bd9Sstevel@tonic-gate int sector, caddr_t bufp, uint_t len) 11387c478bd9Sstevel@tonic-gate { 11397c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 11407c478bd9Sstevel@tonic-gate struct fdcsb *csb; 11417c478bd9Sstevel@tonic-gate uint_t dmar_flags = 0; 11427c478bd9Sstevel@tonic-gate int unit = funit & 3; 11437c478bd9Sstevel@tonic-gate int rval; 11443dda9c1fSmrj ddi_acc_handle_t mem_handle = NULL; 11453dda9c1fSmrj caddr_t aligned_buf; 11463dda9c1fSmrj size_t real_size; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RW, (CE_CONT, "fdrw unit %d\n", funit)); 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate csb = &fcp->c_csb; 11517c478bd9Sstevel@tonic-gate if (rw) { 11527c478bd9Sstevel@tonic-gate dmar_flags = DDI_DMA_READ; 11537c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFDMARD | CSB_OFINRPT; 11547c478bd9Sstevel@tonic-gate *csb->csb_cmd = FO_MT | FO_MFM | FO_SK | FO_RDDAT; 11557c478bd9Sstevel@tonic-gate } else { /* write */ 11567c478bd9Sstevel@tonic-gate dmar_flags = DDI_DMA_WRITE; 11577c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT; 11587c478bd9Sstevel@tonic-gate *csb->csb_cmd = FO_MT | FO_MFM | FO_WRDAT; 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate csb->csb_cmd[1] = (uchar_t)(unit | ((head & 0x1) << 2)); 11617c478bd9Sstevel@tonic-gate csb->csb_cmd[2] = (uchar_t)cyl; 11627c478bd9Sstevel@tonic-gate csb->csb_cmd[3] = (uchar_t)head; 11637c478bd9Sstevel@tonic-gate csb->csb_cmd[4] = (uchar_t)sector; 11647c478bd9Sstevel@tonic-gate encode(sector_size, fjp->fj_chars->fdc_sec_size, 11657c478bd9Sstevel@tonic-gate &csb->csb_cmd[5]); 11667c478bd9Sstevel@tonic-gate csb->csb_cmd[6] = (uchar_t)max(fjp->fj_chars->fdc_secptrack, sector); 11677c478bd9Sstevel@tonic-gate csb->csb_cmd[7] = fjp->fj_attr->fda_gapl; 11687c478bd9Sstevel@tonic-gate csb->csb_cmd[8] = 0xFF; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate csb->csb_ncmds = 9; 11717c478bd9Sstevel@tonic-gate csb->csb_nrslts = 7; 11727c478bd9Sstevel@tonic-gate csb->csb_timer = 36; 11737c478bd9Sstevel@tonic-gate if (rw == FDRDONE) 11747c478bd9Sstevel@tonic-gate csb->csb_maxretry = 1; 11757c478bd9Sstevel@tonic-gate else 11767c478bd9Sstevel@tonic-gate csb->csb_maxretry = rwretry; 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate csb->csb_dmahandle = NULL; 11797c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 0; 11807c478bd9Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 11817c478bd9Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 11827c478bd9Sstevel@tonic-gate csb->csb_dmawincnt = 0; 11837c478bd9Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 11847c478bd9Sstevel@tonic-gate dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL); 11857c478bd9Sstevel@tonic-gate 11863dda9c1fSmrj if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP, 11877c478bd9Sstevel@tonic-gate 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 11887c478bd9Sstevel@tonic-gate rval = EINVAL; 11897c478bd9Sstevel@tonic-gate goto out; 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate 11923dda9c1fSmrj /* 11933dda9c1fSmrj * allocate a page aligned buffer to dma to/from. This way we can 11943dda9c1fSmrj * ensure the cookie is a whole multiple of granularity and avoids 11953dda9c1fSmrj * any alignment issues. 11963dda9c1fSmrj */ 11973dda9c1fSmrj rval = ddi_dma_mem_alloc(csb->csb_dmahandle, len, &fdc_accattr, 11983dda9c1fSmrj DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &aligned_buf, 11993dda9c1fSmrj &real_size, &mem_handle); 12003dda9c1fSmrj if (rval != DDI_SUCCESS) { 12013dda9c1fSmrj rval = EINVAL; 12023dda9c1fSmrj goto out; 12033dda9c1fSmrj } 12043dda9c1fSmrj 12053dda9c1fSmrj if (dmar_flags & DDI_DMA_WRITE) { 12063dda9c1fSmrj bcopy(bufp, aligned_buf, len); 12073dda9c1fSmrj } 12083dda9c1fSmrj 12093dda9c1fSmrj rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, aligned_buf, 12103dda9c1fSmrj len, dmar_flags, DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, 12113dda9c1fSmrj &csb->csb_dmacookiecnt); 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate if (rval == DDI_DMA_MAPPED) { 12147c478bd9Sstevel@tonic-gate csb->csb_dmawincnt = 1; 12157c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 1; 12167c478bd9Sstevel@tonic-gate } else if (rval == DDI_DMA_PARTIAL_MAP) { 12177c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 1; 12187c478bd9Sstevel@tonic-gate if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != 12197c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 12207c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdrw: dma numwin failed\n"); 12217c478bd9Sstevel@tonic-gate rval = EINVAL; 12227c478bd9Sstevel@tonic-gate goto out; 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate } else { 12257c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 12262df1fe9cSrandyf "fdrw: dma addr bind handle failed, rval = %d\n", rval); 12277c478bd9Sstevel@tonic-gate rval = EINVAL; 12287c478bd9Sstevel@tonic-gate goto out; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate rval = fdc_exec(fcp, 1, 1); 12317c478bd9Sstevel@tonic-gate 12323dda9c1fSmrj if (dmar_flags & DDI_DMA_READ) { 12333dda9c1fSmrj bcopy(aligned_buf, bufp, len); 12343dda9c1fSmrj } 12353dda9c1fSmrj 12367c478bd9Sstevel@tonic-gate out: 12377c478bd9Sstevel@tonic-gate if (csb->csb_dmahandle) { 12387c478bd9Sstevel@tonic-gate if (csb->csb_handle_bound) { 12397c478bd9Sstevel@tonic-gate if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 12407c478bd9Sstevel@tonic-gate DDI_SUCCESS) 12417c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdrw: " 12427c478bd9Sstevel@tonic-gate "dma unbind handle failed\n"); 12437c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 0; 12447c478bd9Sstevel@tonic-gate } 12453dda9c1fSmrj if (mem_handle != NULL) { 12463dda9c1fSmrj ddi_dma_mem_free(&mem_handle); 12473dda9c1fSmrj } 12487c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&csb->csb_dmahandle); 12497c478bd9Sstevel@tonic-gate csb->csb_dmahandle = NULL; 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate return (rval); 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate int 12567c478bd9Sstevel@tonic-gate fdtrkformat(struct fcu_obj *fjp, int funit, int cyl, int head, int filldata) 12577c478bd9Sstevel@tonic-gate { 12587c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 12597c478bd9Sstevel@tonic-gate struct fdcsb *csb; 12607c478bd9Sstevel@tonic-gate int unit = funit & 3; 12617c478bd9Sstevel@tonic-gate int fmdatlen, lsector, lstart; 12627c478bd9Sstevel@tonic-gate int interleave, numsctr, offset, psector; 12637c478bd9Sstevel@tonic-gate uchar_t *dp; 12647c478bd9Sstevel@tonic-gate int rval; 12653dda9c1fSmrj ddi_acc_handle_t mem_handle = NULL; 12663dda9c1fSmrj caddr_t aligned_buf; 12673dda9c1fSmrj size_t real_size; 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_FORM, 12707c478bd9Sstevel@tonic-gate (CE_NOTE, "fdformattrk unit %d cyl=%d, hd=%d", funit, cyl, head)); 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate csb = &fcp->c_csb; 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate *csb->csb_cmd = FO_FRMT | FO_MFM; 12777c478bd9Sstevel@tonic-gate csb->csb_cmd[1] = (head << 2) | unit; 12787c478bd9Sstevel@tonic-gate encode(sector_size, fjp->fj_chars->fdc_sec_size, 12797c478bd9Sstevel@tonic-gate &csb->csb_cmd[2]); 12807c478bd9Sstevel@tonic-gate csb->csb_cmd[3] = numsctr = fjp->fj_chars->fdc_secptrack; 12817c478bd9Sstevel@tonic-gate csb->csb_cmd[4] = fjp->fj_attr->fda_gapf; 12827c478bd9Sstevel@tonic-gate csb->csb_cmd[5] = (uchar_t)filldata; 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate csb->csb_npcyl = (uchar_t)(cyl * fjp->fj_chars->fdc_steps); 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate csb->csb_dmahandle = NULL; 12877c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 0; 12887c478bd9Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 12897c478bd9Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 12907c478bd9Sstevel@tonic-gate csb->csb_dmawincnt = 0; 12917c478bd9Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 12927c478bd9Sstevel@tonic-gate csb->csb_ncmds = 6; 12937c478bd9Sstevel@tonic-gate csb->csb_nrslts = 7; 12947c478bd9Sstevel@tonic-gate csb->csb_timer = 32; 12957c478bd9Sstevel@tonic-gate csb->csb_maxretry = rwretry; 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate /* 12983dda9c1fSmrj * alloc space for format track cmd 12997c478bd9Sstevel@tonic-gate */ 13007c478bd9Sstevel@tonic-gate /* 13017c478bd9Sstevel@tonic-gate * NOTE: have to add size of fifo also - for dummy format action 13027c478bd9Sstevel@tonic-gate */ 13037c478bd9Sstevel@tonic-gate fmdatlen = 4 * numsctr; 13043dda9c1fSmrj 13053dda9c1fSmrj if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP, 13063dda9c1fSmrj 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 13073dda9c1fSmrj rval = EINVAL; 13083dda9c1fSmrj goto out; 13093dda9c1fSmrj } 13103dda9c1fSmrj 13113dda9c1fSmrj /* 13123dda9c1fSmrj * allocate a page aligned buffer to dma to/from. This way we can 13133dda9c1fSmrj * ensure the cookie is a whole multiple of granularity and avoids 13143dda9c1fSmrj * any alignment issues. 13153dda9c1fSmrj */ 13163dda9c1fSmrj rval = ddi_dma_mem_alloc(csb->csb_dmahandle, fmdatlen, &fdc_accattr, 13173dda9c1fSmrj DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &aligned_buf, 13183dda9c1fSmrj &real_size, &mem_handle); 13193dda9c1fSmrj if (rval != DDI_SUCCESS) { 13203dda9c1fSmrj rval = EINVAL; 13213dda9c1fSmrj goto out; 13223dda9c1fSmrj } 13233dda9c1fSmrj dp = (uchar_t *)aligned_buf; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate interleave = fjp->fj_attr->fda_intrlv; 13267c478bd9Sstevel@tonic-gate offset = (numsctr + interleave - 1) / interleave; 13277c478bd9Sstevel@tonic-gate for (psector = lstart = 1; 13287c478bd9Sstevel@tonic-gate psector <= numsctr; psector += interleave, lstart++) { 13297c478bd9Sstevel@tonic-gate for (lsector = lstart; lsector <= numsctr; lsector += offset) { 13307c478bd9Sstevel@tonic-gate *dp++ = (uchar_t)cyl; 13317c478bd9Sstevel@tonic-gate *dp++ = (uchar_t)head; 13327c478bd9Sstevel@tonic-gate *dp++ = (uchar_t)lsector; 13337c478bd9Sstevel@tonic-gate *dp++ = csb->csb_cmd[2]; 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13373dda9c1fSmrj rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, aligned_buf, 13383dda9c1fSmrj fmdatlen, DDI_DMA_WRITE | DDI_DMA_STREAMING | DDI_DMA_PARTIAL, 13393dda9c1fSmrj DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, &csb->csb_dmacookiecnt); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate if (rval == DDI_DMA_MAPPED) { 13427c478bd9Sstevel@tonic-gate csb->csb_dmawincnt = 1; 13437c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 1; 13447c478bd9Sstevel@tonic-gate } else if (rval == DDI_DMA_PARTIAL_MAP) { 13457c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 1; 13467c478bd9Sstevel@tonic-gate if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != 13477c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 13487c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdtrkformat: dma numwin failed\n"); 13497c478bd9Sstevel@tonic-gate rval = EINVAL; 13507c478bd9Sstevel@tonic-gate goto out; 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate } else { 13537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 13547c478bd9Sstevel@tonic-gate "fdtrkformat: dma buf bind handle failed, rval = %d\n", 13557c478bd9Sstevel@tonic-gate rval); 13567c478bd9Sstevel@tonic-gate rval = EINVAL; 13577c478bd9Sstevel@tonic-gate goto out; 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate rval = fdc_exec(fcp, 1, 1); 13617c478bd9Sstevel@tonic-gate out: 13627c478bd9Sstevel@tonic-gate if (csb->csb_dmahandle) { 13637c478bd9Sstevel@tonic-gate if (csb->csb_handle_bound) { 13647c478bd9Sstevel@tonic-gate if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 13657c478bd9Sstevel@tonic-gate DDI_SUCCESS) 13667c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdtrkformat: " 13677c478bd9Sstevel@tonic-gate "dma unbind handle failed\n"); 13687c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 0; 13697c478bd9Sstevel@tonic-gate } 13703dda9c1fSmrj if (mem_handle != NULL) { 13713dda9c1fSmrj ddi_dma_mem_free(&mem_handle); 13723dda9c1fSmrj } 13737c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&csb->csb_dmahandle); 13747c478bd9Sstevel@tonic-gate csb->csb_dmahandle = NULL; 13757c478bd9Sstevel@tonic-gate } 13767c478bd9Sstevel@tonic-gate return (rval); 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13807c478bd9Sstevel@tonic-gate int 13817c478bd9Sstevel@tonic-gate fdrawioctl(struct fcu_obj *fjp, int funit, caddr_t arg) 13827c478bd9Sstevel@tonic-gate { 13837c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 13847c478bd9Sstevel@tonic-gate struct fd_raw *fdrp = (struct fd_raw *)arg; 13857c478bd9Sstevel@tonic-gate struct fdcsb *csb; 13867c478bd9Sstevel@tonic-gate uint_t dmar_flags = 0; 13877c478bd9Sstevel@tonic-gate int i; 13887c478bd9Sstevel@tonic-gate int change = 1; 13897c478bd9Sstevel@tonic-gate int sleep = 1; 13907c478bd9Sstevel@tonic-gate int rval = 0; 13917c478bd9Sstevel@tonic-gate int rval_exec = 0; 13923dda9c1fSmrj ddi_acc_handle_t mem_handle = NULL; 13933dda9c1fSmrj caddr_t aligned_buf; 13943dda9c1fSmrj size_t real_size; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RAWI, 13977c478bd9Sstevel@tonic-gate (CE_NOTE, "fdrawioctl: cmd[0]=0x%x", fdrp->fdr_cmd[0])); 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate csb = &fcp->c_csb; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* copy cmd bytes into csb */ 14027c478bd9Sstevel@tonic-gate for (i = 0; i <= fdrp->fdr_cnum; i++) 14037c478bd9Sstevel@tonic-gate csb->csb_cmd[i] = fdrp->fdr_cmd[i]; 14047c478bd9Sstevel@tonic-gate csb->csb_ncmds = (uchar_t)fdrp->fdr_cnum; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate csb->csb_maxretry = 0; /* let the application deal with errors */ 14077c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFRAWIOCTL; 14087c478bd9Sstevel@tonic-gate csb->csb_nrslts = 0; 14097c478bd9Sstevel@tonic-gate csb->csb_timer = 50; 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate switch (fdrp->fdr_cmd[0] & 0x0f) { 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate case FO_SEEK: 14147c478bd9Sstevel@tonic-gate change = 0; 14157c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 14167c478bd9Sstevel@tonic-gate case FO_RECAL: 14177c478bd9Sstevel@tonic-gate csb->csb_opflags |= CSB_OFINRPT; 14187c478bd9Sstevel@tonic-gate break; 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate case FO_FRMT: 14217c478bd9Sstevel@tonic-gate csb->csb_npcyl = *(uchar_t *)(fdrp->fdr_addr) * 14227c478bd9Sstevel@tonic-gate fjp->fj_chars->fdc_steps; 14237c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 14247c478bd9Sstevel@tonic-gate case FO_WRDAT: 14257c478bd9Sstevel@tonic-gate case FO_WRDEL: 14267c478bd9Sstevel@tonic-gate csb->csb_opflags |= CSB_OFDMAWT | CSB_OFRESLT | CSB_OFINRPT; 14277c478bd9Sstevel@tonic-gate csb->csb_nrslts = 7; 14287c478bd9Sstevel@tonic-gate if (fdrp->fdr_nbytes == 0) 14297c478bd9Sstevel@tonic-gate return (EINVAL); 14307c478bd9Sstevel@tonic-gate dmar_flags = DDI_DMA_WRITE; 14317c478bd9Sstevel@tonic-gate break; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate case FO_RDDAT: 14347c478bd9Sstevel@tonic-gate case FO_RDDEL: 14357c478bd9Sstevel@tonic-gate case FO_RDTRK: 14367c478bd9Sstevel@tonic-gate csb->csb_opflags |= CSB_OFDMARD | CSB_OFRESLT | CSB_OFINRPT; 14377c478bd9Sstevel@tonic-gate csb->csb_nrslts = 7; 14387c478bd9Sstevel@tonic-gate dmar_flags = DDI_DMA_READ; 14397c478bd9Sstevel@tonic-gate break; 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate case FO_RDID: 14427c478bd9Sstevel@tonic-gate csb->csb_opflags |= CSB_OFRESLT | CSB_OFINRPT; 14437c478bd9Sstevel@tonic-gate csb->csb_nrslts = 7; 14447c478bd9Sstevel@tonic-gate break; 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate case FO_SDRV: 14477c478bd9Sstevel@tonic-gate sleep = 0; 14487c478bd9Sstevel@tonic-gate csb->csb_nrslts = 1; 14497c478bd9Sstevel@tonic-gate break; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate case FO_SINT: 14527c478bd9Sstevel@tonic-gate sleep = 0; 14537c478bd9Sstevel@tonic-gate change = 0; 14547c478bd9Sstevel@tonic-gate csb->csb_nrslts = 2; 14557c478bd9Sstevel@tonic-gate break; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate case FO_SPEC: 14587c478bd9Sstevel@tonic-gate sleep = 0; 14597c478bd9Sstevel@tonic-gate change = 0; 14607c478bd9Sstevel@tonic-gate break; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate default: 14637c478bd9Sstevel@tonic-gate return (EINVAL); 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate csb->csb_dmahandle = NULL; 14677c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 0; 14687c478bd9Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 14697c478bd9Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 14707c478bd9Sstevel@tonic-gate csb->csb_dmawincnt = 0; 14717c478bd9Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) { 14743dda9c1fSmrj if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, 14753dda9c1fSmrj DDI_DMA_SLEEP, 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 14767c478bd9Sstevel@tonic-gate rval = EINVAL; 14777c478bd9Sstevel@tonic-gate goto out; 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate 14803dda9c1fSmrj /* 14813dda9c1fSmrj * allocate a page aligned buffer to dma to/from. This way we 14823dda9c1fSmrj * can ensure the cookie is a whole multiple of granularity and 14833dda9c1fSmrj * avoids any alignment issues. 14843dda9c1fSmrj */ 14853dda9c1fSmrj rval = ddi_dma_mem_alloc(csb->csb_dmahandle, 14863dda9c1fSmrj (uint_t)fdrp->fdr_nbytes, &fdc_accattr, DDI_DMA_CONSISTENT, 14873dda9c1fSmrj DDI_DMA_SLEEP, NULL, &aligned_buf, &real_size, &mem_handle); 14883dda9c1fSmrj if (rval != DDI_SUCCESS) { 14893dda9c1fSmrj rval = EINVAL; 14903dda9c1fSmrj goto out; 14913dda9c1fSmrj } 14923dda9c1fSmrj 14933dda9c1fSmrj if (dmar_flags & DDI_DMA_WRITE) { 14943dda9c1fSmrj bcopy(fdrp->fdr_addr, aligned_buf, 14953dda9c1fSmrj (uint_t)fdrp->fdr_nbytes); 14963dda9c1fSmrj } 14973dda9c1fSmrj 14987c478bd9Sstevel@tonic-gate dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL); 14997c478bd9Sstevel@tonic-gate rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, 15003dda9c1fSmrj aligned_buf, (uint_t)fdrp->fdr_nbytes, dmar_flags, 15013dda9c1fSmrj DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, 15023dda9c1fSmrj &csb->csb_dmacookiecnt); 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate if (rval == DDI_DMA_MAPPED) { 15057c478bd9Sstevel@tonic-gate csb->csb_dmawincnt = 1; 15067c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 1; 15077c478bd9Sstevel@tonic-gate } else if (rval == DDI_DMA_PARTIAL_MAP) { 15087c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 1; 15097c478bd9Sstevel@tonic-gate if (ddi_dma_numwin(csb->csb_dmahandle, 15107c478bd9Sstevel@tonic-gate &csb->csb_dmawincnt) != DDI_SUCCESS) { 15117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 15127c478bd9Sstevel@tonic-gate "fdrawioctl: dma numwin failed\n"); 15137c478bd9Sstevel@tonic-gate rval = EINVAL; 15147c478bd9Sstevel@tonic-gate goto out; 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate } else { 15177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdrawioctl: " 15187c478bd9Sstevel@tonic-gate "dma buf bind handle failed, rval = %d\n", rval); 15197c478bd9Sstevel@tonic-gate rval = EINVAL; 15207c478bd9Sstevel@tonic-gate goto out; 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RAWI, 15257c478bd9Sstevel@tonic-gate (CE_CONT, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmd[0], 15267c478bd9Sstevel@tonic-gate csb->csb_cmd[1], csb->csb_cmd[2], csb->csb_cmd[3], 15277c478bd9Sstevel@tonic-gate csb->csb_cmd[4], csb->csb_cmd[5], csb->csb_cmd[6], 15287c478bd9Sstevel@tonic-gate csb->csb_cmd[7], csb->csb_cmd[8], csb->csb_cmd[9])); 15297c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RAWI, 15307c478bd9Sstevel@tonic-gate (CE_CONT, "nbytes: %x, opflags: %x, addr: %p, len: %x\n", 15317c478bd9Sstevel@tonic-gate csb->csb_ncmds, csb->csb_opflags, (void *)fdrp->fdr_addr, 15327c478bd9Sstevel@tonic-gate fdrp->fdr_nbytes)); 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * Note that we ignore any error returns from fdexec. 15367c478bd9Sstevel@tonic-gate * This is the way the driver has been, and it may be 15377c478bd9Sstevel@tonic-gate * that the raw ioctl senders simply don't want to 15387c478bd9Sstevel@tonic-gate * see any errors returned in this fashion. 15397c478bd9Sstevel@tonic-gate */ 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate /* 15427c478bd9Sstevel@tonic-gate * VP/ix sense drive ioctl call checks for the error return. 15437c478bd9Sstevel@tonic-gate */ 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate rval_exec = fdc_exec(fcp, sleep, change); 15467c478bd9Sstevel@tonic-gate 15473dda9c1fSmrj if (dmar_flags & DDI_DMA_READ) { 15483dda9c1fSmrj bcopy(aligned_buf, fdrp->fdr_addr, (uint_t)fdrp->fdr_nbytes); 15493dda9c1fSmrj } 15503dda9c1fSmrj 15517c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RAWI, 15527c478bd9Sstevel@tonic-gate (CE_CONT, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0], 15537c478bd9Sstevel@tonic-gate csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3], 15547c478bd9Sstevel@tonic-gate csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6], 15557c478bd9Sstevel@tonic-gate csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9])); 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate /* copy results into fdr */ 15587c478bd9Sstevel@tonic-gate for (i = 0; i <= (int)csb->csb_nrslts; i++) 15597c478bd9Sstevel@tonic-gate fdrp->fdr_result[i] = csb->csb_rslt[i]; 15607c478bd9Sstevel@tonic-gate /* fdrp->fdr_nbytes = fdc->c_csb.csb_rlen; return resid */ 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate out: 15637c478bd9Sstevel@tonic-gate if (csb->csb_dmahandle) { 15647c478bd9Sstevel@tonic-gate if (csb->csb_handle_bound) { 15657c478bd9Sstevel@tonic-gate if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 15667c478bd9Sstevel@tonic-gate DDI_SUCCESS) 15677c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdrawioctl: " 15687c478bd9Sstevel@tonic-gate "dma unbind handle failed\n"); 15697c478bd9Sstevel@tonic-gate csb->csb_handle_bound = 0; 15707c478bd9Sstevel@tonic-gate } 15713dda9c1fSmrj if (mem_handle != NULL) { 15723dda9c1fSmrj ddi_dma_mem_free(&mem_handle); 15733dda9c1fSmrj } 15747c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&csb->csb_dmahandle); 15757c478bd9Sstevel@tonic-gate csb->csb_dmahandle = NULL; 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate if ((fdrp->fdr_cmd[0] & 0x0f) == FO_SDRV) { 15787c478bd9Sstevel@tonic-gate return (rval_exec); 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate return (rval); 15817c478bd9Sstevel@tonic-gate } 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate void 15847c478bd9Sstevel@tonic-gate encode(xlate_tbl_t *tablep, int val, uchar_t *rcode) 15857c478bd9Sstevel@tonic-gate { 15867c478bd9Sstevel@tonic-gate do { 15877c478bd9Sstevel@tonic-gate if (tablep->value >= val) { 15887c478bd9Sstevel@tonic-gate *rcode = tablep->code; 15897c478bd9Sstevel@tonic-gate return; 15907c478bd9Sstevel@tonic-gate } 15917c478bd9Sstevel@tonic-gate } while ((++tablep)->value); 15927c478bd9Sstevel@tonic-gate *rcode = tablep->code; 15937c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc encode failed, table %p val %x code %x\n", 15947c478bd9Sstevel@tonic-gate (void *)tablep, val, (uint_t)*rcode); 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate int 15987c478bd9Sstevel@tonic-gate decode(xlate_tbl_t *tablep, int kode, int *rvalue) 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate do { 16017c478bd9Sstevel@tonic-gate if (tablep->code == kode) { 16027c478bd9Sstevel@tonic-gate *rvalue = tablep->value; 16037c478bd9Sstevel@tonic-gate return (0); 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate } while ((++tablep)->value); 16067c478bd9Sstevel@tonic-gate return (-1); 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate 1609*19397407SSherry Moore /* 1610*19397407SSherry Moore * quiesce(9E) entry point. 1611*19397407SSherry Moore * 1612*19397407SSherry Moore * This function is called when the system is single-threaded at high 1613*19397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 1614*19397407SSherry Moore * blocked. 1615*19397407SSherry Moore * 1616*19397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 1617*19397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 1618*19397407SSherry Moore */ 1619*19397407SSherry Moore int 1620*19397407SSherry Moore fdc_quiesce(dev_info_t *dip) 1621*19397407SSherry Moore { 1622*19397407SSherry Moore struct fdcntlr *fcp; 1623*19397407SSherry Moore int ctlr = ddi_get_instance(dip); 1624*19397407SSherry Moore int unit; 1625*19397407SSherry Moore 1626*19397407SSherry Moore fcp = ddi_get_soft_state(fdc_state_head, ctlr); 1627*19397407SSherry Moore 1628*19397407SSherry Moore if (fcp == NULL) 1629*19397407SSherry Moore return (DDI_FAILURE); 1630*19397407SSherry Moore 1631*19397407SSherry Moore /* 1632*19397407SSherry Moore * If no FD units are attached, there is no need to quiesce. 1633*19397407SSherry Moore */ 1634*19397407SSherry Moore for (unit = 0; unit < NFDUN; unit++) { 1635*19397407SSherry Moore struct fcu_obj *fjp = fcp->c_unit[unit]; 1636*19397407SSherry Moore if (fjp->fj_flags & FUNIT_DRVATCH) { 1637*19397407SSherry Moore break; 1638*19397407SSherry Moore } 1639*19397407SSherry Moore } 1640*19397407SSherry Moore 1641*19397407SSherry Moore if (unit == NFDUN) 1642*19397407SSherry Moore return (DDI_SUCCESS); 1643*19397407SSherry Moore 1644*19397407SSherry Moore (void) ddi_dmae_disable(fcp->c_dip, fcp->c_dmachan); 1645*19397407SSherry Moore 1646*19397407SSherry Moore fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE; 1647*19397407SSherry Moore outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1648*19397407SSherry Moore drv_usecwait(20); 1649*19397407SSherry Moore fcp->c_digout |= FD_RSETZ; 1650*19397407SSherry Moore outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1651*19397407SSherry Moore 1652*19397407SSherry Moore if (fcp->c_chip >= i82077) { 1653*19397407SSherry Moore int count = 4; 1654*19397407SSherry Moore uchar_t *oplistp = configurecmd; 1655*19397407SSherry Moore do { 1656*19397407SSherry Moore int ntries = FDC_RQM_RETRY; 1657*19397407SSherry Moore do { 1658*19397407SSherry Moore if ((inb(fcp->c_regbase + FCR_MSR) & 1659*19397407SSherry Moore (MS_RQM|MS_DIO)) == MS_RQM) 1660*19397407SSherry Moore break; 1661*19397407SSherry Moore else 1662*19397407SSherry Moore drv_usecwait(1); 1663*19397407SSherry Moore } while (--ntries); 1664*19397407SSherry Moore if (ntries == 0) { 1665*19397407SSherry Moore break; 1666*19397407SSherry Moore } 1667*19397407SSherry Moore outb(fcp->c_regbase + FCR_DATA, *oplistp++); 1668*19397407SSherry Moore drv_usecwait(16); /* See comment in fdc_result() */ 1669*19397407SSherry Moore } while (--count); 1670*19397407SSherry Moore } 1671*19397407SSherry Moore 1672*19397407SSherry Moore return (DDI_SUCCESS); 1673*19397407SSherry Moore } 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate void 16767c478bd9Sstevel@tonic-gate fdcquiesce(struct fdcntlr *fcp) 16777c478bd9Sstevel@tonic-gate { 16787c478bd9Sstevel@tonic-gate int unit; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RESE, (CE_NOTE, "fdcquiesce fcp %p", 16817c478bd9Sstevel@tonic-gate (void*)fcp)); 16827c478bd9Sstevel@tonic-gate 1683*19397407SSherry Moore ASSERT(MUTEX_HELD(&fcp->c_lock)); 16847c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS) 16877c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdcquiesce: dmae stop failed, " 16887c478bd9Sstevel@tonic-gate "dip %p, dmachan %x\n", 16897c478bd9Sstevel@tonic-gate (void*)fcp->c_dip, fcp->c_dmachan); 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE; 16927c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 16937c478bd9Sstevel@tonic-gate drv_usecwait(20); 16947c478bd9Sstevel@tonic-gate fcp->c_digout |= FD_RSETZ; 16957c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate /* count resets */ 17007c478bd9Sstevel@tonic-gate fcp->fdstats.reset++; 17017c478bd9Sstevel@tonic-gate fcp->c_curunit = -1; 17027c478bd9Sstevel@tonic-gate for (unit = 0; unit < NFDUN; unit++) 17037c478bd9Sstevel@tonic-gate fcp->c_curpcyl[unit] = -1; 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate if (fcp->c_chip >= i82077) { 17067c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, configurecmd, 4); 17077c478bd9Sstevel@tonic-gate /* 17087c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 17097c478bd9Sstevel@tonic-gate */ 17107c478bd9Sstevel@tonic-gate } 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate void 17147c478bd9Sstevel@tonic-gate fdcreadid(struct fdcntlr *fcp, struct fdcsb *csb) 17157c478bd9Sstevel@tonic-gate { 17167c478bd9Sstevel@tonic-gate static uchar_t readidcmd[2] = {FO_RDID | FO_MFM, 0}; 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate readidcmd[1] = csb->csb_cmd[1]; 17197c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, readidcmd, 2); 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate int 17237c478bd9Sstevel@tonic-gate fdcseek(struct fdcntlr *fcp, int unit, int cyl) 17247c478bd9Sstevel@tonic-gate { 17257c478bd9Sstevel@tonic-gate static uchar_t seekabscmd[3] = {FO_SEEK, 0, 0}; 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_RECA, (CE_CONT, "fdcseek unit %d to cyl %d\n", 17287c478bd9Sstevel@tonic-gate unit, cyl)); 17297c478bd9Sstevel@tonic-gate seekabscmd[1] = (uchar_t)unit; 17307c478bd9Sstevel@tonic-gate seekabscmd[2] = (uchar_t)cyl; 17317c478bd9Sstevel@tonic-gate return (fdc_docmd(fcp, seekabscmd, 3)); 17327c478bd9Sstevel@tonic-gate } 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate /* 17357c478bd9Sstevel@tonic-gate * Returns status of disk change line of selected drive. 17367c478bd9Sstevel@tonic-gate * = 0 means diskette is present 17377c478bd9Sstevel@tonic-gate * != 0 means diskette was removed and current state is unknown 17387c478bd9Sstevel@tonic-gate */ 17397c478bd9Sstevel@tonic-gate int 17407c478bd9Sstevel@tonic-gate fdcsense_chng(struct fdcntlr *fcp, int unit) 17417c478bd9Sstevel@tonic-gate { 17427c478bd9Sstevel@tonic-gate int digital_input; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_SCHG, 17457c478bd9Sstevel@tonic-gate (CE_CONT, "fdcsense_chng unit %d\n", unit)); 17467c478bd9Sstevel@tonic-gate digital_input = inb(fcp->c_regbase + FCR_DIR); 17477c478bd9Sstevel@tonic-gate if (fcp->c_mode == FDCMODE_30) 17487c478bd9Sstevel@tonic-gate digital_input ^= FDI_DKCHG; 17497c478bd9Sstevel@tonic-gate return (digital_input & FDI_DKCHG); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate int 17537c478bd9Sstevel@tonic-gate fdcsense_drv(struct fdcntlr *fcp, int unit) 17547c478bd9Sstevel@tonic-gate { 17557c478bd9Sstevel@tonic-gate static uchar_t sensedrvcmd[2] = {FO_SDRV, 0}; 17567c478bd9Sstevel@tonic-gate uchar_t senser; 17577c478bd9Sstevel@tonic-gate int rval; 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate sensedrvcmd[1] = (uchar_t)unit; 17607c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, sensedrvcmd, 2); 17617c478bd9Sstevel@tonic-gate /* 17627c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 17637c478bd9Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 17647c478bd9Sstevel@tonic-gate */ 17657c478bd9Sstevel@tonic-gate if (rval = fdc_result(fcp, &senser, 1)) 17667c478bd9Sstevel@tonic-gate goto done; 17677c478bd9Sstevel@tonic-gate if (senser & S3_WPROT) 17687c478bd9Sstevel@tonic-gate fcp->c_unit[unit]->fj_flags |= FUNIT_WPROT; 17697c478bd9Sstevel@tonic-gate else 17707c478bd9Sstevel@tonic-gate fcp->c_unit[unit]->fj_flags &= ~FUNIT_WPROT; 17717c478bd9Sstevel@tonic-gate done: 17727c478bd9Sstevel@tonic-gate return (rval); 17737c478bd9Sstevel@tonic-gate } 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate int 17767c478bd9Sstevel@tonic-gate fdcsense_int(struct fdcntlr *fcp, int *unitp, int *cylp) 17777c478bd9Sstevel@tonic-gate { 17787c478bd9Sstevel@tonic-gate uchar_t senser[2]; 17797c478bd9Sstevel@tonic-gate int rval; 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 17827c478bd9Sstevel@tonic-gate /* 17837c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 17847c478bd9Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 17857c478bd9Sstevel@tonic-gate */ 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate if (!(rval = fdc_result(fcp, senser, 2))) { 17887c478bd9Sstevel@tonic-gate if ((*senser & (S0_IVCMD | S0_SEKEND | S0_ECHK)) != S0_SEKEND) 17897c478bd9Sstevel@tonic-gate rval = 1; 17907c478bd9Sstevel@tonic-gate if (unitp) 17917c478bd9Sstevel@tonic-gate *unitp = *senser & 3; 17927c478bd9Sstevel@tonic-gate if (cylp) 17937c478bd9Sstevel@tonic-gate *cylp = senser[1]; 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate return (rval); 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate int 17997c478bd9Sstevel@tonic-gate fdcspecify(struct fdcntlr *fcp, int xferrate, int steprate, int hlt) 18007c478bd9Sstevel@tonic-gate { 18017c478bd9Sstevel@tonic-gate static uchar_t perpindcmd[2] = {FO_PERP, 0}; 18027c478bd9Sstevel@tonic-gate static uchar_t specifycmd[3] = {FO_SPEC, 0, 0}; 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate encode(drate_mfm, xferrate, &fcp->c_config); 18057c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_CCR, fcp->c_config); 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate if (fcp->c_chip >= i82077) { 18087c478bd9Sstevel@tonic-gate /* 18097c478bd9Sstevel@tonic-gate * Use old style perpendicular mode command of 82077. 18107c478bd9Sstevel@tonic-gate */ 18117c478bd9Sstevel@tonic-gate if (xferrate == 1000) { 18127c478bd9Sstevel@tonic-gate /* Set GAP and WGATE */ 18137c478bd9Sstevel@tonic-gate perpindcmd[1] = 3; 18147c478bd9Sstevel@tonic-gate /* double step rate because xlate table is for 500Kb */ 18157c478bd9Sstevel@tonic-gate steprate <<= 1; 18167c478bd9Sstevel@tonic-gate hlt <<= 1; 18177c478bd9Sstevel@tonic-gate } else 18187c478bd9Sstevel@tonic-gate perpindcmd[1] = 0; 18197c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, perpindcmd, 2); 18207c478bd9Sstevel@tonic-gate /* 18217c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 18227c478bd9Sstevel@tonic-gate */ 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate encode(step_rate, steprate, &fcp->c_hutsrt); 18257c478bd9Sstevel@tonic-gate specifycmd[1] = fcp->c_hutsrt |= 0x0F; /* use max head unload time */ 18267c478bd9Sstevel@tonic-gate hlt = (hlt >= 256) ? 0 : (hlt >> 1); /* encode head load time */ 18277c478bd9Sstevel@tonic-gate specifycmd[2] = fcp->c_hlt = hlt << 1; /* make room for DMA bit */ 18287c478bd9Sstevel@tonic-gate return (fdc_docmd(fcp, specifycmd, 3)); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate int 18327c478bd9Sstevel@tonic-gate fdcspdchange(struct fdcntlr *fcp, struct fcu_obj *fjp, int rpm) 18337c478bd9Sstevel@tonic-gate { 18347c478bd9Sstevel@tonic-gate int retcode = 0; 18357c478bd9Sstevel@tonic-gate uint_t ddic; 18367c478bd9Sstevel@tonic-gate uchar_t deselect = 0; 18377c478bd9Sstevel@tonic-gate uchar_t ds_code; 18387c478bd9Sstevel@tonic-gate uchar_t enable_code; 18397c478bd9Sstevel@tonic-gate uchar_t save; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate if (((fcp->c_flags & FCFLG_DSOUT) == 0 && rpm <= fjp->fj_rotspd) || 18427c478bd9Sstevel@tonic-gate ((fcp->c_flags & FCFLG_DSOUT) && (fjp->fj_flags & FUNIT_3DMODE) && 18437c478bd9Sstevel@tonic-gate rpm > fjp->fj_rotspd)) { 18447c478bd9Sstevel@tonic-gate return (0); 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_SCHG, 18487c478bd9Sstevel@tonic-gate (CE_CONT, "fdcspdchange: %d rpm\n", rpm)); 18497c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_dorlock)); 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate switch (fcp->c_chip) { 18527c478bd9Sstevel@tonic-gate default: 18537c478bd9Sstevel@tonic-gate break; 18547c478bd9Sstevel@tonic-gate case i82077: 18557c478bd9Sstevel@tonic-gate break; 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate case PC87322: 18587c478bd9Sstevel@tonic-gate { 18597c478bd9Sstevel@tonic-gate uchar_t nscmodecmd[5] = {FO_MODE, 0x02, 0x00, 0xC8, 0x00}; 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate if (rpm > fjp->fj_rotspd) { 18627c478bd9Sstevel@tonic-gate nscmodecmd[3] ^= 0xC0; 18637c478bd9Sstevel@tonic-gate retcode = (fcp->c_flags ^ FCFLG_DSOUT) || 18647c478bd9Sstevel@tonic-gate (fjp->fj_flags ^ FUNIT_3DMODE); 18657c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_DSOUT; 18667c478bd9Sstevel@tonic-gate fjp->fj_flags |= FUNIT_3DMODE; 18677c478bd9Sstevel@tonic-gate } else { 18687c478bd9Sstevel@tonic-gate /* program DENSEL to default output */ 18697c478bd9Sstevel@tonic-gate fcp->c_flags &= ~FCFLG_DSOUT; 18707c478bd9Sstevel@tonic-gate retcode = fjp->fj_flags & FUNIT_3DMODE; 18717c478bd9Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_3DMODE; 18727c478bd9Sstevel@tonic-gate } 18737c478bd9Sstevel@tonic-gate if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) { 18747c478bd9Sstevel@tonic-gate /* de-select drive while changing speed */ 18757c478bd9Sstevel@tonic-gate deselect = fcp->c_digout ^ FD_DRSEL; 18767c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, deselect); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, nscmodecmd, 5); 18807c478bd9Sstevel@tonic-gate /* 18817c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 18827c478bd9Sstevel@tonic-gate */ 18837c478bd9Sstevel@tonic-gate break; 18847c478bd9Sstevel@tonic-gate } 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate case FDC37C665: 18877c478bd9Sstevel@tonic-gate enable_code = FSA_ENA5; 18887c478bd9Sstevel@tonic-gate goto SMC_config; 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate case FDC37C666: 18917c478bd9Sstevel@tonic-gate enable_code = FSA_ENA6; 18927c478bd9Sstevel@tonic-gate SMC_config: 18937c478bd9Sstevel@tonic-gate if (rpm > fjp->fj_rotspd) { 18947c478bd9Sstevel@tonic-gate /* force DENSEL output to active LOW */ 18957c478bd9Sstevel@tonic-gate ds_code = FSB_DSHI; 18967c478bd9Sstevel@tonic-gate retcode = (fcp->c_flags ^ FCFLG_DSOUT) || 18977c478bd9Sstevel@tonic-gate (fjp->fj_flags ^ FUNIT_3DMODE); 18987c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_DSOUT; 18997c478bd9Sstevel@tonic-gate fjp->fj_flags |= FUNIT_3DMODE; 19007c478bd9Sstevel@tonic-gate } else { 19017c478bd9Sstevel@tonic-gate /* program DENSEL to default output */ 19027c478bd9Sstevel@tonic-gate ds_code = 0; 19037c478bd9Sstevel@tonic-gate fcp->c_flags &= ~FCFLG_DSOUT; 19047c478bd9Sstevel@tonic-gate retcode = fjp->fj_flags & FUNIT_3DMODE; 19057c478bd9Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_3DMODE; 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) { 19087c478bd9Sstevel@tonic-gate /* de-select drive while changing speed */ 19097c478bd9Sstevel@tonic-gate deselect = fcp->c_digout ^ FD_DRSEL; 19107c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, deselect); 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate save = inb(fcp->c_regbase + FCR_SRA); 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate /* enter configuration mode */ 19157c478bd9Sstevel@tonic-gate ddic = ddi_enter_critical(); 19167c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, enable_code); 19177c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, enable_code); 19187c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_CR5); 19217c478bd9Sstevel@tonic-gate enable_code = inb(fcp->c_regbase + FCR_SRB) & FSB_DSDEF; 19227c478bd9Sstevel@tonic-gate /* update DENSEL mode bits */ 19237c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRB, enable_code | ds_code); 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate /* exit configuration mode */ 19267c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 19277c478bd9Sstevel@tonic-gate drv_usecwait(10); 19287c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, save); 19297c478bd9Sstevel@tonic-gate break; 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate if (deselect) 19327c478bd9Sstevel@tonic-gate /* reselect drive */ 19337c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 19347c478bd9Sstevel@tonic-gate return (retcode); 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate static int 19387c478bd9Sstevel@tonic-gate fdc_motorsm(struct fcu_obj *fjp, int input, int timeval) 19397c478bd9Sstevel@tonic-gate { 19407c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 19417c478bd9Sstevel@tonic-gate int unit = fjp->fj_unit & 3; 19427c478bd9Sstevel@tonic-gate int old_mstate; 19437c478bd9Sstevel@tonic-gate int rval = 0; 19447c478bd9Sstevel@tonic-gate uchar_t motorbit; 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_dorlock)); 19477c478bd9Sstevel@tonic-gate old_mstate = fcp->c_mtrstate[unit]; 19487c478bd9Sstevel@tonic-gate encode(motor_onbits, unit, &motorbit); 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate switch (input) { 19517c478bd9Sstevel@tonic-gate case FMI_TIMER: /* timer expired */ 19527c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = 0; 19537c478bd9Sstevel@tonic-gate switch (old_mstate) { 19547c478bd9Sstevel@tonic-gate case FMS_START: 19557c478bd9Sstevel@tonic-gate case FMS_DELAY: 19567c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_ON; 19577c478bd9Sstevel@tonic-gate break; 19587c478bd9Sstevel@tonic-gate case FMS_KILLST: 19597c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 19607c478bd9Sstevel@tonic-gate drv_usectohz(1000000)); 19617c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_IDLE; 19627c478bd9Sstevel@tonic-gate break; 19637c478bd9Sstevel@tonic-gate case FMS_IDLE: 19647c478bd9Sstevel@tonic-gate fcp->c_digout &= ~motorbit; 19657c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 19667c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_OFF; 19677c478bd9Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_3DMODE; 19687c478bd9Sstevel@tonic-gate break; 19697c478bd9Sstevel@tonic-gate case 86: 19707c478bd9Sstevel@tonic-gate rval = -1; 19717c478bd9Sstevel@tonic-gate break; 19727c478bd9Sstevel@tonic-gate case FMS_OFF: 19737c478bd9Sstevel@tonic-gate case FMS_ON: 19747c478bd9Sstevel@tonic-gate default: 19757c478bd9Sstevel@tonic-gate rval = -2; 19767c478bd9Sstevel@tonic-gate } 19777c478bd9Sstevel@tonic-gate break; 19787c478bd9Sstevel@tonic-gate 19797c478bd9Sstevel@tonic-gate case FMI_STARTCMD: /* start command */ 19807c478bd9Sstevel@tonic-gate switch (old_mstate) { 19817c478bd9Sstevel@tonic-gate case FMS_IDLE: 19827c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = 86; 19837c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 19847c478bd9Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 19857c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 19867c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = 0; 19877c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_ON; 19887c478bd9Sstevel@tonic-gate break; 19897c478bd9Sstevel@tonic-gate case FMS_OFF: 19907c478bd9Sstevel@tonic-gate fcp->c_digout |= motorbit; 19917c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate /* start motor_spinup_timer */ 19947c478bd9Sstevel@tonic-gate ASSERT(timeval > 0); 19957c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 19967c478bd9Sstevel@tonic-gate drv_usectohz(100000 * timeval)); 19977c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 19987c478bd9Sstevel@tonic-gate case FMS_KILLST: 19997c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_START; 20007c478bd9Sstevel@tonic-gate break; 20017c478bd9Sstevel@tonic-gate default: 20027c478bd9Sstevel@tonic-gate rval = -2; 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate break; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate case FMI_RSTARTCMD: /* restart command */ 20077c478bd9Sstevel@tonic-gate if (fcp->c_motort[unit] != 0) { 20087c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = 86; 20097c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20107c478bd9Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 20117c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20127c478bd9Sstevel@tonic-gate } 20137c478bd9Sstevel@tonic-gate ASSERT(timeval > 0); 20147c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 20157c478bd9Sstevel@tonic-gate drv_usectohz(100000 * timeval)); 20167c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_START; 20177c478bd9Sstevel@tonic-gate break; 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate case FMI_DELAYCMD: /* delay command */ 20207c478bd9Sstevel@tonic-gate if (fcp->c_motort[unit] == 0) 20217c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 20227c478bd9Sstevel@tonic-gate drv_usectohz(15000)); 20237c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_DELAY; 20247c478bd9Sstevel@tonic-gate break; 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate case FMI_IDLECMD: /* idle command */ 20277c478bd9Sstevel@tonic-gate switch (old_mstate) { 20287c478bd9Sstevel@tonic-gate case FMS_DELAY: 20297c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = 86; 20307c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20317c478bd9Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 20327c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20337c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 20347c478bd9Sstevel@tonic-gate case FMS_ON: 20357c478bd9Sstevel@tonic-gate ASSERT(timeval > 0); 20367c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 20377c478bd9Sstevel@tonic-gate drv_usectohz(100000 * timeval)); 20387c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_IDLE; 20397c478bd9Sstevel@tonic-gate break; 20407c478bd9Sstevel@tonic-gate case FMS_START: 20417c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_KILLST; 20427c478bd9Sstevel@tonic-gate break; 20437c478bd9Sstevel@tonic-gate default: 20447c478bd9Sstevel@tonic-gate rval = -2; 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate break; 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate default: 20497c478bd9Sstevel@tonic-gate rval = -3; 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate if (rval) { 20527c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_EXEC, (CE_WARN, 20537c478bd9Sstevel@tonic-gate "fdc_motorsm: unit %d bad input %d or bad state %d", 20547c478bd9Sstevel@tonic-gate (int)fjp->fj_unit, input, old_mstate)); 20557c478bd9Sstevel@tonic-gate #if 0 20567c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 20577c478bd9Sstevel@tonic-gate "fdc_motorsm: unit %d bad input %d or bad state %d\n", 20587c478bd9Sstevel@tonic-gate (int)fjp->fj_unit, input, old_mstate); 20597c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_OFF; 20607c478bd9Sstevel@tonic-gate if (fcp->c_motort[unit] != 0) { 20617c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20627c478bd9Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 20637c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20647c478bd9Sstevel@tonic-gate fcp->c_motort[unit] = 0; 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate #endif 20677c478bd9Sstevel@tonic-gate } else 20687c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_EXEC, 20697c478bd9Sstevel@tonic-gate (CE_CONT, "fdc_motorsm unit %d: input %d, %d -> %d\n", 20707c478bd9Sstevel@tonic-gate (int)fjp->fj_unit, input, old_mstate, 20717c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit])); 20727c478bd9Sstevel@tonic-gate return (rval); 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate /* 20767c478bd9Sstevel@tonic-gate * fdmotort 20777c478bd9Sstevel@tonic-gate * is called from timeout() when a motor timer has expired. 20787c478bd9Sstevel@tonic-gate */ 20797c478bd9Sstevel@tonic-gate static void 20807c478bd9Sstevel@tonic-gate fdmotort(void *arg) 20817c478bd9Sstevel@tonic-gate { 20827c478bd9Sstevel@tonic-gate struct fcu_obj *fjp = (struct fcu_obj *)arg; 20837c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 20847c478bd9Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 20857c478bd9Sstevel@tonic-gate int unit = fjp->fj_unit & 3; 20867c478bd9Sstevel@tonic-gate int mval; 20877c478bd9Sstevel@tonic-gate int newxstate = 0; 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20907c478bd9Sstevel@tonic-gate mval = fdc_motorsm(fjp, FMI_TIMER, 0); 20917c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20927c478bd9Sstevel@tonic-gate if (mval < 0) 20937c478bd9Sstevel@tonic-gate return; 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate if ((fcp->c_flags & FCFLG_WAITING) && 20987c478bd9Sstevel@tonic-gate fcp->c_mtrstate[unit] == FMS_ON && 20997c478bd9Sstevel@tonic-gate (csb->csb_xstate == FXS_MTRON || csb->csb_xstate == FXS_HDST || 21007c478bd9Sstevel@tonic-gate csb->csb_xstate == FXS_DKCHGX)) 21017c478bd9Sstevel@tonic-gate newxstate = fdc_statemach(fcp); 21027c478bd9Sstevel@tonic-gate if (newxstate == -1) { 21037c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 21047c478bd9Sstevel@tonic-gate (CE_WARN, 21057c478bd9Sstevel@tonic-gate "fdc_motort unit %d: motor ready but bad xstate", 21067c478bd9Sstevel@tonic-gate (int)fjp->fj_unit)); 21077c478bd9Sstevel@tonic-gate fcp->c_csb.csb_cmdstat = EIO; 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate if (newxstate == -1 || newxstate == FXS_END) { 21107c478bd9Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 21117c478bd9Sstevel@tonic-gate cv_signal(&fcp->c_iocv); 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 21147c478bd9Sstevel@tonic-gate } 21157c478bd9Sstevel@tonic-gate 21167c478bd9Sstevel@tonic-gate /* 21177c478bd9Sstevel@tonic-gate * DMA interrupt service routine 21187c478bd9Sstevel@tonic-gate * 21197c478bd9Sstevel@tonic-gate * Called by EISA dma interrupt service routine when buffer chaining 21207c478bd9Sstevel@tonic-gate * is required. 21217c478bd9Sstevel@tonic-gate */ 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate ddi_dma_cookie_t * 21247c478bd9Sstevel@tonic-gate fdc_dmae_isr(struct fdcntlr *fcp) 21257c478bd9Sstevel@tonic-gate { 21267c478bd9Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 21277c478bd9Sstevel@tonic-gate off_t off; 21287c478bd9Sstevel@tonic-gate size_t len; 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate if (csb->csb_dmahandle && !csb->csb_cmdstat) { 21317c478bd9Sstevel@tonic-gate if (++csb->csb_dmacurrcookie < csb->csb_dmacookiecnt) { 21327c478bd9Sstevel@tonic-gate ddi_dma_nextcookie(csb->csb_dmahandle, 21337c478bd9Sstevel@tonic-gate &csb->csb_dmacookie); 21347c478bd9Sstevel@tonic-gate return (&csb->csb_dmacookie); 21357c478bd9Sstevel@tonic-gate } else if (++csb->csb_dmacurrwin < csb->csb_dmawincnt) { 21367c478bd9Sstevel@tonic-gate if (ddi_dma_getwin(csb->csb_dmahandle, 21377c478bd9Sstevel@tonic-gate csb->csb_dmacurrwin, &off, &len, 21387c478bd9Sstevel@tonic-gate &csb->csb_dmacookie, 21397c478bd9Sstevel@tonic-gate &csb->csb_dmacookiecnt) != DDI_SUCCESS) { 21407c478bd9Sstevel@tonic-gate return (NULL); 21417c478bd9Sstevel@tonic-gate } 21427c478bd9Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 21437c478bd9Sstevel@tonic-gate return (&csb->csb_dmacookie); 21447c478bd9Sstevel@tonic-gate } 21457c478bd9Sstevel@tonic-gate } else 21467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: unsolicited DMA interrupt\n"); 21477c478bd9Sstevel@tonic-gate return (NULL); 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate /* 21527c478bd9Sstevel@tonic-gate * returns: 21537c478bd9Sstevel@tonic-gate * 0 if all ok, 21547c478bd9Sstevel@tonic-gate * ENXIO - diskette not in drive 21557c478bd9Sstevel@tonic-gate * ETIMEDOUT - for immediate operations that timed out 21567c478bd9Sstevel@tonic-gate * EBUSY - if stupid chip is locked busy??? 21577c478bd9Sstevel@tonic-gate * ENOEXEC - for timeout during sending cmds to chip 21587c478bd9Sstevel@tonic-gate * 21597c478bd9Sstevel@tonic-gate * to sleep: set sleep 21607c478bd9Sstevel@tonic-gate * to check for disk changed: set change 21617c478bd9Sstevel@tonic-gate */ 21627c478bd9Sstevel@tonic-gate static int 21637c478bd9Sstevel@tonic-gate fdc_exec(struct fdcntlr *fcp, int sleep, int change) 21647c478bd9Sstevel@tonic-gate { 21657c478bd9Sstevel@tonic-gate struct ddi_dmae_req dmaereq; 21667c478bd9Sstevel@tonic-gate struct fcu_obj *fjp; 21677c478bd9Sstevel@tonic-gate struct fdcsb *csb; 21687c478bd9Sstevel@tonic-gate off_t off; 21697c478bd9Sstevel@tonic-gate size_t len; 21707c478bd9Sstevel@tonic-gate int unit; 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 21737c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_EXEC, 21747c478bd9Sstevel@tonic-gate (CE_CONT, "fdc_exec: sleep %x change %x\n", sleep, change)); 21757c478bd9Sstevel@tonic-gate csb = &fcp->c_csb; 21767c478bd9Sstevel@tonic-gate unit = csb->csb_drive; 21777c478bd9Sstevel@tonic-gate fjp = fcp->c_unit[unit]; 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFINRPT) { 21807c478bd9Sstevel@tonic-gate if (*csb->csb_cmd == FO_RECAL) 21817c478bd9Sstevel@tonic-gate csb->csb_npcyl = 0; 21827c478bd9Sstevel@tonic-gate else if ((*csb->csb_cmd & ~FO_MFM) != FO_FRMT) 21837c478bd9Sstevel@tonic-gate csb->csb_npcyl = 21847c478bd9Sstevel@tonic-gate csb->csb_cmd[2] * fjp->fj_chars->fdc_steps; 21857c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_START; 21867c478bd9Sstevel@tonic-gate } else 21877c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_DOIT; 21887c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 21897c478bd9Sstevel@tonic-gate csb->csb_ourtrys = 0; 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate if (csb->csb_dmahandle) { 21927c478bd9Sstevel@tonic-gate /* ensure that entire format xfer is in one cookie */ 21937c478bd9Sstevel@tonic-gate /* 21947c478bd9Sstevel@tonic-gate * The change from ddi_dma_buf/addr_setup() to 21957c478bd9Sstevel@tonic-gate * ddi_dma_buf/addr_bind_handle() has already loaded 21967c478bd9Sstevel@tonic-gate * the first DMA window and cookie. 21977c478bd9Sstevel@tonic-gate */ 21987c478bd9Sstevel@tonic-gate if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT && 21997c478bd9Sstevel@tonic-gate (4 * csb->csb_cmd[3]) != csb->csb_dmacookie.dmac_size) { 22007c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 22017c478bd9Sstevel@tonic-gate return (EINVAL); 22027c478bd9Sstevel@tonic-gate } 22037c478bd9Sstevel@tonic-gate } 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate retry: 22067c478bd9Sstevel@tonic-gate if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) { 22077c478bd9Sstevel@tonic-gate fcp->c_curunit = unit; 22087c478bd9Sstevel@tonic-gate fjp->fj_flags |= FUNIT_CHAROK; 22097c478bd9Sstevel@tonic-gate if (fjp->fj_chars->fdc_transfer_rate == 417) { 22107c478bd9Sstevel@tonic-gate /* XXX hack for fdformat */ 22117c478bd9Sstevel@tonic-gate /* fjp->fj_chars->fdc_transfer_rate == 500; */ 22127c478bd9Sstevel@tonic-gate fjp->fj_attr->fda_rotatespd = 360; 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate if (fdcspecify(fcp, fjp->fj_chars->fdc_transfer_rate, 22157c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_steprate, 40)) 22167c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 22177c478bd9Sstevel@tonic-gate "fdc_select: controller setup rejected " 22187c478bd9Sstevel@tonic-gate "fdcntrl %p transfer rate %x step rate %x " 22197c478bd9Sstevel@tonic-gate "head load time 40\n", (void*)fcp, 22207c478bd9Sstevel@tonic-gate fjp->fj_chars->fdc_transfer_rate, 22217c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_steprate); 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 22247c478bd9Sstevel@tonic-gate if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) { 22257c478bd9Sstevel@tonic-gate /* 3D drive requires 500 ms for speed change */ 22267c478bd9Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5); 22277c478bd9Sstevel@tonic-gate /* 22287c478bd9Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 22297c478bd9Sstevel@tonic-gate */ 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 22327c478bd9Sstevel@tonic-gate } 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate /* 22357c478bd9Sstevel@tonic-gate * If checking for disk_change is enabled 22367c478bd9Sstevel@tonic-gate * (i.e. not seeking in fdresetchng), 22377c478bd9Sstevel@tonic-gate * we sample the DSKCHG line to see if the diskette has wandered away. 22387c478bd9Sstevel@tonic-gate */ 22397c478bd9Sstevel@tonic-gate if (change && fdcsense_chng(fcp, unit)) { 22407c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 22417c478bd9Sstevel@tonic-gate (CE_WARN, "diskette %d changed!!!", csb->csb_drive)); 22427c478bd9Sstevel@tonic-gate fcp->c_unit[unit]->fj_flags |= FUNIT_CHANGED; 22437c478bd9Sstevel@tonic-gate /* 22447c478bd9Sstevel@tonic-gate * If the diskette is still gone... so are we, adios! 22457c478bd9Sstevel@tonic-gate */ 22467c478bd9Sstevel@tonic-gate if (fdcheckdisk(fcp, unit)) { 22477c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate /* VP/ix expects an EBUSY return here */ 22507c478bd9Sstevel@tonic-gate if (*csb->csb_cmd == FO_SDRV) { 22517c478bd9Sstevel@tonic-gate return (EBUSY); 22527c478bd9Sstevel@tonic-gate } 22537c478bd9Sstevel@tonic-gate return (ENXIO); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate /* 22567c478bd9Sstevel@tonic-gate * delay to ensure that new diskette is up to speed 22577c478bd9Sstevel@tonic-gate */ 22587c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 22597c478bd9Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 22607c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_motoron); 22617c478bd9Sstevel@tonic-gate /* 22627c478bd9Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 22637c478bd9Sstevel@tonic-gate */ 22647c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate /* 22687c478bd9Sstevel@tonic-gate * gather some statistics 22697c478bd9Sstevel@tonic-gate */ 22707c478bd9Sstevel@tonic-gate switch (csb->csb_cmd[0] & 0x1f) { 22717c478bd9Sstevel@tonic-gate case FO_RDDAT: 22727c478bd9Sstevel@tonic-gate fcp->fdstats.rd++; 22737c478bd9Sstevel@tonic-gate break; 22747c478bd9Sstevel@tonic-gate case FO_WRDAT: 22757c478bd9Sstevel@tonic-gate fcp->fdstats.wr++; 22767c478bd9Sstevel@tonic-gate break; 22777c478bd9Sstevel@tonic-gate case FO_RECAL: 22787c478bd9Sstevel@tonic-gate fcp->fdstats.recal++; 22797c478bd9Sstevel@tonic-gate break; 22807c478bd9Sstevel@tonic-gate case FO_FRMT: 22817c478bd9Sstevel@tonic-gate fcp->fdstats.form++; 22827c478bd9Sstevel@tonic-gate break; 22837c478bd9Sstevel@tonic-gate default: 22847c478bd9Sstevel@tonic-gate fcp->fdstats.other++; 22857c478bd9Sstevel@tonic-gate break; 22867c478bd9Sstevel@tonic-gate } 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate bzero(csb->csb_rslt, 10); 22897c478bd9Sstevel@tonic-gate csb->csb_cmdstat = 0; 22907c478bd9Sstevel@tonic-gate 22917c478bd9Sstevel@tonic-gate if (csb->csb_dmahandle) { 22927c478bd9Sstevel@tonic-gate bzero(&dmaereq, sizeof (struct ddi_dmae_req)); 22937c478bd9Sstevel@tonic-gate dmaereq.der_command = (csb->csb_opflags & CSB_OFDMAWT) ? 22947c478bd9Sstevel@tonic-gate DMAE_CMD_WRITE : DMAE_CMD_READ; 22957c478bd9Sstevel@tonic-gate /* 22967c478bd9Sstevel@tonic-gate * setup for dma buffer chaining regardless of bus capability 22977c478bd9Sstevel@tonic-gate */ 22987c478bd9Sstevel@tonic-gate dmaereq.der_bufprocess = DMAE_BUF_CHAIN; 22997c478bd9Sstevel@tonic-gate dmaereq.proc = fdc_dmae_isr; 23007c478bd9Sstevel@tonic-gate dmaereq.procparms = (void *)fcp; 23017c478bd9Sstevel@tonic-gate if (ddi_dmae_prog(fcp->c_dip, &dmaereq, &csb->csb_dmacookie, 23027c478bd9Sstevel@tonic-gate fcp->c_dmachan) != DDI_SUCCESS) 23037c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc_exec: dmae prog failed, " 23047c478bd9Sstevel@tonic-gate "dip %p, dmachan %x\n", 23057c478bd9Sstevel@tonic-gate (void*)fcp->c_dip, fcp->c_dmachan); 23067c478bd9Sstevel@tonic-gate } 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate if ((fdc_statemach(fcp) == FXS_DOWT) && !sleep) { 23097c478bd9Sstevel@tonic-gate /* 23107c478bd9Sstevel@tonic-gate * If the operation has no results - then just return 23117c478bd9Sstevel@tonic-gate */ 23127c478bd9Sstevel@tonic-gate if (!csb->csb_nrslts) { 23137c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23147c478bd9Sstevel@tonic-gate return (0); 23157c478bd9Sstevel@tonic-gate } 23167c478bd9Sstevel@tonic-gate /* 23177c478bd9Sstevel@tonic-gate * this operation has no interrupt and an immediate result 23187c478bd9Sstevel@tonic-gate * so wait for the results and stuff them into the csb 23197c478bd9Sstevel@tonic-gate */ 23207c478bd9Sstevel@tonic-gate if (fdc_statemach(fcp) == -1) { 23217c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23227c478bd9Sstevel@tonic-gate return (EIO); 23237c478bd9Sstevel@tonic-gate } 23247c478bd9Sstevel@tonic-gate } else { 23257c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 23267c478bd9Sstevel@tonic-gate /* 23277c478bd9Sstevel@tonic-gate * wait for completion interrupt 23287c478bd9Sstevel@tonic-gate */ 23297c478bd9Sstevel@tonic-gate while (fcp->c_flags & FCFLG_WAITING) { 23307c478bd9Sstevel@tonic-gate cv_wait(&fcp->c_iocv, &fcp->c_lock); 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate /* 23357c478bd9Sstevel@tonic-gate * See if there was an error detected, if so, fdrecover() 23367c478bd9Sstevel@tonic-gate * will check it out and say what to do. 23377c478bd9Sstevel@tonic-gate * 23387c478bd9Sstevel@tonic-gate * Don't do this, though, if this was the Sense Drive Status 23397c478bd9Sstevel@tonic-gate * or the Dump Registers command. 23407c478bd9Sstevel@tonic-gate */ 23417c478bd9Sstevel@tonic-gate if (csb->csb_cmdstat && *csb->csb_cmd != FO_SDRV) { 23427c478bd9Sstevel@tonic-gate /* if it can restarted OK, then do so, else return error */ 23437c478bd9Sstevel@tonic-gate if (fdrecover(fcp)) { 23447c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23457c478bd9Sstevel@tonic-gate return (EIO); 23467c478bd9Sstevel@tonic-gate } 23477c478bd9Sstevel@tonic-gate /* ASSUMES that cmd is still intact in csb */ 23487c478bd9Sstevel@tonic-gate if (csb->csb_xstate == FXS_END) 23497c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_START; 23507c478bd9Sstevel@tonic-gate if (fdc_dma_attr.dma_attr_sgllen > 1 && csb->csb_dmahandle) { 23517c478bd9Sstevel@tonic-gate /* 23527c478bd9Sstevel@tonic-gate * restarted read/write operation requires 23537c478bd9Sstevel@tonic-gate * first DMA cookie of current window 23547c478bd9Sstevel@tonic-gate */ 23557c478bd9Sstevel@tonic-gate if (ddi_dma_getwin(csb->csb_dmahandle, 23567c478bd9Sstevel@tonic-gate csb->csb_dmacurrwin, &off, &len, 23577c478bd9Sstevel@tonic-gate &csb->csb_dmacookie, 23587c478bd9Sstevel@tonic-gate &csb->csb_dmacookiecnt) != DDI_SUCCESS) { 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23617c478bd9Sstevel@tonic-gate return (EIO); 23627c478bd9Sstevel@tonic-gate } 23637c478bd9Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 23647c478bd9Sstevel@tonic-gate } 23657c478bd9Sstevel@tonic-gate goto retry; 23667c478bd9Sstevel@tonic-gate } 23677c478bd9Sstevel@tonic-gate /* things went ok */ 23687c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23697c478bd9Sstevel@tonic-gate return (0); 23707c478bd9Sstevel@tonic-gate } 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate /* 23737c478bd9Sstevel@tonic-gate * fdcheckdisk 23747c478bd9Sstevel@tonic-gate * called by fdc_exec to check if the disk is still there - do a seek 23757c478bd9Sstevel@tonic-gate * then see if DSKCHG line went away; if so, diskette is in; else 23767c478bd9Sstevel@tonic-gate * it's (still) out. 23777c478bd9Sstevel@tonic-gate */ 23787c478bd9Sstevel@tonic-gate int 23797c478bd9Sstevel@tonic-gate fdcheckdisk(struct fdcntlr *fcp, int unit) 23807c478bd9Sstevel@tonic-gate { 23817c478bd9Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 23827c478bd9Sstevel@tonic-gate int newcyl; /* where to seek for reset of DSKCHG */ 23837c478bd9Sstevel@tonic-gate int rval; 23847c478bd9Sstevel@tonic-gate enum fxstate save_xstate; 23857c478bd9Sstevel@tonic-gate uchar_t save_cmd, save_cd1, save_npcyl; 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_lock)); 23887c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_CHEK, 23897c478bd9Sstevel@tonic-gate (CE_CONT, "fdcheckdisk unit %d\n", unit)); 23907c478bd9Sstevel@tonic-gate 23917c478bd9Sstevel@tonic-gate if (fcp->c_curpcyl[unit]) 23927c478bd9Sstevel@tonic-gate newcyl = fcp->c_curpcyl[unit] - 1; 23937c478bd9Sstevel@tonic-gate else 23947c478bd9Sstevel@tonic-gate newcyl = 1; 23957c478bd9Sstevel@tonic-gate 23967c478bd9Sstevel@tonic-gate save_cmd = *csb->csb_cmd; 23977c478bd9Sstevel@tonic-gate save_cd1 = csb->csb_cmd[1]; 23987c478bd9Sstevel@tonic-gate save_npcyl = csb->csb_npcyl; 23997c478bd9Sstevel@tonic-gate save_xstate = csb->csb_xstate; 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate *csb->csb_cmd = FO_SEEK; 24027c478bd9Sstevel@tonic-gate csb->csb_cmd[1] = (uchar_t)unit; 24037c478bd9Sstevel@tonic-gate csb->csb_npcyl = (uchar_t)newcyl; 24047c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 24057c478bd9Sstevel@tonic-gate 24067c478bd9Sstevel@tonic-gate if (fcp->c_mtrstate[unit] != FMS_ON && fcp->c_motort[unit] != 0) 24077c478bd9Sstevel@tonic-gate /* 24087c478bd9Sstevel@tonic-gate * wait for motor to get up to speed, 24097c478bd9Sstevel@tonic-gate * and let motor_timer issue seek cmd 24107c478bd9Sstevel@tonic-gate */ 24117c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_DKCHGX; 24127c478bd9Sstevel@tonic-gate else { 24137c478bd9Sstevel@tonic-gate /* 24147c478bd9Sstevel@tonic-gate * motor is up to speed; issue seek cmd now 24157c478bd9Sstevel@tonic-gate */ 24167c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_SEEK; 24177c478bd9Sstevel@tonic-gate if (rval = fdcseek(fcp, unit, newcyl)) { 24187c478bd9Sstevel@tonic-gate /* 24197c478bd9Sstevel@tonic-gate * any recal/seek errors are too serious to attend to 24207c478bd9Sstevel@tonic-gate */ 24217c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_CHEK, 24227c478bd9Sstevel@tonic-gate (CE_WARN, "fdcheckdisk err %d", rval)); 24237c478bd9Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 24247c478bd9Sstevel@tonic-gate } 24257c478bd9Sstevel@tonic-gate } 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * wait for completion interrupt 24287c478bd9Sstevel@tonic-gate * XXX This should be backed up with a watchdog timer! 24297c478bd9Sstevel@tonic-gate */ 24307c478bd9Sstevel@tonic-gate while (fcp->c_flags & FCFLG_WAITING) { 24317c478bd9Sstevel@tonic-gate cv_wait(&fcp->c_iocv, &fcp->c_lock); 24327c478bd9Sstevel@tonic-gate } 24337c478bd9Sstevel@tonic-gate 24347c478bd9Sstevel@tonic-gate /* 24357c478bd9Sstevel@tonic-gate * if disk change still asserted, no diskette in drive! 24367c478bd9Sstevel@tonic-gate */ 24377c478bd9Sstevel@tonic-gate if (rval = fdcsense_chng(fcp, unit)) { 24387c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_CHEK, 24397c478bd9Sstevel@tonic-gate (CE_WARN, "fdcheckdisk no disk %d", unit)); 24407c478bd9Sstevel@tonic-gate } 24417c478bd9Sstevel@tonic-gate 24427c478bd9Sstevel@tonic-gate *csb->csb_cmd = save_cmd; 24437c478bd9Sstevel@tonic-gate csb->csb_cmd[1] = save_cd1; 24447c478bd9Sstevel@tonic-gate csb->csb_npcyl = save_npcyl; 24457c478bd9Sstevel@tonic-gate csb->csb_xstate = save_xstate; 24467c478bd9Sstevel@tonic-gate return (rval); 24477c478bd9Sstevel@tonic-gate } 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate static int 24507c478bd9Sstevel@tonic-gate fdrecover(struct fdcntlr *fcp) 24517c478bd9Sstevel@tonic-gate { 24527c478bd9Sstevel@tonic-gate struct fcu_obj *fjp; 24537c478bd9Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 24547c478bd9Sstevel@tonic-gate int residual; 24557c478bd9Sstevel@tonic-gate int unit; 24567c478bd9Sstevel@tonic-gate char *failure; 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 24597c478bd9Sstevel@tonic-gate (CE_NOTE, "fdrecover unit %d", csb->csb_drive)); 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate unit = csb->csb_drive; 24627c478bd9Sstevel@tonic-gate fjp = fcp->c_unit[unit]; 24637c478bd9Sstevel@tonic-gate if (fcp->c_flags & FCFLG_TIMEOUT) { 24647c478bd9Sstevel@tonic-gate fcp->c_flags ^= FCFLG_TIMEOUT; 24657c478bd9Sstevel@tonic-gate csb->csb_rslt[1] |= 0x08; 24667c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_RECO, 24677c478bd9Sstevel@tonic-gate (CE_WARN, "fd unit %d: %s timed out", csb->csb_drive, 24687c478bd9Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname)); 24697c478bd9Sstevel@tonic-gate } 24707c478bd9Sstevel@tonic-gate 24717c478bd9Sstevel@tonic-gate if (csb->csb_status & S0_SEKEND) 24727c478bd9Sstevel@tonic-gate fcp->c_curpcyl[unit] = -1; 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate switch (csb->csb_oldxs) { 24757c478bd9Sstevel@tonic-gate case FXS_RCAL: /* recalibrate */ 24767c478bd9Sstevel@tonic-gate case FXS_SEEK: /* seek */ 24777c478bd9Sstevel@tonic-gate case FXS_RESET: /* cntlr reset */ 24787c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN, 24797c478bd9Sstevel@tonic-gate "fd unit %d: %s error: st0=0x%x pcn=%d", csb->csb_drive, 24807c478bd9Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, 24817c478bd9Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1])); 24827c478bd9Sstevel@tonic-gate if (csb->csb_retrys++ < skretry && 24837c478bd9Sstevel@tonic-gate !(csb->csb_opflags & CSB_OFRAWIOCTL)) 24847c478bd9Sstevel@tonic-gate return (0); 24857c478bd9Sstevel@tonic-gate break; 24867c478bd9Sstevel@tonic-gate 24877c478bd9Sstevel@tonic-gate case FXS_RDID: /* read ID */ 24887c478bd9Sstevel@tonic-gate if (!(csb->csb_status & S0_SEKEND)) 24897c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_HDST; 24907c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 24917c478bd9Sstevel@tonic-gate case FXS_DOIT: /* original operation */ 24927c478bd9Sstevel@tonic-gate case FXS_DOWT: /* waiting on operation */ 24937c478bd9Sstevel@tonic-gate if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) { 24947c478bd9Sstevel@tonic-gate if (ddi_dmae_getcnt(fcp->c_dip, fcp->c_dmachan, 24957c478bd9Sstevel@tonic-gate &residual) != DDI_SUCCESS) 24967c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 24977c478bd9Sstevel@tonic-gate "fdc_recover: dmae getcnt failed, " 24987c478bd9Sstevel@tonic-gate "dip %p dmachan %x residual %x\n", 24997c478bd9Sstevel@tonic-gate (void*)fcp->c_dip, fcp->c_dmachan, 25007c478bd9Sstevel@tonic-gate residual); 25017c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 25022df1fe9cSrandyf (CE_NOTE, 25032df1fe9cSrandyf "fd unit %d: %s error: " 25042df1fe9cSrandyf "dma count=0x%lx residual=0x%x", 25057c478bd9Sstevel@tonic-gate csb->csb_drive, 25067c478bd9Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, 25077c478bd9Sstevel@tonic-gate csb->csb_dmacookie.dmac_size, residual)); 25087c478bd9Sstevel@tonic-gate } 25097c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] == S1_OVRUN) 25107c478bd9Sstevel@tonic-gate /* 25117c478bd9Sstevel@tonic-gate * handle retries of over/underrun 25127c478bd9Sstevel@tonic-gate * with a secondary retry counter 25137c478bd9Sstevel@tonic-gate */ 25147c478bd9Sstevel@tonic-gate if (++csb->csb_ourtrys <= OURUN_TRIES) { 25157c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 25162df1fe9cSrandyf (CE_NOTE, 25172df1fe9cSrandyf "fd unit %d: %s error: over/under-run", 25182df1fe9cSrandyf csb->csb_drive, 25192df1fe9cSrandyf fdcmds[*csb->csb_cmd & 0x1f].cmdname)); 25207c478bd9Sstevel@tonic-gate return (0); 25217c478bd9Sstevel@tonic-gate } else 25227c478bd9Sstevel@tonic-gate /* 25237c478bd9Sstevel@tonic-gate * count 1 set of over/underruns 25247c478bd9Sstevel@tonic-gate * as 1 primary retry effort 25257c478bd9Sstevel@tonic-gate */ 25267c478bd9Sstevel@tonic-gate csb->csb_ourtrys = 0; 25277c478bd9Sstevel@tonic-gate 25287c478bd9Sstevel@tonic-gate if ((fjp->fj_flags & (FUNIT_UNLABELED | FUNIT_LABELOK)) && 25297c478bd9Sstevel@tonic-gate !(csb->csb_opflags & CSB_OFRAWIOCTL)) { 25307c478bd9Sstevel@tonic-gate /* 25317c478bd9Sstevel@tonic-gate * device is open so keep trying and 25327c478bd9Sstevel@tonic-gate * gather statistics on errors 25337c478bd9Sstevel@tonic-gate */ 25347c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & S1_CRCER) 25357c478bd9Sstevel@tonic-gate fcp->fdstats.de++; 25367c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & S1_OVRUN) 25377c478bd9Sstevel@tonic-gate fcp->fdstats.run++; 25387c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK)) 25397c478bd9Sstevel@tonic-gate fcp->fdstats.bfmt++; 25407c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & 0x08) 25417c478bd9Sstevel@tonic-gate fcp->fdstats.to++; 25427c478bd9Sstevel@tonic-gate 25437c478bd9Sstevel@tonic-gate /* 25447c478bd9Sstevel@tonic-gate * if we have not run out of retries, return 0 25457c478bd9Sstevel@tonic-gate */ 25467c478bd9Sstevel@tonic-gate if (csb->csb_retrys++ < csb->csb_maxretry && 25477c478bd9Sstevel@tonic-gate (*csb->csb_cmd & ~FO_MFM) != FO_FRMT) { 25487c478bd9Sstevel@tonic-gate if (csb->csb_opflags & 25497c478bd9Sstevel@tonic-gate (CSB_OFDMARD | CSB_OFDMAWT)) { 25507c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_RECO, 25512df1fe9cSrandyf (CE_WARN, 25522df1fe9cSrandyf "fd unit %d: %s error: " 25532df1fe9cSrandyf "st0=0x%x st1=0x%x st2=0x%x", 25547c478bd9Sstevel@tonic-gate csb->csb_drive, 25552df1fe9cSrandyf fdcmds[*csb->csb_cmd & 25562df1fe9cSrandyf 0x1f].cmdname, 25577c478bd9Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], 25587c478bd9Sstevel@tonic-gate csb->csb_rslt[2])); 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate if ((csb->csb_retrys & 1) && 25617c478bd9Sstevel@tonic-gate csb->csb_xstate == FXS_END) 25627c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_DOIT; 25637c478bd9Sstevel@tonic-gate else if (csb->csb_retrys == 3) 25647c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RESTART; 25657c478bd9Sstevel@tonic-gate return (0); 25667c478bd9Sstevel@tonic-gate } 25677c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & S1_CRCER) 25687c478bd9Sstevel@tonic-gate failure = "crc error"; 25697c478bd9Sstevel@tonic-gate else if (csb->csb_rslt[1] & S1_OVRUN) 25707c478bd9Sstevel@tonic-gate failure = "over/under-run"; 25717c478bd9Sstevel@tonic-gate else if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK)) 25727c478bd9Sstevel@tonic-gate failure = "bad format"; 25737c478bd9Sstevel@tonic-gate else if (csb->csb_rslt[1] & 0x08) 25747c478bd9Sstevel@tonic-gate failure = "timeout"; 25757c478bd9Sstevel@tonic-gate else 25767c478bd9Sstevel@tonic-gate failure = "failed"; 25777c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "!fd unit %d: %s %s (%x %x %x)", 25787c478bd9Sstevel@tonic-gate csb->csb_drive, 25797c478bd9Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, failure, 25807c478bd9Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2]); 25817c478bd9Sstevel@tonic-gate } else { 25827c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 25837c478bd9Sstevel@tonic-gate (CE_NOTE, "fd unit %d: %s failed (%x %x %x)", 25847c478bd9Sstevel@tonic-gate csb->csb_drive, 25857c478bd9Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, 25867c478bd9Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], 25877c478bd9Sstevel@tonic-gate csb->csb_rslt[2])); 25887c478bd9Sstevel@tonic-gate } 25897c478bd9Sstevel@tonic-gate break; 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate default: 25927c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN, 25937c478bd9Sstevel@tonic-gate "fd unit %d: %s failed: st0=0x%x st1=0x%x st2=0x%x", 25947c478bd9Sstevel@tonic-gate csb->csb_drive, fdcmds[*csb->csb_cmd & 0x1f].cmdname, 25957c478bd9Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2])); 25967c478bd9Sstevel@tonic-gate break; 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate return (1); 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate 26027c478bd9Sstevel@tonic-gate /* Autovector Interrupt Entry Point */ 26037c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26047c478bd9Sstevel@tonic-gate static uint_t 26057c478bd9Sstevel@tonic-gate fdc_intr(caddr_t arg) 26067c478bd9Sstevel@tonic-gate { 26077c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = (struct fdcntlr *)arg; 26087c478bd9Sstevel@tonic-gate struct fdcsb *csb; 26097c478bd9Sstevel@tonic-gate off_t off; 26107c478bd9Sstevel@tonic-gate size_t blklen; 26117c478bd9Sstevel@tonic-gate int drive; 26127c478bd9Sstevel@tonic-gate int newstate; 26137c478bd9Sstevel@tonic-gate int pendstate; 26147c478bd9Sstevel@tonic-gate int rval = DDI_DMA_DONE; 26157c478bd9Sstevel@tonic-gate int state; 26167c478bd9Sstevel@tonic-gate int maxspin = 10; 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate csb = &fcp->c_csb; 26197c478bd9Sstevel@tonic-gate 26207c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 26217c478bd9Sstevel@tonic-gate /* 26227c478bd9Sstevel@tonic-gate * Wait for the RQM bit to be set, or until we've tested it 26237c478bd9Sstevel@tonic-gate * a bunch of times (which may imply this isn't our interrupt). 26247c478bd9Sstevel@tonic-gate */ 26257c478bd9Sstevel@tonic-gate state = inb(fcp->c_regbase + FCR_MSR); 26267c478bd9Sstevel@tonic-gate pendstate = state & (MS_RQM | MS_DIO | MS_CB); 26277c478bd9Sstevel@tonic-gate while (((pendstate & MS_RQM) == 0) && (maxspin-- > 0)) { 26287c478bd9Sstevel@tonic-gate /* Small pause in between reading the status port */ 26297c478bd9Sstevel@tonic-gate drv_usecwait(10); 26307c478bd9Sstevel@tonic-gate /* Reread the status port */ 26317c478bd9Sstevel@tonic-gate state = inb(fcp->c_regbase + FCR_MSR); 26327c478bd9Sstevel@tonic-gate pendstate = state & (MS_RQM | MS_DIO | MS_CB); 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_INTR, 26357c478bd9Sstevel@tonic-gate (CE_CONT, "fdc_intr unit %d: xstate=%d MSR=0x%x\n", 26367c478bd9Sstevel@tonic-gate csb->csb_drive, csb->csb_xstate, state)); 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate /* 26397c478bd9Sstevel@tonic-gate * If there is an operation outstanding AND the controller is ready 26407c478bd9Sstevel@tonic-gate * to receive a command or send us the result of a command (OR if the 26417c478bd9Sstevel@tonic-gate * controller is ready to accept a new command), AND if 26427c478bd9Sstevel@tonic-gate * someone has been waiting for a command to finish AND (if no unit 26437c478bd9Sstevel@tonic-gate * is BUSY OR if the unit that we're waiting for is BUSY (i.e. it's in 26447c478bd9Sstevel@tonic-gate * the middle of a seek/recalibrate)) then this interrupt is for us. 26457c478bd9Sstevel@tonic-gate */ 26467c478bd9Sstevel@tonic-gate if ((pendstate == (MS_RQM | MS_DIO | MS_CB) || pendstate == MS_RQM) && 26477c478bd9Sstevel@tonic-gate (fcp->c_flags & FCFLG_WAITING) && 26487c478bd9Sstevel@tonic-gate (!(state & 0x0f) || ((1 << csb->csb_drive) & state))) { 26497c478bd9Sstevel@tonic-gate /* 26507c478bd9Sstevel@tonic-gate * Remove one of the conditions for entering this code. 26517c478bd9Sstevel@tonic-gate * The state_machine will release the c_lock if it 26527c478bd9Sstevel@tonic-gate * calls untimeout() 26537c478bd9Sstevel@tonic-gate */ 26547c478bd9Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 26557c478bd9Sstevel@tonic-gate 26567c478bd9Sstevel@tonic-gate if ((newstate = fdc_statemach(fcp)) == -1) { 26577c478bd9Sstevel@tonic-gate /* restore waiting flag */ 26587c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 26597c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 26607c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 26617c478bd9Sstevel@tonic-gate } 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate if (fcp->c_intrstat) 26647c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 26657c478bd9Sstevel@tonic-gate if (newstate == FXS_END) { 26667c478bd9Sstevel@tonic-gate 26677c478bd9Sstevel@tonic-gate if (csb->csb_dmahandle && !csb->csb_cmdstat && 26687c478bd9Sstevel@tonic-gate /* 26697c478bd9Sstevel@tonic-gate * read/write operation may have multiple DMA 26707c478bd9Sstevel@tonic-gate * cookies: process next one 26717c478bd9Sstevel@tonic-gate */ 26727c478bd9Sstevel@tonic-gate ((csb->csb_dmacurrcookie < 26737c478bd9Sstevel@tonic-gate (csb->csb_dmacookiecnt - 1)) || 26747c478bd9Sstevel@tonic-gate (csb->csb_dmacurrwin) < (csb->csb_dmawincnt - 1))) { 26757c478bd9Sstevel@tonic-gate /* 26767c478bd9Sstevel@tonic-gate * read/write operation requires another 26777c478bd9Sstevel@tonic-gate * DMA cookie: process next one 26787c478bd9Sstevel@tonic-gate */ 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate if (++csb->csb_dmacurrcookie < 26817c478bd9Sstevel@tonic-gate csb->csb_dmacookiecnt) { 26827c478bd9Sstevel@tonic-gate ddi_dma_nextcookie(csb->csb_dmahandle, 26837c478bd9Sstevel@tonic-gate &csb->csb_dmacookie); 26847c478bd9Sstevel@tonic-gate } else if (++csb->csb_dmacurrwin < 26857c478bd9Sstevel@tonic-gate csb->csb_dmawincnt) { 26867c478bd9Sstevel@tonic-gate if (ddi_dma_getwin(csb->csb_dmahandle, 26877c478bd9Sstevel@tonic-gate csb->csb_dmacurrwin, &off, &blklen, 26887c478bd9Sstevel@tonic-gate &csb->csb_dmacookie, 26897c478bd9Sstevel@tonic-gate &csb->csb_dmacookiecnt) != 26907c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 26917c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 26927c478bd9Sstevel@tonic-gate "fdc_intr: " 26937c478bd9Sstevel@tonic-gate "dma getwin failed\n"); 26947c478bd9Sstevel@tonic-gate } 26957c478bd9Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 26967c478bd9Sstevel@tonic-gate } 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate if (ddi_dmae_prog(fcp->c_dip, NULL, 26997c478bd9Sstevel@tonic-gate &csb->csb_dmacookie, fcp->c_dmachan) != 27007c478bd9Sstevel@tonic-gate DDI_SUCCESS) 27017c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 27027c478bd9Sstevel@tonic-gate "fdc_intr: dmae prog failed, " 27037c478bd9Sstevel@tonic-gate "dip %p dmachannel %x\n", 27047c478bd9Sstevel@tonic-gate (void*)fcp->c_dip, 27057c478bd9Sstevel@tonic-gate fcp->c_dmachan); 27067c478bd9Sstevel@tonic-gate 27077c478bd9Sstevel@tonic-gate /* 27087c478bd9Sstevel@tonic-gate * status of last operation has disk 27097c478bd9Sstevel@tonic-gate * address for continuation 27107c478bd9Sstevel@tonic-gate */ 27117c478bd9Sstevel@tonic-gate csb->csb_cmd[2] = csb->csb_rslt[3]; 27127c478bd9Sstevel@tonic-gate csb->csb_cmd[3] = csb->csb_rslt[4]; 27137c478bd9Sstevel@tonic-gate csb->csb_cmd[4] = csb->csb_rslt[5]; 27147c478bd9Sstevel@tonic-gate csb->csb_cmd[1] = (csb->csb_cmd[1] & ~0x04) | 27157c478bd9Sstevel@tonic-gate (csb->csb_cmd[3] << 2); 27167c478bd9Sstevel@tonic-gate 27177c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_START; 27187c478bd9Sstevel@tonic-gate (void) fdc_statemach(fcp); 27197c478bd9Sstevel@tonic-gate /* 27207c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning already 27217c478bd9Sstevel@tonic-gate * posted. Returned state irrelevant. 27227c478bd9Sstevel@tonic-gate */ 27237c478bd9Sstevel@tonic-gate /* restore waiting flag */ 27247c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 27257c478bd9Sstevel@tonic-gate goto fi_exit; 27267c478bd9Sstevel@tonic-gate } 27277c478bd9Sstevel@tonic-gate if (rval != DDI_DMA_DONE) 27287c478bd9Sstevel@tonic-gate csb->csb_cmdstat = EIO; 27297c478bd9Sstevel@tonic-gate /* 27307c478bd9Sstevel@tonic-gate * somebody's waiting for completion of fdcntlr/csb, 27317c478bd9Sstevel@tonic-gate * wake them 27327c478bd9Sstevel@tonic-gate */ 27337c478bd9Sstevel@tonic-gate cv_signal(&fcp->c_iocv); 27347c478bd9Sstevel@tonic-gate } 27357c478bd9Sstevel@tonic-gate else 27367c478bd9Sstevel@tonic-gate /* restore waiting flag */ 27377c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 27387c478bd9Sstevel@tonic-gate fi_exit: 27397c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 27407c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 27417c478bd9Sstevel@tonic-gate } 27427c478bd9Sstevel@tonic-gate 27437c478bd9Sstevel@tonic-gate if (state & MS_RQM) { 27447c478bd9Sstevel@tonic-gate (void) fdcsense_int(fcp, &drive, NULL); 27457c478bd9Sstevel@tonic-gate /* 27467c478bd9Sstevel@tonic-gate * Ignored return - senser state already saved 27477c478bd9Sstevel@tonic-gate */ 27487c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_INTR, 27497c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_intr unit %d: nobody sleeping 0x%x", 27507c478bd9Sstevel@tonic-gate drive, state)); 27517c478bd9Sstevel@tonic-gate } else { 27527c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_INTR, 27537c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_intr: nobody sleeping on %d 0x%x", 27547c478bd9Sstevel@tonic-gate csb->csb_drive, state)); 27557c478bd9Sstevel@tonic-gate } 27567c478bd9Sstevel@tonic-gate /* 27577c478bd9Sstevel@tonic-gate * This should probably be protected, but, what the 27587c478bd9Sstevel@tonic-gate * heck...the cost isn't worth the accuracy for this 27597c478bd9Sstevel@tonic-gate * statistic. 27607c478bd9Sstevel@tonic-gate */ 27617c478bd9Sstevel@tonic-gate if (fcp->c_intrstat) 27627c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 27637c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 27647c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 27657c478bd9Sstevel@tonic-gate } 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate /* 27687c478bd9Sstevel@tonic-gate * fdwatch 27697c478bd9Sstevel@tonic-gate * is called from timeout() when a floppy operation timer has expired. 27707c478bd9Sstevel@tonic-gate */ 27717c478bd9Sstevel@tonic-gate static void 27727c478bd9Sstevel@tonic-gate fdwatch(void *arg) 27737c478bd9Sstevel@tonic-gate { 27747c478bd9Sstevel@tonic-gate struct fdcntlr *fcp = (struct fdcntlr *)arg; 27757c478bd9Sstevel@tonic-gate struct fdcsb *csb; 27767c478bd9Sstevel@tonic-gate 27777c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate if (fcp->c_timeid == 0) { 27807c478bd9Sstevel@tonic-gate /* 27817c478bd9Sstevel@tonic-gate * fdc_intr got here first, ergo, no timeout condition.. 27827c478bd9Sstevel@tonic-gate */ 27837c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 27847c478bd9Sstevel@tonic-gate return; 27857c478bd9Sstevel@tonic-gate } 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate if (fcp->c_flags & FCFLG_WAITING) { 27887c478bd9Sstevel@tonic-gate if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS) 27897c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdwatch: dmae stop failed, " 27907c478bd9Sstevel@tonic-gate "dip %p, dmachan %x\n", 27917c478bd9Sstevel@tonic-gate (void*)fcp->c_dip, fcp->c_dmachan); 27927c478bd9Sstevel@tonic-gate csb = &fcp->c_csb; 27937c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_WATC, 27947c478bd9Sstevel@tonic-gate (CE_WARN, "fdcwatch unit %d: xstate = %d", 27957c478bd9Sstevel@tonic-gate csb->csb_drive, csb->csb_xstate)); 27967c478bd9Sstevel@tonic-gate drv_usecwait(50); 27977c478bd9Sstevel@tonic-gate 27987c478bd9Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_MSR) != MS_RQM) { 27997c478bd9Sstevel@tonic-gate /* 28007c478bd9Sstevel@tonic-gate * cntlr is still busy, so reset it 28017c478bd9Sstevel@tonic-gate */ 28027c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_KILL; 28037c478bd9Sstevel@tonic-gate (void) fdc_statemach(fcp); 28047c478bd9Sstevel@tonic-gate /* 28057c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning already 28067c478bd9Sstevel@tonic-gate * posted. Returned state irrelevant. 28077c478bd9Sstevel@tonic-gate */ 28087c478bd9Sstevel@tonic-gate } else { 28097c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_END; 28107c478bd9Sstevel@tonic-gate fcp->c_timeid = 0; 28117c478bd9Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 28127c478bd9Sstevel@tonic-gate cv_signal(&fcp->c_iocv); 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate csb->csb_cmdstat = EIO; 28157c478bd9Sstevel@tonic-gate fcp->c_flags |= FCFLG_TIMEOUT; 28167c478bd9Sstevel@tonic-gate } else { 28177c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_INTR, 28187c478bd9Sstevel@tonic-gate (CE_WARN, "fdcwatch: not sleeping for unit %d", 28197c478bd9Sstevel@tonic-gate fcp->c_csb.csb_drive)); 28207c478bd9Sstevel@tonic-gate } 28217c478bd9Sstevel@tonic-gate if (fcp->c_intrstat) 28227c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_WATCHDOG]++; 28237c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 28247c478bd9Sstevel@tonic-gate } 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate 28277c478bd9Sstevel@tonic-gate static int 28287c478bd9Sstevel@tonic-gate fdc_statemach(struct fdcntlr *fcp) 28297c478bd9Sstevel@tonic-gate { 28307c478bd9Sstevel@tonic-gate struct fcu_obj *fjp; 28317c478bd9Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 28327c478bd9Sstevel@tonic-gate int backoff; 28337c478bd9Sstevel@tonic-gate clock_t time; 28347c478bd9Sstevel@tonic-gate int unit; 28357c478bd9Sstevel@tonic-gate 28367c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_lock)); 28377c478bd9Sstevel@tonic-gate 28387c478bd9Sstevel@tonic-gate unit = csb->csb_drive; 28397c478bd9Sstevel@tonic-gate fjp = fcp->c_unit[unit]; 28407c478bd9Sstevel@tonic-gate 28417c478bd9Sstevel@tonic-gate csb->csb_oldxs = csb->csb_xstate; 28427c478bd9Sstevel@tonic-gate switch (csb->csb_xstate) { 28437c478bd9Sstevel@tonic-gate 28447c478bd9Sstevel@tonic-gate case FXS_START: /* start of operation */ 28457c478bd9Sstevel@tonic-gate ASSERT(fcp->c_timeid == 0); 28467c478bd9Sstevel@tonic-gate time = drv_usectohz(100000 * (unsigned int)csb->csb_timer); 28477c478bd9Sstevel@tonic-gate if (time == 0) 28487c478bd9Sstevel@tonic-gate time = drv_usectohz(2000000); 28497c478bd9Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate if (fcp->c_mtrstate[unit] == FMS_START) { 28527c478bd9Sstevel@tonic-gate /* 28537c478bd9Sstevel@tonic-gate * wait for motor to get up to speed 28547c478bd9Sstevel@tonic-gate */ 28557c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_MTRON; 28567c478bd9Sstevel@tonic-gate break; 28577c478bd9Sstevel@tonic-gate } 28587c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate case FXS_MTRON: /* motor is at speed */ 28617c478bd9Sstevel@tonic-gate if (fcp->c_mtrstate[unit] != FMS_ON) { 28627c478bd9Sstevel@tonic-gate /* how did we get here ?? */ 28637c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: selected but motor off"); 28647c478bd9Sstevel@tonic-gate return (-1); 28657c478bd9Sstevel@tonic-gate } 28667c478bd9Sstevel@tonic-gate if (fcp->c_curpcyl[unit] != -1 && *csb->csb_cmd != FO_RECAL) 28677c478bd9Sstevel@tonic-gate goto nxs_seek; 28687c478bd9Sstevel@tonic-gate recalcmd[1] = (uchar_t)unit; 28697c478bd9Sstevel@tonic-gate if (fdc_docmd(fcp, recalcmd, 2) == -1) { 28707c478bd9Sstevel@tonic-gate /* cntlr did not accept command bytes */ 28717c478bd9Sstevel@tonic-gate fdcquiesce(fcp); 28727c478bd9Sstevel@tonic-gate csb->csb_cmdstat = EIO; 28737c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 28747c478bd9Sstevel@tonic-gate break; 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate fcp->c_sekdir[unit] = 0; 28777c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RCAL; 28787c478bd9Sstevel@tonic-gate break; 28797c478bd9Sstevel@tonic-gate 28807c478bd9Sstevel@tonic-gate case FXS_RCAL: /* forced recalibrate is complete */ 28817c478bd9Sstevel@tonic-gate #if 0 /* #ifdef _VPIX */ 28827c478bd9Sstevel@tonic-gate /* WARNING: this code breaks SPARC compatibility */ 28837c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFRAWIOCTL && 28847c478bd9Sstevel@tonic-gate *csb->csb_cmd == FO_RECAL) { 28857c478bd9Sstevel@tonic-gate fcp->c_curpcyl[unit] = 0; 28867c478bd9Sstevel@tonic-gate csb->csb_status = 0; 28877c478bd9Sstevel@tonic-gate goto nxs_cmpl; 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate #endif 28907c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 28917c478bd9Sstevel@tonic-gate /* 28927c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 28937c478bd9Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 28947c478bd9Sstevel@tonic-gate */ 28957c478bd9Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 2); 28967c478bd9Sstevel@tonic-gate /* 28977c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 28987c478bd9Sstevel@tonic-gate * Actual results checked below 28997c478bd9Sstevel@tonic-gate */ 29007c478bd9Sstevel@tonic-gate if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 29017c478bd9Sstevel@tonic-gate (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) { 29027c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 29037c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_statemach unit %d: recal result %x", 29047c478bd9Sstevel@tonic-gate csb->csb_drive, *csb->csb_rslt)); 29057c478bd9Sstevel@tonic-gate fdcquiesce(fcp); 29067c478bd9Sstevel@tonic-gate csb->csb_cmdstat = EIO; 29077c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 29087c478bd9Sstevel@tonic-gate break; 29097c478bd9Sstevel@tonic-gate } 29107c478bd9Sstevel@tonic-gate if (unit != (*csb->csb_rslt & 3) || csb->csb_rslt[1]) { 29117c478bd9Sstevel@tonic-gate csb->csb_status = S0_SEKEND; 29127c478bd9Sstevel@tonic-gate goto nxs_cmpl; 29137c478bd9Sstevel@tonic-gate } 29147c478bd9Sstevel@tonic-gate fcp->c_curpcyl[unit] = csb->csb_rslt[1]; 29157c478bd9Sstevel@tonic-gate if (*csb->csb_cmd == FO_RECAL) 29167c478bd9Sstevel@tonic-gate goto nxs_cmpl; 29177c478bd9Sstevel@tonic-gate nxs_seek: 29187c478bd9Sstevel@tonic-gate if (*csb->csb_cmd != FO_SEEK && 29197c478bd9Sstevel@tonic-gate csb->csb_npcyl == fcp->c_curpcyl[unit]) 29207c478bd9Sstevel@tonic-gate goto nxs_doit; 29217c478bd9Sstevel@tonic-gate fcp->c_sekdir[unit] = csb->csb_npcyl - fcp->c_curpcyl[unit]; 29227c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate case FXS_DKCHGX: /* reset Disk-Change latch */ 29257c478bd9Sstevel@tonic-gate (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl); 29267c478bd9Sstevel@tonic-gate /* 29277c478bd9Sstevel@tonic-gate * Ignored return. If command rejected, warnig already posted 29287c478bd9Sstevel@tonic-gate * by fdc_docmd(). 29297c478bd9Sstevel@tonic-gate */ 29307c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_SEEK; 29317c478bd9Sstevel@tonic-gate break; 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate case FXS_RESTART: /* special restart of read/write operation */ 29347c478bd9Sstevel@tonic-gate ASSERT(fcp->c_timeid == 0); 29357c478bd9Sstevel@tonic-gate time = drv_usectohz(100000 * csb->csb_timer); 29367c478bd9Sstevel@tonic-gate if (time == 0) 29377c478bd9Sstevel@tonic-gate time = drv_usectohz(2000000); 29387c478bd9Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 29397c478bd9Sstevel@tonic-gate 29407c478bd9Sstevel@tonic-gate if (fcp->c_mtrstate[unit] != FMS_ON) { 29417c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: selected but motor off"); 29427c478bd9Sstevel@tonic-gate return (-1); 29437c478bd9Sstevel@tonic-gate } 29447c478bd9Sstevel@tonic-gate if ((csb->csb_npcyl == 0 || fcp->c_sekdir[unit] >= 0) && 29457c478bd9Sstevel@tonic-gate (int)csb->csb_cmd[2] < (fjp->fj_chars->fdc_ncyl - 1)) 29467c478bd9Sstevel@tonic-gate backoff = csb->csb_npcyl + 1; 29477c478bd9Sstevel@tonic-gate else 29487c478bd9Sstevel@tonic-gate backoff = csb->csb_npcyl - 1; 29497c478bd9Sstevel@tonic-gate (void) fdcseek(fcp, csb->csb_cmd[1], backoff); 29507c478bd9Sstevel@tonic-gate /* 29517c478bd9Sstevel@tonic-gate * Ignored return. If command rejected, warnig already posted 29527c478bd9Sstevel@tonic-gate * by fdc_docmd(). 29537c478bd9Sstevel@tonic-gate */ 29547c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RESEEK; 29557c478bd9Sstevel@tonic-gate break; 29567c478bd9Sstevel@tonic-gate 29577c478bd9Sstevel@tonic-gate case FXS_RESEEK: /* seek to backoff-cyl complete */ 29587c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 29597c478bd9Sstevel@tonic-gate /* 29607c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 29617c478bd9Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 29627c478bd9Sstevel@tonic-gate */ 29637c478bd9Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 2); 29647c478bd9Sstevel@tonic-gate /* 29657c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 29667c478bd9Sstevel@tonic-gate * Actual results checked below 29677c478bd9Sstevel@tonic-gate */ 29687c478bd9Sstevel@tonic-gate if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 29697c478bd9Sstevel@tonic-gate (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) 29707c478bd9Sstevel@tonic-gate goto nxs_cmpl; 29717c478bd9Sstevel@tonic-gate (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl); 29727c478bd9Sstevel@tonic-gate /* 29737c478bd9Sstevel@tonic-gate * Ignored return. If command rejected, warnig already posted 29747c478bd9Sstevel@tonic-gate * by fdc_docmd(). 29757c478bd9Sstevel@tonic-gate */ 29767c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_SEEK; 29777c478bd9Sstevel@tonic-gate break; 29787c478bd9Sstevel@tonic-gate 29797c478bd9Sstevel@tonic-gate case FXS_SEEK: /* seek complete */ 29807c478bd9Sstevel@tonic-gate #if 0 /* #ifdef _VPIX */ 29817c478bd9Sstevel@tonic-gate /* WARNING: this code breaks SPARC compatibility and */ 29827c478bd9Sstevel@tonic-gate /* rawioctls in fdformat */ 29837c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFRAWIOCTL) { 29847c478bd9Sstevel@tonic-gate fcp->c_curpcyl[unit] = csb->csb_npcyl; 29857c478bd9Sstevel@tonic-gate csb->csb_status = 0; 29867c478bd9Sstevel@tonic-gate goto nxs_cmpl; 29877c478bd9Sstevel@tonic-gate } 29887c478bd9Sstevel@tonic-gate #endif 29897c478bd9Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 29907c478bd9Sstevel@tonic-gate /* 29917c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 29927c478bd9Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 29937c478bd9Sstevel@tonic-gate */ 29947c478bd9Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 2); 29957c478bd9Sstevel@tonic-gate /* 29967c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 29977c478bd9Sstevel@tonic-gate * Actual results checked below 29987c478bd9Sstevel@tonic-gate */ 29997c478bd9Sstevel@tonic-gate if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 30007c478bd9Sstevel@tonic-gate (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) 30017c478bd9Sstevel@tonic-gate goto nxs_cmpl; 30027c478bd9Sstevel@tonic-gate if (unit != (*csb->csb_rslt & 3) || 30037c478bd9Sstevel@tonic-gate csb->csb_rslt[1] != csb->csb_npcyl) { 30047c478bd9Sstevel@tonic-gate csb->csb_status = S0_SEKEND; 30057c478bd9Sstevel@tonic-gate goto nxs_cmpl; 30067c478bd9Sstevel@tonic-gate }; 30077c478bd9Sstevel@tonic-gate fcp->c_curpcyl[unit] = csb->csb_rslt[1]; 30087c478bd9Sstevel@tonic-gate /* use motor_timer to delay for head settle */ 30097c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 30107c478bd9Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_DELAYCMD, 30117c478bd9Sstevel@tonic-gate fjp->fj_drive->fdd_headsettle / 1000); 30127c478bd9Sstevel@tonic-gate /* 30137c478bd9Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 30147c478bd9Sstevel@tonic-gate */ 30157c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 30167c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_HDST; 30177c478bd9Sstevel@tonic-gate break; 30187c478bd9Sstevel@tonic-gate 30197c478bd9Sstevel@tonic-gate case FXS_HDST: /* head settle */ 30207c478bd9Sstevel@tonic-gate if (*csb->csb_cmd == FO_SEEK) 30217c478bd9Sstevel@tonic-gate goto nxs_cmpl; 30227c478bd9Sstevel@tonic-gate if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT) 30237c478bd9Sstevel@tonic-gate goto nxs_doit; 30247c478bd9Sstevel@tonic-gate fdcreadid(fcp, csb); 30257c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RDID; 30267c478bd9Sstevel@tonic-gate break; 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate case FXS_RDID: /* read ID complete */ 30297c478bd9Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 7); 30307c478bd9Sstevel@tonic-gate /* 30317c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 30327c478bd9Sstevel@tonic-gate * Actual results checked below 30337c478bd9Sstevel@tonic-gate */ 30347c478bd9Sstevel@tonic-gate if ((csb->csb_status = (*csb->csb_rslt & 30357c478bd9Sstevel@tonic-gate (S0_ICMASK | S0_ECHK | S0_NOTRDY))) != 0) 30367c478bd9Sstevel@tonic-gate goto nxs_cmpl; 30377c478bd9Sstevel@tonic-gate if (csb->csb_cmd[2] != csb->csb_rslt[3]) { 30387c478bd9Sstevel@tonic-gate /* at wrong logical cylinder */ 30397c478bd9Sstevel@tonic-gate csb->csb_status = S0_SEKEND; 30407c478bd9Sstevel@tonic-gate goto nxs_cmpl; 30417c478bd9Sstevel@tonic-gate }; 30427c478bd9Sstevel@tonic-gate goto nxs_doit; 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate case FXS_DOIT: /* do original operation */ 30457c478bd9Sstevel@tonic-gate ASSERT(fcp->c_timeid == 0); 30467c478bd9Sstevel@tonic-gate time = drv_usectohz(100000 * csb->csb_timer); 30477c478bd9Sstevel@tonic-gate if (time == 0) 30487c478bd9Sstevel@tonic-gate time = drv_usectohz(2000000); 30497c478bd9Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 30507c478bd9Sstevel@tonic-gate nxs_doit: 30517c478bd9Sstevel@tonic-gate if (fdc_docmd(fcp, csb->csb_cmd, csb->csb_ncmds) == -1) { 30527c478bd9Sstevel@tonic-gate /* cntlr did not accept command bytes */ 30537c478bd9Sstevel@tonic-gate fdcquiesce(fcp); 30547c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 30557c478bd9Sstevel@tonic-gate csb->csb_cmdstat = EIO; 30567c478bd9Sstevel@tonic-gate break; 30577c478bd9Sstevel@tonic-gate } 30587c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_DOWT; 30597c478bd9Sstevel@tonic-gate break; 30607c478bd9Sstevel@tonic-gate 30617c478bd9Sstevel@tonic-gate case FXS_DOWT: /* operation complete */ 30627c478bd9Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, csb->csb_nrslts); 30637c478bd9Sstevel@tonic-gate /* 30647c478bd9Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 30657c478bd9Sstevel@tonic-gate * Actual results checked below. 30667c478bd9Sstevel@tonic-gate */ 30677c478bd9Sstevel@tonic-gate if (*csb->csb_cmd == FO_SDRV) { 30687c478bd9Sstevel@tonic-gate csb->csb_status = 30697c478bd9Sstevel@tonic-gate (*csb->csb_rslt ^ (S3_DRRDY | S3_2SIDE)) & 30707c478bd9Sstevel@tonic-gate ~(S3_HEAD | S3_UNIT); 30717c478bd9Sstevel@tonic-gate } else { 30727c478bd9Sstevel@tonic-gate csb->csb_status = *csb->csb_rslt & 30737c478bd9Sstevel@tonic-gate (S0_ICMASK | S0_ECHK | S0_NOTRDY); 30747c478bd9Sstevel@tonic-gate } 30757c478bd9Sstevel@tonic-gate nxs_cmpl: 30767c478bd9Sstevel@tonic-gate if (csb->csb_status) 30777c478bd9Sstevel@tonic-gate csb->csb_cmdstat = EIO; 30787c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_END; 30797c478bd9Sstevel@tonic-gate 30807c478bd9Sstevel@tonic-gate /* remove watchdog timer if armed and not already triggered */ 30817c478bd9Sstevel@tonic-gate if (fcp->c_timeid != 0) { 30827c478bd9Sstevel@tonic-gate timeout_id_t timeid; 30837c478bd9Sstevel@tonic-gate timeid = fcp->c_timeid; 30847c478bd9Sstevel@tonic-gate fcp->c_timeid = 0; 30857c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 30867c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 30877c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 30887c478bd9Sstevel@tonic-gate } 30897c478bd9Sstevel@tonic-gate break; 30907c478bd9Sstevel@tonic-gate 30917c478bd9Sstevel@tonic-gate case FXS_KILL: /* quiesce cntlr by reset */ 30927c478bd9Sstevel@tonic-gate fdcquiesce(fcp); 30937c478bd9Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, 30947c478bd9Sstevel@tonic-gate drv_usectohz(2000000)); 30957c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 30967c478bd9Sstevel@tonic-gate break; 30977c478bd9Sstevel@tonic-gate 30987c478bd9Sstevel@tonic-gate case FXS_RESET: /* int from reset */ 30997c478bd9Sstevel@tonic-gate for (unit = 0; unit < NFDUN; unit++) { 31007c478bd9Sstevel@tonic-gate (void) fdcsense_int(fcp, NULL, NULL); 31017c478bd9Sstevel@tonic-gate fcp->c_curpcyl[unit] = -1; 31027c478bd9Sstevel@tonic-gate } 31037c478bd9Sstevel@tonic-gate if (fcp->c_timeid != 0) { 31047c478bd9Sstevel@tonic-gate timeout_id_t timeid; 31057c478bd9Sstevel@tonic-gate timeid = fcp->c_timeid; 31067c478bd9Sstevel@tonic-gate fcp->c_timeid = 0; 31077c478bd9Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 31087c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 31097c478bd9Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate csb->csb_xstate = FXS_END; 31127c478bd9Sstevel@tonic-gate break; 31137c478bd9Sstevel@tonic-gate 31147c478bd9Sstevel@tonic-gate default: 31157c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: statemach, unknown state"); 31167c478bd9Sstevel@tonic-gate return (-1); 31177c478bd9Sstevel@tonic-gate } 31187c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_EXEC, 31197c478bd9Sstevel@tonic-gate (CE_CONT, "fdc_statemach unit %d: %d -> %d\n", 31207c478bd9Sstevel@tonic-gate csb->csb_drive, csb->csb_oldxs, csb->csb_xstate)); 31217c478bd9Sstevel@tonic-gate return (csb->csb_xstate); 31227c478bd9Sstevel@tonic-gate } 31237c478bd9Sstevel@tonic-gate 31247c478bd9Sstevel@tonic-gate 31257c478bd9Sstevel@tonic-gate /* 31267c478bd9Sstevel@tonic-gate * routine to program a command into the floppy disk controller. 31277c478bd9Sstevel@tonic-gate */ 31287c478bd9Sstevel@tonic-gate int 31297c478bd9Sstevel@tonic-gate fdc_docmd(struct fdcntlr *fcp, uchar_t *oplistp, uchar_t count) 31307c478bd9Sstevel@tonic-gate { 31317c478bd9Sstevel@tonic-gate int ntries; 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate ASSERT(count >= 1); 31347c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_EXEC, 31357c478bd9Sstevel@tonic-gate (CE_CONT, "fdc_docmd: %x %x %x %x %x %x %x %x %x\n", 31367c478bd9Sstevel@tonic-gate oplistp[0], oplistp[1], oplistp[2], oplistp[3], oplistp[4], 31377c478bd9Sstevel@tonic-gate oplistp[5], oplistp[6], oplistp[7], oplistp[8])); 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate do { 31407c478bd9Sstevel@tonic-gate ntries = FDC_RQM_RETRY; 31417c478bd9Sstevel@tonic-gate do { 31427c478bd9Sstevel@tonic-gate if ((inb(fcp->c_regbase + FCR_MSR) & (MS_RQM|MS_DIO)) 31437c478bd9Sstevel@tonic-gate == MS_RQM) 31447c478bd9Sstevel@tonic-gate break; 31457c478bd9Sstevel@tonic-gate else 31467c478bd9Sstevel@tonic-gate drv_usecwait(1); 31477c478bd9Sstevel@tonic-gate } while (--ntries); 31487c478bd9Sstevel@tonic-gate if (ntries == 0) { 31497c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 31507c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_docmd: ctlr not ready")); 31517c478bd9Sstevel@tonic-gate return (-1); 31527c478bd9Sstevel@tonic-gate } 31537c478bd9Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DATA, *oplistp++); 31547c478bd9Sstevel@tonic-gate drv_usecwait(16); /* See comment in fdc_result() */ 31557c478bd9Sstevel@tonic-gate } while (--count); 31567c478bd9Sstevel@tonic-gate return (0); 31577c478bd9Sstevel@tonic-gate } 31587c478bd9Sstevel@tonic-gate 31597c478bd9Sstevel@tonic-gate 31607c478bd9Sstevel@tonic-gate /* 31617c478bd9Sstevel@tonic-gate * Routine to return controller/drive status information. 31627c478bd9Sstevel@tonic-gate * The diskette-controller data-register is read the 31637c478bd9Sstevel@tonic-gate * requested number of times and the results are placed in 31647c478bd9Sstevel@tonic-gate * consecutive memory locations starting at the passed 31657c478bd9Sstevel@tonic-gate * address. 31667c478bd9Sstevel@tonic-gate */ 31677c478bd9Sstevel@tonic-gate int 31687c478bd9Sstevel@tonic-gate fdc_result(struct fdcntlr *fcp, uchar_t *rsltp, uchar_t rcount) 31697c478bd9Sstevel@tonic-gate { 31707c478bd9Sstevel@tonic-gate int ntries; 31717c478bd9Sstevel@tonic-gate uchar_t *abresultp = rsltp; 31727c478bd9Sstevel@tonic-gate uchar_t stat; 31737c478bd9Sstevel@tonic-gate int laxative = 7; 31747c478bd9Sstevel@tonic-gate 31757c478bd9Sstevel@tonic-gate ntries = 10 * FDC_RQM_RETRY; 31767c478bd9Sstevel@tonic-gate do { 31777c478bd9Sstevel@tonic-gate do { 31787c478bd9Sstevel@tonic-gate if ((inb(fcp->c_regbase + FCR_MSR) & 31797c478bd9Sstevel@tonic-gate (MS_RQM | MS_DIO)) == (MS_RQM | MS_DIO)) 31807c478bd9Sstevel@tonic-gate break; 31817c478bd9Sstevel@tonic-gate else 31827c478bd9Sstevel@tonic-gate drv_usecwait(10); 31837c478bd9Sstevel@tonic-gate } while (--ntries); 31847c478bd9Sstevel@tonic-gate if (!ntries) { 31857c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 31867c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_result: ctlr not ready")); 31877c478bd9Sstevel@tonic-gate return (-2); 31887c478bd9Sstevel@tonic-gate } 31897c478bd9Sstevel@tonic-gate *rsltp++ = inb(fcp->c_regbase + FCR_DATA); 31907c478bd9Sstevel@tonic-gate 31917c478bd9Sstevel@tonic-gate /* 31927c478bd9Sstevel@tonic-gate * The PRM suggests waiting for 14.5 us. 31937c478bd9Sstevel@tonic-gate * Adding a bit more to cover the case of bad calibration 31947c478bd9Sstevel@tonic-gate * of drv_usecwait(). 31957c478bd9Sstevel@tonic-gate */ 31967c478bd9Sstevel@tonic-gate drv_usecwait(16); 31977c478bd9Sstevel@tonic-gate ntries = FDC_RQM_RETRY; 31987c478bd9Sstevel@tonic-gate } while (--rcount); 31997c478bd9Sstevel@tonic-gate while ((inb(fcp->c_regbase + FCR_MSR) & MS_CB) && laxative--) { 32007c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 32017c478bd9Sstevel@tonic-gate (CE_WARN, "fdc_result: ctlr still busy")); 32027c478bd9Sstevel@tonic-gate /* 32037c478bd9Sstevel@tonic-gate * try to complete Result phase by purging 32047c478bd9Sstevel@tonic-gate * result bytes queued for reading 32057c478bd9Sstevel@tonic-gate */ 32067c478bd9Sstevel@tonic-gate *abresultp = S0_IVCMD; 32077c478bd9Sstevel@tonic-gate do { 32087c478bd9Sstevel@tonic-gate stat = inb(fcp->c_regbase + FCR_MSR) & 32097c478bd9Sstevel@tonic-gate (MS_RQM | MS_DIO); 32107c478bd9Sstevel@tonic-gate if (stat == MS_RQM) { 32117c478bd9Sstevel@tonic-gate /* 32127c478bd9Sstevel@tonic-gate * Result phase is complete 32137c478bd9Sstevel@tonic-gate * but did we get the results corresponding to 32147c478bd9Sstevel@tonic-gate * the command we think we executed? 32157c478bd9Sstevel@tonic-gate */ 32167c478bd9Sstevel@tonic-gate return (-1); 32177c478bd9Sstevel@tonic-gate } 32187c478bd9Sstevel@tonic-gate if (stat == (MS_RQM | MS_DIO)) 32197c478bd9Sstevel@tonic-gate break; 32207c478bd9Sstevel@tonic-gate else 32217c478bd9Sstevel@tonic-gate drv_usecwait(10); 32227c478bd9Sstevel@tonic-gate } while (--ntries); 32237c478bd9Sstevel@tonic-gate if (!ntries || !laxative) { 32247c478bd9Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 32257c478bd9Sstevel@tonic-gate (CE_WARN, 32267c478bd9Sstevel@tonic-gate "fdc_result: ctlr still busy and not ready")); 32277c478bd9Sstevel@tonic-gate return (-3); 32287c478bd9Sstevel@tonic-gate } 32297c478bd9Sstevel@tonic-gate (void) inb(fcp->c_regbase + FCR_DATA); 32307c478bd9Sstevel@tonic-gate 32317c478bd9Sstevel@tonic-gate drv_usecwait(16); /* See comment above */ 32327c478bd9Sstevel@tonic-gate ntries = FDC_RQM_RETRY; 32337c478bd9Sstevel@tonic-gate } 32347c478bd9Sstevel@tonic-gate return (0); 32357c478bd9Sstevel@tonic-gate } 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate /* 32387c478bd9Sstevel@tonic-gate * Function: get_unit() 32397c478bd9Sstevel@tonic-gate * 32407c478bd9Sstevel@tonic-gate * Assumptions: ioaddr is either 0x3f0 or 0x370 32417c478bd9Sstevel@tonic-gate */ 32427c478bd9Sstevel@tonic-gate static int 32437c478bd9Sstevel@tonic-gate get_unit(dev_info_t *dip, int *cntrl_num) 32447c478bd9Sstevel@tonic-gate { 32457c478bd9Sstevel@tonic-gate int ioaddr; 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS) 32487c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate switch (ioaddr) { 32517c478bd9Sstevel@tonic-gate case 0x3f0: 32527c478bd9Sstevel@tonic-gate *cntrl_num = 0; 32537c478bd9Sstevel@tonic-gate break; 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate case 0x370: 32567c478bd9Sstevel@tonic-gate *cntrl_num = 1; 32577c478bd9Sstevel@tonic-gate break; 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate default: 32607c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 32617c478bd9Sstevel@tonic-gate } 32627c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 32637c478bd9Sstevel@tonic-gate } 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate static int 32667c478bd9Sstevel@tonic-gate get_ioaddr(dev_info_t *dip, int *ioaddr) 32677c478bd9Sstevel@tonic-gate { 32687c478bd9Sstevel@tonic-gate int reglen, nregs, i; 32697c478bd9Sstevel@tonic-gate int status = DDI_FAILURE; 32707c478bd9Sstevel@tonic-gate struct { 32717c478bd9Sstevel@tonic-gate int bustype; 32727c478bd9Sstevel@tonic-gate int base; 32737c478bd9Sstevel@tonic-gate int size; 32747c478bd9Sstevel@tonic-gate } *reglist; 32757c478bd9Sstevel@tonic-gate 32767c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 32777c478bd9Sstevel@tonic-gate "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { 32787c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: reg property not found"); 32797c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 32807c478bd9Sstevel@tonic-gate } 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate nregs = reglen / sizeof (*reglist); 32837c478bd9Sstevel@tonic-gate for (i = 0; i < nregs; i++) { 32847c478bd9Sstevel@tonic-gate if (reglist[i].bustype == 1) { 32857c478bd9Sstevel@tonic-gate *ioaddr = reglist[i].base; 32867c478bd9Sstevel@tonic-gate status = DDI_SUCCESS; 32877c478bd9Sstevel@tonic-gate break; 32887c478bd9Sstevel@tonic-gate } 32897c478bd9Sstevel@tonic-gate } 32907c478bd9Sstevel@tonic-gate kmem_free(reglist, reglen); 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate if (status == DDI_SUCCESS) { 32937c478bd9Sstevel@tonic-gate if (*ioaddr == 0x3f2 || *ioaddr == 0x372) { 32947c478bd9Sstevel@tonic-gate /* 32957c478bd9Sstevel@tonic-gate * Some BIOS's (ASUS is one) don't include first 32967c478bd9Sstevel@tonic-gate * two IO ports in the floppy controller resources. 32977c478bd9Sstevel@tonic-gate */ 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate *ioaddr -= 2; /* step back to 0x3f0 or 0x370 */ 33007c478bd9Sstevel@tonic-gate 33017c478bd9Sstevel@tonic-gate /* 33027c478bd9Sstevel@tonic-gate * It would be nice to update the regs property as well 33037c478bd9Sstevel@tonic-gate * so device pathname contains 3f0 instead of 3f2, but 33047c478bd9Sstevel@tonic-gate * updating the regs now won't have this effect as that 33057c478bd9Sstevel@tonic-gate * component of the device pathname has already been 33067c478bd9Sstevel@tonic-gate * constructed by the ISA nexus driver. 33077c478bd9Sstevel@tonic-gate * 33087c478bd9Sstevel@tonic-gate * reglist[i].base -= 2; 33097c478bd9Sstevel@tonic-gate * reglist[i].size += 2; 33107c478bd9Sstevel@tonic-gate * dev = makedevice(ddi_driver_major(dip), 0); 33117c478bd9Sstevel@tonic-gate * ddi_prop_update_int_array(dev, dip, "reg", 33127c478bd9Sstevel@tonic-gate * (int *)reglist, reglen / sizeof (int)); 33137c478bd9Sstevel@tonic-gate */ 33147c478bd9Sstevel@tonic-gate } 33157c478bd9Sstevel@tonic-gate } 33167c478bd9Sstevel@tonic-gate 33177c478bd9Sstevel@tonic-gate return (status); 33187c478bd9Sstevel@tonic-gate } 3319