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