10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55295Srandyf * Common Development and Distribution License (the "License"). 65295Srandyf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * Floppy Disk Controller Driver 290Sstevel@tonic-gate * 300Sstevel@tonic-gate * for the standard PC architecture using the Intel 8272A fdc. 310Sstevel@tonic-gate * Note that motor control and drive select use a latch external 320Sstevel@tonic-gate * to the fdc. 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * This driver is EISA capable, and uses DMA buffer chaining if available. 350Sstevel@tonic-gate * If this driver is attached to the ISA bus nexus (or if the EISA bus driver 360Sstevel@tonic-gate * does not support DMA buffer chaining), then the bus driver must ensure 370Sstevel@tonic-gate * that dma mapping (breakup) and dma engine requests are properly degraded. 380Sstevel@tonic-gate */ 390Sstevel@tonic-gate 400Sstevel@tonic-gate /* 410Sstevel@tonic-gate * hack for bugid 1160621: 420Sstevel@tonic-gate * workaround compiler optimization bug by turning on DEBUG 430Sstevel@tonic-gate */ 440Sstevel@tonic-gate #ifndef DEBUG 450Sstevel@tonic-gate #define DEBUG 1 460Sstevel@tonic-gate #endif 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include <sys/param.h> 490Sstevel@tonic-gate #include <sys/buf.h> 500Sstevel@tonic-gate #include <sys/ioctl.h> 510Sstevel@tonic-gate #include <sys/uio.h> 520Sstevel@tonic-gate #include <sys/open.h> 530Sstevel@tonic-gate #include <sys/conf.h> 540Sstevel@tonic-gate #include <sys/file.h> 550Sstevel@tonic-gate #include <sys/cmn_err.h> 560Sstevel@tonic-gate #include <sys/debug.h> 570Sstevel@tonic-gate #include <sys/kmem.h> 580Sstevel@tonic-gate #include <sys/stat.h> 590Sstevel@tonic-gate 600Sstevel@tonic-gate #include <sys/autoconf.h> 610Sstevel@tonic-gate #include <sys/dkio.h> 620Sstevel@tonic-gate #include <sys/vtoc.h> 630Sstevel@tonic-gate #include <sys/kstat.h> 640Sstevel@tonic-gate 650Sstevel@tonic-gate #include <sys/fdio.h> 660Sstevel@tonic-gate #include <sys/fdc.h> 670Sstevel@tonic-gate #include <sys/i8272A.h> 680Sstevel@tonic-gate #include <sys/fd_debug.h> 690Sstevel@tonic-gate #include <sys/promif.h> 700Sstevel@tonic-gate #include <sys/ddi.h> 710Sstevel@tonic-gate #include <sys/sunddi.h> 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * bss (uninitialized data) 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate static void *fdc_state_head; /* opaque handle top of state structs */ 770Sstevel@tonic-gate static ddi_dma_attr_t fdc_dma_attr; 78940Smrj static ddi_device_acc_attr_t fdc_accattr = {DDI_DEVICE_ATTR_V0, 79940Smrj DDI_STRUCTURE_LE_ACC, DDI_STRICTORDER_ACC}; 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * Local static data 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate #define OURUN_TRIES 12 850Sstevel@tonic-gate static uchar_t rwretry = 4; 860Sstevel@tonic-gate static uchar_t skretry = 3; 870Sstevel@tonic-gate static uchar_t configurecmd[4] = {FO_CNFG, 0, 0x0F, 0}; 880Sstevel@tonic-gate static uchar_t recalcmd[2] = {FO_RECAL, 0}; 890Sstevel@tonic-gate static uchar_t senseintcmd = FO_SINT; 900Sstevel@tonic-gate 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * error handling 930Sstevel@tonic-gate * 940Sstevel@tonic-gate * for debugging, set rwretry and skretry = 1 950Sstevel@tonic-gate * set fcerrlevel to 1 960Sstevel@tonic-gate * set fcerrmask to 224 or 644 970Sstevel@tonic-gate * 980Sstevel@tonic-gate * after debug, set rwretry to 4, skretry to 3, and fcerrlevel to 5 990Sstevel@tonic-gate * set fcerrmask to FDEM_ALL 1000Sstevel@tonic-gate * or remove the define DEBUG 1010Sstevel@tonic-gate */ 1020Sstevel@tonic-gate static uint_t fcerrmask = FDEM_ALL; 1030Sstevel@tonic-gate static int fcerrlevel = 6; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate #define KIOIP KSTAT_INTR_PTR(fcp->c_intrstat) 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate static xlate_tbl_t drate_mfm[] = { 1090Sstevel@tonic-gate { 250, 2}, 1100Sstevel@tonic-gate { 300, 1}, 1110Sstevel@tonic-gate { 417, 0}, 1120Sstevel@tonic-gate { 500, 0}, 1130Sstevel@tonic-gate { 1000, 3}, 1140Sstevel@tonic-gate { 0, 0} 1150Sstevel@tonic-gate }; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate static xlate_tbl_t sector_size[] = { 1180Sstevel@tonic-gate { 256, 1}, 1190Sstevel@tonic-gate { 512, 2}, 1200Sstevel@tonic-gate { 1024, 3}, 1210Sstevel@tonic-gate { 0, 2} 1220Sstevel@tonic-gate }; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate static xlate_tbl_t motor_onbits[] = { 1250Sstevel@tonic-gate { 0, 0x10}, 1260Sstevel@tonic-gate { 1, 0x20}, 1270Sstevel@tonic-gate { 2, 0x40}, 1280Sstevel@tonic-gate { 3, 0x80}, 1290Sstevel@tonic-gate { 0, 0x80} 1300Sstevel@tonic-gate }; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate static xlate_tbl_t step_rate[] = { 1330Sstevel@tonic-gate { 10, 0xF0}, /* for 500K data rate */ 1340Sstevel@tonic-gate { 20, 0xE0}, 1350Sstevel@tonic-gate { 30, 0xD0}, 1360Sstevel@tonic-gate { 40, 0xC0}, 1370Sstevel@tonic-gate { 50, 0xB0}, 1380Sstevel@tonic-gate { 60, 0xA0}, 1390Sstevel@tonic-gate { 70, 0x90}, 1400Sstevel@tonic-gate { 80, 0x80}, 1410Sstevel@tonic-gate { 90, 0x70}, 1420Sstevel@tonic-gate { 100, 0x60}, 1430Sstevel@tonic-gate { 110, 0x50}, 1440Sstevel@tonic-gate { 120, 0x40}, 1450Sstevel@tonic-gate { 130, 0x30}, 1460Sstevel@tonic-gate { 140, 0x20}, 1470Sstevel@tonic-gate { 150, 0x10}, 1480Sstevel@tonic-gate { 160, 0x00}, 1490Sstevel@tonic-gate { 0, 0x00} 1500Sstevel@tonic-gate }; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate #ifdef notdef 1530Sstevel@tonic-gate static xlate_tbl_t head_unld[] = { 1540Sstevel@tonic-gate { 16, 0x1}, /* for 500K data rate */ 1550Sstevel@tonic-gate { 32, 0x2}, 1560Sstevel@tonic-gate { 48, 0x3}, 1570Sstevel@tonic-gate { 64, 0x4}, 1580Sstevel@tonic-gate { 80, 0x5}, 1590Sstevel@tonic-gate { 96, 0x6}, 1600Sstevel@tonic-gate { 112, 0x7}, 1610Sstevel@tonic-gate { 128, 0x8}, 1620Sstevel@tonic-gate { 144, 0x9}, 1630Sstevel@tonic-gate { 160, 0xA}, 1640Sstevel@tonic-gate { 176, 0xB}, 1650Sstevel@tonic-gate { 192, 0xC}, 1660Sstevel@tonic-gate { 208, 0xD}, 1670Sstevel@tonic-gate { 224, 0xE}, 1680Sstevel@tonic-gate { 240, 0xF}, 1690Sstevel@tonic-gate { 256, 0x0}, 1700Sstevel@tonic-gate { 0, 0x0} 1710Sstevel@tonic-gate }; 1720Sstevel@tonic-gate #endif 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static struct fdcmdinfo { 1750Sstevel@tonic-gate char *cmdname; /* command name */ 1760Sstevel@tonic-gate uchar_t ncmdbytes; /* number of bytes of command */ 1770Sstevel@tonic-gate uchar_t nrsltbytes; /* number of bytes in result */ 1780Sstevel@tonic-gate uchar_t cmdtype; /* characteristics */ 1790Sstevel@tonic-gate } fdcmds[] = { 1800Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1810Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1820Sstevel@tonic-gate "read_track", 9, 7, 1, /* 2 */ 1830Sstevel@tonic-gate "specify", 3, 0, 3, /* 3 */ 1840Sstevel@tonic-gate "sense_drv_status", 2, 1, 3, /* 4 */ 1850Sstevel@tonic-gate "write", 9, 7, 1, /* 5 */ 1860Sstevel@tonic-gate "read", 9, 7, 1, /* 6 */ 1870Sstevel@tonic-gate "recalibrate", 2, 0, 2, /* 7 */ 1880Sstevel@tonic-gate "sense_int_status", 1, 2, 3, /* 8 */ 1890Sstevel@tonic-gate "write_del", 9, 7, 1, /* 9 */ 1900Sstevel@tonic-gate "read_id", 2, 7, 2, /* A */ 1910Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1920Sstevel@tonic-gate "read_del", 9, 7, 1, /* C */ 1930Sstevel@tonic-gate "format_track", 10, 7, 1, /* D */ 1940Sstevel@tonic-gate "dump_reg", 1, 10, 4, /* E */ 1950Sstevel@tonic-gate "seek", 3, 0, 2, /* F */ 1960Sstevel@tonic-gate "version", 1, 1, 3, /* 10 */ 1970Sstevel@tonic-gate "", 0, 0, 0, /* - */ 1980Sstevel@tonic-gate "perp_mode", 2, 0, 3, /* 12 */ 1990Sstevel@tonic-gate "configure", 4, 0, 4, /* 13 */ 2000Sstevel@tonic-gate /* relative seek */ 2010Sstevel@tonic-gate }; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate static int 2050Sstevel@tonic-gate fdc_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 2060Sstevel@tonic-gate static int get_ioaddr(dev_info_t *dip, int *ioaddr); 2070Sstevel@tonic-gate static int get_unit(dev_info_t *dip, int *cntrl_num); 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate struct bus_ops fdc_bus_ops = { 2100Sstevel@tonic-gate BUSO_REV, 2110Sstevel@tonic-gate nullbusmap, 2120Sstevel@tonic-gate 0, /* ddi_intrspec_t (*bus_get_intrspec)(); */ 2130Sstevel@tonic-gate 0, /* int (*bus_add_intrspec)(); */ 2140Sstevel@tonic-gate 0, /* void (*bus_remove_intrspec)(); */ 2150Sstevel@tonic-gate i_ddi_map_fault, 2160Sstevel@tonic-gate ddi_dma_map, 2170Sstevel@tonic-gate ddi_dma_allochdl, 2180Sstevel@tonic-gate ddi_dma_freehdl, 2190Sstevel@tonic-gate ddi_dma_bindhdl, 2200Sstevel@tonic-gate ddi_dma_unbindhdl, 2210Sstevel@tonic-gate ddi_dma_flush, 2220Sstevel@tonic-gate ddi_dma_win, 2230Sstevel@tonic-gate ddi_dma_mctl, 2240Sstevel@tonic-gate fdc_bus_ctl, 2250Sstevel@tonic-gate ddi_bus_prop_op, 2260Sstevel@tonic-gate }; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate static int fdc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 2290Sstevel@tonic-gate static int fdc_probe(dev_info_t *); 2300Sstevel@tonic-gate static int fdc_attach(dev_info_t *, ddi_attach_cmd_t); 2310Sstevel@tonic-gate static int fdc_detach(dev_info_t *, ddi_detach_cmd_t); 232*7656SSherry.Moore@Sun.COM static int fdc_quiesce(dev_info_t *); 2330Sstevel@tonic-gate static int fdc_enhance_probe(struct fdcntlr *fcp); 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate struct dev_ops fdc_ops = { 2360Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 2370Sstevel@tonic-gate 0, /* refcnt */ 2380Sstevel@tonic-gate fdc_getinfo, /* getinfo */ 2390Sstevel@tonic-gate nulldev, /* identify */ 2400Sstevel@tonic-gate fdc_probe, /* probe */ 2410Sstevel@tonic-gate fdc_attach, /* attach */ 2420Sstevel@tonic-gate fdc_detach, /* detach */ 2430Sstevel@tonic-gate nodev, /* reset */ 2440Sstevel@tonic-gate (struct cb_ops *)0, /* driver operations */ 245*7656SSherry.Moore@Sun.COM &fdc_bus_ops, /* bus operations */ 246*7656SSherry.Moore@Sun.COM NULL, /* power */ 247*7656SSherry.Moore@Sun.COM fdc_quiesce, /* quiesce */ 2480Sstevel@tonic-gate }; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate /* 2510Sstevel@tonic-gate * This is the loadable module wrapper. 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate #include <sys/modctl.h> 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate static struct modldrv modldrv = { 2580Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 259*7656SSherry.Moore@Sun.COM "Floppy Controller", /* Name of the module. */ 2600Sstevel@tonic-gate &fdc_ops, /* Driver ops vector */ 2610Sstevel@tonic-gate }; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate static struct modlinkage modlinkage = { 2640Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 2650Sstevel@tonic-gate }; 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate int 2680Sstevel@tonic-gate _init(void) 2690Sstevel@tonic-gate { 2700Sstevel@tonic-gate int retval; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate if ((retval = ddi_soft_state_init(&fdc_state_head, 2730Sstevel@tonic-gate sizeof (struct fdcntlr) + NFDUN * sizeof (struct fcu_obj), 0)) != 0) 2740Sstevel@tonic-gate return (retval); 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate if ((retval = mod_install(&modlinkage)) != 0) 2770Sstevel@tonic-gate ddi_soft_state_fini(&fdc_state_head); 2780Sstevel@tonic-gate return (retval); 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate int 2820Sstevel@tonic-gate _fini(void) 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate int retval; 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate if ((retval = mod_remove(&modlinkage)) != 0) 2870Sstevel@tonic-gate return (retval); 2880Sstevel@tonic-gate ddi_soft_state_fini(&fdc_state_head); 2890Sstevel@tonic-gate return (retval); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate int 2930Sstevel@tonic-gate _info(struct modinfo *modinfop) 2940Sstevel@tonic-gate { 2950Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate int fdc_start(struct fcu_obj *); 3000Sstevel@tonic-gate int fdc_abort(struct fcu_obj *); 3010Sstevel@tonic-gate int fdc_getcap(struct fcu_obj *, char *, int); 3020Sstevel@tonic-gate int fdc_setcap(struct fcu_obj *, char *, int, int); 3030Sstevel@tonic-gate int fdc_dkinfo(struct fcu_obj *, struct dk_cinfo *); 3040Sstevel@tonic-gate int fdc_select(struct fcu_obj *, int, int); 3050Sstevel@tonic-gate int fdgetchng(struct fcu_obj *, int); 3060Sstevel@tonic-gate int fdresetchng(struct fcu_obj *, int); 3070Sstevel@tonic-gate int fdrecalseek(struct fcu_obj *, int, int, int); 3080Sstevel@tonic-gate int fdrw(struct fcu_obj *, int, int, int, int, int, caddr_t, uint_t); 3090Sstevel@tonic-gate int fdtrkformat(struct fcu_obj *, int, int, int, int); 3100Sstevel@tonic-gate int fdrawioctl(struct fcu_obj *, int, caddr_t); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate static struct fcobjops fdc_iops = { 3130Sstevel@tonic-gate fdc_start, /* controller start */ 3140Sstevel@tonic-gate fdc_abort, /* controller abort */ 3150Sstevel@tonic-gate fdc_getcap, /* capability retrieval */ 3160Sstevel@tonic-gate fdc_setcap, /* capability establishment */ 3170Sstevel@tonic-gate fdc_dkinfo, /* get disk controller info */ 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate fdc_select, /* select / deselect unit */ 3200Sstevel@tonic-gate fdgetchng, /* get media change */ 3210Sstevel@tonic-gate fdresetchng, /* reset media change */ 3220Sstevel@tonic-gate fdrecalseek, /* recal / seek */ 323940Smrj NULL, /* read /write request (UNUSED) */ 3240Sstevel@tonic-gate fdrw, /* read /write sector */ 3250Sstevel@tonic-gate fdtrkformat, /* format track */ 3260Sstevel@tonic-gate fdrawioctl /* raw ioctl */ 3270Sstevel@tonic-gate }; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /* 3310Sstevel@tonic-gate * Function prototypes 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate void encode(xlate_tbl_t *tablep, int val, uchar_t *rcode); 3340Sstevel@tonic-gate int decode(xlate_tbl_t *, int, int *); 3350Sstevel@tonic-gate static int fdc_propinit1(struct fdcntlr *, int); 3360Sstevel@tonic-gate static void fdc_propinit2(struct fdcntlr *, int); 3370Sstevel@tonic-gate void fdcquiesce(struct fdcntlr *); 3380Sstevel@tonic-gate int fdcsense_chng(struct fdcntlr *, int); 3390Sstevel@tonic-gate int fdcsense_drv(struct fdcntlr *, int); 3400Sstevel@tonic-gate int fdcsense_int(struct fdcntlr *, int *, int *); 3410Sstevel@tonic-gate int fdcspecify(struct fdcntlr *, int, int, int); 3420Sstevel@tonic-gate int fdcspdchange(struct fdcntlr *, struct fcu_obj *, int); 3430Sstevel@tonic-gate static int fdc_exec(struct fdcntlr *, int, int); 3440Sstevel@tonic-gate int fdcheckdisk(struct fdcntlr *, int); 3450Sstevel@tonic-gate static uint_t fdc_intr(caddr_t arg); 3460Sstevel@tonic-gate static void fdwatch(void *arg); 3470Sstevel@tonic-gate static void fdmotort(void *arg); 3480Sstevel@tonic-gate static int fdrecover(struct fdcntlr *); 3490Sstevel@tonic-gate static int fdc_motorsm(struct fcu_obj *, int, int); 3500Sstevel@tonic-gate static int fdc_statemach(struct fdcntlr *); 3510Sstevel@tonic-gate int fdc_docmd(struct fdcntlr *, uchar_t *, uchar_t); 3520Sstevel@tonic-gate int fdc_result(struct fdcntlr *, uchar_t *, uchar_t); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* ARGSUSED */ 3560Sstevel@tonic-gate static int 3570Sstevel@tonic-gate fdc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 3580Sstevel@tonic-gate void *arg, void *result) 3590Sstevel@tonic-gate { 3600Sstevel@tonic-gate struct fdcntlr *fcp; 3610Sstevel@tonic-gate struct fcu_obj *fjp; 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_ATTA, 3640Sstevel@tonic-gate (CE_CONT, "fdc_bus_ctl: cmd= %x\n", ctlop)); 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate if ((fcp = ddi_get_driver_private(dip)) == NULL) 3670Sstevel@tonic-gate return (DDI_FAILURE); 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate switch (ctlop) { 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 3720Sstevel@tonic-gate cmn_err(CE_CONT, "?%s%d at %s%d\n", 3730Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 3740Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip)); 3750Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, 3760Sstevel@tonic-gate (CE_WARN, "fdc_bus_ctl: report %s%d at %s%d", 3770Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 3780Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip))); 3790Sstevel@tonic-gate return (DDI_SUCCESS); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate dev_info_t *udip = (dev_info_t *)arg; 3840Sstevel@tonic-gate int cntlr; 3850Sstevel@tonic-gate int len; 3860Sstevel@tonic-gate int unit; 3870Sstevel@tonic-gate char name[MAXNAMELEN]; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, 3900Sstevel@tonic-gate (CE_WARN, "fdc_bus_ctl: init child 0x%p", (void*)udip)); 3910Sstevel@tonic-gate cntlr = fcp->c_number; 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate len = sizeof (unit); 3940Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, udip, PROP_LEN_AND_VAL_BUF, 3950Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit", (caddr_t)&unit, &len) 3960Sstevel@tonic-gate != DDI_PROP_SUCCESS || 3970Sstevel@tonic-gate cntlr != FDCTLR(unit) || 3980Sstevel@tonic-gate (fcp->c_unit[FDUNIT(unit)])->fj_dip) 3990Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate (void) sprintf(name, "%d,%d", cntlr, FDUNIT(unit)); 4020Sstevel@tonic-gate ddi_set_name_addr(udip, name); 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate fjp = fcp->c_unit[FDUNIT(unit)]; 4050Sstevel@tonic-gate fjp->fj_unit = unit; 4060Sstevel@tonic-gate fjp->fj_dip = udip; 4070Sstevel@tonic-gate fjp->fj_ops = &fdc_iops; 4080Sstevel@tonic-gate fjp->fj_fdc = fcp; 4090Sstevel@tonic-gate fjp->fj_iblock = &fcp->c_iblock; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate ddi_set_driver_private(udip, fjp); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate return (DDI_SUCCESS); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate dev_info_t *udip = (dev_info_t *)arg; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, 4200Sstevel@tonic-gate (CE_WARN, "fdc_bus_ctl: uninit child 0x%p", (void *)udip)); 4210Sstevel@tonic-gate fjp = ddi_get_driver_private(udip); 4220Sstevel@tonic-gate ddi_set_driver_private(udip, NULL); 4230Sstevel@tonic-gate fjp->fj_dip = NULL; 4240Sstevel@tonic-gate ddi_set_name_addr(udip, NULL); 4250Sstevel@tonic-gate return (DDI_SUCCESS); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate default: 4280Sstevel@tonic-gate return (DDI_FAILURE); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* ARGSUSED */ 4330Sstevel@tonic-gate static int 4340Sstevel@tonic-gate fdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 4350Sstevel@tonic-gate { 4360Sstevel@tonic-gate struct fdcntlr *fcp; 4370Sstevel@tonic-gate int rval; 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate switch (cmd) { 4400Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 4410Sstevel@tonic-gate if (fcp = ddi_get_soft_state(fdc_state_head, (dev_t)arg)) { 4420Sstevel@tonic-gate *result = fcp->c_dip; 4430Sstevel@tonic-gate rval = DDI_SUCCESS; 4440Sstevel@tonic-gate break; 4450Sstevel@tonic-gate } else { 4460Sstevel@tonic-gate rval = DDI_FAILURE; 4470Sstevel@tonic-gate break; 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 4500Sstevel@tonic-gate *result = (void *)(uintptr_t)getminor((dev_t)arg); 4510Sstevel@tonic-gate rval = DDI_SUCCESS; 4520Sstevel@tonic-gate break; 4530Sstevel@tonic-gate default: 4540Sstevel@tonic-gate rval = DDI_FAILURE; 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate return (rval); 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate static int 4600Sstevel@tonic-gate fdc_probe(dev_info_t *dip) 4610Sstevel@tonic-gate { 4620Sstevel@tonic-gate int debug[2]; 4630Sstevel@tonic-gate int ioaddr; 4640Sstevel@tonic-gate int len; 4650Sstevel@tonic-gate uchar_t stat; 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate len = sizeof (debug); 4680Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 4690Sstevel@tonic-gate DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) == 4700Sstevel@tonic-gate DDI_PROP_SUCCESS) { 4710Sstevel@tonic-gate fcerrlevel = debug[0]; 4720Sstevel@tonic-gate fcerrmask = (uint_t)debug[1]; 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_probe: dip %p", 4765295Srandyf (void*)dip)); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS) 4790Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate stat = inb(ioaddr + FCR_MSR); 4820Sstevel@tonic-gate if ((stat & (MS_RQM | MS_DIO | MS_CB)) != MS_RQM && 4830Sstevel@tonic-gate (stat & ~MS_DIO) != MS_CB) 4840Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* ARGSUSED */ 4900Sstevel@tonic-gate static int 4910Sstevel@tonic-gate fdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4920Sstevel@tonic-gate { 4930Sstevel@tonic-gate struct fdcntlr *fcp; 4940Sstevel@tonic-gate struct fcu_obj *fjp; 4950Sstevel@tonic-gate int cntlr_num, ctlr, unit; 4960Sstevel@tonic-gate int intr_set = 0; 4970Sstevel@tonic-gate int len; 4980Sstevel@tonic-gate char name[MAXNAMELEN]; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_attach: dip %p", 5015295Srandyf (void*)dip)); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate switch (cmd) { 5040Sstevel@tonic-gate case DDI_ATTACH: 5050Sstevel@tonic-gate if (ddi_getprop 5060Sstevel@tonic-gate (DDI_DEV_T_ANY, dip, 0, "ignore-hardware-nodes", 0)) { 5070Sstevel@tonic-gate len = sizeof (cntlr_num); 5080Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, 5090Sstevel@tonic-gate PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "unit", 5100Sstevel@tonic-gate (caddr_t)&cntlr_num, &len) != DDI_PROP_SUCCESS) { 5110Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, 5120Sstevel@tonic-gate "fdc_attach failed: dip %p", (void*)dip)); 5130Sstevel@tonic-gate return (DDI_FAILURE); 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate } else { 5160Sstevel@tonic-gate if (get_unit(dip, &cntlr_num) != DDI_SUCCESS) 5170Sstevel@tonic-gate return (DDI_FAILURE); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate ctlr = ddi_get_instance(dip); 5210Sstevel@tonic-gate if (ddi_soft_state_zalloc(fdc_state_head, ctlr) != 0) 5220Sstevel@tonic-gate return (DDI_FAILURE); 5230Sstevel@tonic-gate fcp = ddi_get_soft_state(fdc_state_head, ctlr); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate for (unit = 0, fjp = (struct fcu_obj *)(fcp+1); 5260Sstevel@tonic-gate unit < NFDUN; unit++) { 5270Sstevel@tonic-gate fcp->c_unit[unit] = fjp++; 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate fcp->c_dip = dip; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate if (fdc_propinit1(fcp, cntlr_num) != DDI_SUCCESS) 5320Sstevel@tonic-gate goto no_attach; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* get iblock cookie to initialize mutex used in the ISR */ 5350Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, (uint_t)0, &fcp->c_iblock) != 5360Sstevel@tonic-gate DDI_SUCCESS) { 5370Sstevel@tonic-gate cmn_err(CE_WARN, 5380Sstevel@tonic-gate "fdc_attach: cannot get iblock cookie"); 5390Sstevel@tonic-gate goto no_attach; 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate mutex_init(&fcp->c_lock, NULL, MUTEX_DRIVER, fcp->c_iblock); 5420Sstevel@tonic-gate intr_set = 1; 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* setup interrupt handler */ 5450Sstevel@tonic-gate if (ddi_add_intr(dip, (uint_t)0, NULL, 5460Sstevel@tonic-gate (ddi_idevice_cookie_t *)0, fdc_intr, (caddr_t)fcp) != 5470Sstevel@tonic-gate DDI_SUCCESS) { 5480Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: cannot add intr\n"); 5490Sstevel@tonic-gate goto no_attach; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate intr_set++; 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate /* 5540Sstevel@tonic-gate * acquire the DMA channel 5550Sstevel@tonic-gate * this assumes that the chnl is not shared; else allocate 5560Sstevel@tonic-gate * and free the chnl with each fdc request 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate if (ddi_dmae_alloc(dip, fcp->c_dmachan, DDI_DMA_DONTWAIT, NULL) 5590Sstevel@tonic-gate != DDI_SUCCESS) { 5600Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: cannot acquire dma%d\n", 5610Sstevel@tonic-gate fcp->c_dmachan); 5620Sstevel@tonic-gate goto no_attach; 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate (void) ddi_dmae_getattr(dip, &fdc_dma_attr); 565940Smrj fdc_dma_attr.dma_attr_align = MMU_PAGESIZE; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate mutex_init(&fcp->c_dorlock, NULL, MUTEX_DRIVER, fcp->c_iblock); 5680Sstevel@tonic-gate cv_init(&fcp->c_iocv, NULL, CV_DRIVER, fcp->c_iblock); 5690Sstevel@tonic-gate sema_init(&fcp->c_selsem, 1, NULL, SEMA_DRIVER, NULL); 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate (void) sprintf(name, "fdc%d", ctlr); 5720Sstevel@tonic-gate fcp->c_intrstat = kstat_create("fdc", ctlr, name, 5730Sstevel@tonic-gate "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 5740Sstevel@tonic-gate if (fcp->c_intrstat) { 5750Sstevel@tonic-gate kstat_install(fcp->c_intrstat); 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate ddi_set_driver_private(dip, fcp); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate /* 5810Sstevel@tonic-gate * reset the controller 5820Sstevel@tonic-gate */ 5830Sstevel@tonic-gate sema_p(&fcp->c_selsem); 5840Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 5850Sstevel@tonic-gate fcp->c_csb.csb_xstate = FXS_RESET; 5860Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 5870Sstevel@tonic-gate fdcquiesce(fcp); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* first test for mode == Model 30 */ 5900Sstevel@tonic-gate fcp->c_mode = (inb(fcp->c_regbase + FCR_SRB) & 0x1c) ? 5910Sstevel@tonic-gate FDCMODE_AT : FDCMODE_30; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate while (fcp->c_flags & FCFLG_WAITING) { 5940Sstevel@tonic-gate cv_wait(&fcp->c_iocv, &fcp->c_lock); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 5970Sstevel@tonic-gate sema_v(&fcp->c_selsem); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate fdc_propinit2(fcp, cntlr_num); 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate ddi_report_dev(dip); 6020Sstevel@tonic-gate return (DDI_SUCCESS); 6030Sstevel@tonic-gate 6045295Srandyf case DDI_RESUME: 6055295Srandyf return (DDI_SUCCESS); 6065295Srandyf /* break; */ 6075295Srandyf 6080Sstevel@tonic-gate default: 6090Sstevel@tonic-gate return (DDI_FAILURE); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate no_attach: 6130Sstevel@tonic-gate if (intr_set) { 6140Sstevel@tonic-gate if (intr_set > 1) 6150Sstevel@tonic-gate ddi_remove_intr(dip, 0, fcp->c_iblock); 6160Sstevel@tonic-gate mutex_destroy(&fcp->c_lock); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate ddi_soft_state_free(fdc_state_head, cntlr_num); 6190Sstevel@tonic-gate return (DDI_FAILURE); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate static int 6230Sstevel@tonic-gate fdc_propinit1(struct fdcntlr *fcp, int cntlr) 6240Sstevel@tonic-gate { 6250Sstevel@tonic-gate dev_info_t *dip; 6260Sstevel@tonic-gate int len; 6270Sstevel@tonic-gate int value; 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate dip = fcp->c_dip; 6300Sstevel@tonic-gate len = sizeof (value); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate if (get_ioaddr(dip, &value) != DDI_SUCCESS) 6330Sstevel@tonic-gate return (DDI_FAILURE); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate fcp->c_regbase = (ushort_t)value; 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 6380Sstevel@tonic-gate DDI_PROP_DONTPASS, "dma-channels", (caddr_t)&value, &len) 6390Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 6400Sstevel@tonic-gate cmn_err(CE_WARN, 6410Sstevel@tonic-gate "fdc_attach: Error, could not find a dma channel"); 6420Sstevel@tonic-gate return (DDI_FAILURE); 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate fcp->c_dmachan = (ushort_t)value; 6450Sstevel@tonic-gate fcp->c_number = cntlr; 6460Sstevel@tonic-gate return (DDI_SUCCESS); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* ARGSUSED */ 6500Sstevel@tonic-gate static void 6510Sstevel@tonic-gate fdc_propinit2(struct fdcntlr *fcp, int cntlr) 6520Sstevel@tonic-gate { 6530Sstevel@tonic-gate dev_info_t *dip; 6540Sstevel@tonic-gate int ccr; 6550Sstevel@tonic-gate int len; 6560Sstevel@tonic-gate int value; 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate dip = fcp->c_dip; 6590Sstevel@tonic-gate len = sizeof (value); 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 6620Sstevel@tonic-gate DDI_PROP_DONTPASS, "chip", (caddr_t)&value, &len) 6630Sstevel@tonic-gate == DDI_PROP_SUCCESS) 6640Sstevel@tonic-gate fcp->c_chip = value; 6650Sstevel@tonic-gate else { 6660Sstevel@tonic-gate static uchar_t perpindcmd[2] = {FO_PERP, 0}; 6670Sstevel@tonic-gate static uchar_t versioncmd = FO_VRSN; 6680Sstevel@tonic-gate uchar_t result; 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate fcp->c_chip = i8272A; 6710Sstevel@tonic-gate (void) fdc_docmd(fcp, &versioncmd, 1); 6720Sstevel@tonic-gate /* 6730Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 6740Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate if (!fdc_result(fcp, &result, 1) && result == 0x90) { 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * try a perpendicular_mode cmd to ensure 6790Sstevel@tonic-gate * that we really have an enhanced controller 6800Sstevel@tonic-gate */ 6810Sstevel@tonic-gate if (fdc_docmd(fcp, perpindcmd, 2) || 6820Sstevel@tonic-gate fdc_docmd(fcp, configurecmd, 4)) 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * perpindicular_mode will be rejected by 6850Sstevel@tonic-gate * older controllers; make sure we don't hang. 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate (void) fdc_result(fcp, &result, 1); 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * Ignored return. If failed, warning was 6900Sstevel@tonic-gate * issued by fdc_result. 6910Sstevel@tonic-gate */ 6920Sstevel@tonic-gate else 6930Sstevel@tonic-gate /* enhanced type controller */ 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate if ((fcp->c_chip = fdc_enhance_probe(fcp)) == 0) 6960Sstevel@tonic-gate /* default enhanced cntlr */ 6970Sstevel@tonic-gate fcp->c_chip = i82077; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 7000Sstevel@tonic-gate "chip", fcp->c_chip); 7010Sstevel@tonic-gate /* 7020Sstevel@tonic-gate * Ignoring return value because, for passed arguments, only 7030Sstevel@tonic-gate * DDI_SUCCESS is returned. 7040Sstevel@tonic-gate */ 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate if (fcp->c_chip >= i82077 && fcp->c_mode == FDCMODE_30 && 7070Sstevel@tonic-gate (inb(fcp->c_regbase + FCR_DIR) & 0x70) == 0) 7080Sstevel@tonic-gate for (ccr = 0; ccr <= (FCC_NOPREC | FCC_DRATE); ccr++) { 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * run through all the combinations of NOPREC and 7110Sstevel@tonic-gate * datarate selection, and see if they show up in the 7120Sstevel@tonic-gate * Model 30 DIR 7130Sstevel@tonic-gate */ 7140Sstevel@tonic-gate outb(fcp->c_regbase + FCR_CCR, ccr); 7150Sstevel@tonic-gate drv_usecwait(5); 7160Sstevel@tonic-gate if ((inb(fcp->c_regbase + FCR_DIR) & 7170Sstevel@tonic-gate (FCC_NOPREC | FCC_DRATE)) != ccr) { 7180Sstevel@tonic-gate fcp->c_mode = FDCMODE_AT; 7190Sstevel@tonic-gate break; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate else 7230Sstevel@tonic-gate fcp->c_mode = FDCMODE_AT; 7240Sstevel@tonic-gate outb(fcp->c_regbase + FCR_CCR, 0); 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate /* ARGSUSED */ 7280Sstevel@tonic-gate static int 7290Sstevel@tonic-gate fdc_enhance_probe(struct fdcntlr *fcp) 7300Sstevel@tonic-gate { 7310Sstevel@tonic-gate static uchar_t nsccmd = FO_NSC; 7320Sstevel@tonic-gate uint_t ddic; 7330Sstevel@tonic-gate int retcode = 0; 7340Sstevel@tonic-gate uchar_t result; 7350Sstevel@tonic-gate uchar_t save; 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate /* 7380Sstevel@tonic-gate * Try to identify the enhanced floppy controller. 7390Sstevel@tonic-gate * This is required so that we can program the DENSEL output to 7400Sstevel@tonic-gate * control 3D mode (1.0 MB, 1.6 MB and 2.0 MB unformatted capacity, 7410Sstevel@tonic-gate * 720 KB, 1.2 MB, and 1.44 MB formatted capacity) 3.5" dual-speed 7420Sstevel@tonic-gate * floppy drives. Refer to bugid 1195155. 7430Sstevel@tonic-gate */ 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate (void) fdc_docmd(fcp, &nsccmd, 1); 7460Sstevel@tonic-gate /* 7470Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 7480Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 7490Sstevel@tonic-gate */ 7500Sstevel@tonic-gate if (!fdc_result(fcp, &result, 1) && result != S0_IVCMD) { 7510Sstevel@tonic-gate /* 7520Sstevel@tonic-gate * only enhanced National Semi PC8477 core 7530Sstevel@tonic-gate * should respond to this command 7540Sstevel@tonic-gate */ 7550Sstevel@tonic-gate if ((result & 0xf0) == 0x70) { 7560Sstevel@tonic-gate /* low 4 bits may change */ 7570Sstevel@tonic-gate fcp->c_flags |= FCFLG_3DMODE; 7580Sstevel@tonic-gate retcode = PC87322; 7590Sstevel@tonic-gate } else 7600Sstevel@tonic-gate cmn_err(CE_CONT, 7610Sstevel@tonic-gate "?fdc: unidentified, enhanced, National Semiconductor cntlr %x\n", result); 7620Sstevel@tonic-gate } else { 7630Sstevel@tonic-gate save = inb(fcp->c_regbase + FCR_SRA); 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate do { 7660Sstevel@tonic-gate /* probe for motherboard version of SMC cntlr */ 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate /* try to enable configuration mode */ 7690Sstevel@tonic-gate ddic = ddi_enter_critical(); 7700Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 7710Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA5); 7720Sstevel@tonic-gate ddi_exit_critical(ddic); 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0F); 7750Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 7760Sstevel@tonic-gate /* always expect 0 from config reg F */ 7770Sstevel@tonic-gate break; 7780Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0D); 7790Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x65) 7800Sstevel@tonic-gate /* expect 0x65 from config reg D */ 7810Sstevel@tonic-gate break; 7820Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0E); 7830Sstevel@tonic-gate result = inb(fcp->c_regbase + FCR_SRB); 7840Sstevel@tonic-gate if (result != 0x02) { 7850Sstevel@tonic-gate /* expect revision level 2 from config reg E */ 7860Sstevel@tonic-gate cmn_err(CE_CONT, 7870Sstevel@tonic-gate "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 7880Sstevel@tonic-gate /* break; */ 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate fcp->c_flags |= FCFLG_3DMODE; 7910Sstevel@tonic-gate retcode = FDC37C665; 7920Sstevel@tonic-gate } while (retcode == 0); 7930Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate while (retcode == 0) { 7960Sstevel@tonic-gate /* probe for adapter version of SMC cntlr */ 7970Sstevel@tonic-gate ddic = ddi_enter_critical(); 7980Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 7990Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_ENA6); 8000Sstevel@tonic-gate ddi_exit_critical(ddic); 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0F); 8030Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x00) 8040Sstevel@tonic-gate /* always expect 0 from config reg F */ 8050Sstevel@tonic-gate break; 8060Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0D); 8070Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_SRB) != 0x66) 8080Sstevel@tonic-gate /* expect 0x66 from config reg D */ 8090Sstevel@tonic-gate break; 8100Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, 0x0E); 8110Sstevel@tonic-gate result = inb(fcp->c_regbase + FCR_SRB); 8120Sstevel@tonic-gate if (result != 0x02) { 8130Sstevel@tonic-gate /* expect revision level 2 from config reg E */ 8140Sstevel@tonic-gate cmn_err(CE_CONT, 8150Sstevel@tonic-gate "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result); 8160Sstevel@tonic-gate /* break; */ 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate fcp->c_flags |= FCFLG_3DMODE; 8190Sstevel@tonic-gate retcode = FDC37C666; 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate drv_usecwait(10); 8240Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, save); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate return (retcode); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /* ARGSUSED */ 8300Sstevel@tonic-gate static int 8310Sstevel@tonic-gate fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 8320Sstevel@tonic-gate { 8330Sstevel@tonic-gate struct fdcntlr *fcp; 8345295Srandyf struct fcu_obj *fjp; 8350Sstevel@tonic-gate int unit; 8360Sstevel@tonic-gate int rval = 0; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_detach: dip %p", 8395295Srandyf (void*)dip)); 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate fcp = ddi_get_driver_private(dip); 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate switch (cmd) { 8440Sstevel@tonic-gate case DDI_DETACH: 8450Sstevel@tonic-gate for (unit = 0; unit < NFDUN; unit++) 8460Sstevel@tonic-gate if ((fcp->c_unit[unit])->fj_dip) { 8470Sstevel@tonic-gate rval = EBUSY; 8480Sstevel@tonic-gate break; 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate kstat_delete(fcp->c_intrstat); 8510Sstevel@tonic-gate fcp->c_intrstat = NULL; 8520Sstevel@tonic-gate ddi_remove_intr(fcp->c_dip, 0, fcp->c_iblock); 8530Sstevel@tonic-gate if (ddi_dmae_release(fcp->c_dip, fcp->c_dmachan) != 8540Sstevel@tonic-gate DDI_SUCCESS) 8550Sstevel@tonic-gate cmn_err(CE_WARN, "fdc_detach: dma release failed, " 8565295Srandyf "dip %p, dmachan %x\n", 8575295Srandyf (void*)fcp->c_dip, fcp->c_dmachan); 8580Sstevel@tonic-gate ddi_prop_remove_all(fcp->c_dip); 8590Sstevel@tonic-gate ddi_set_driver_private(fcp->c_dip, NULL); 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate mutex_destroy(&fcp->c_lock); 8620Sstevel@tonic-gate mutex_destroy(&fcp->c_dorlock); 8630Sstevel@tonic-gate cv_destroy(&fcp->c_iocv); 8640Sstevel@tonic-gate sema_destroy(&fcp->c_selsem); 8650Sstevel@tonic-gate ddi_soft_state_free(fdc_state_head, ddi_get_instance(dip)); 8660Sstevel@tonic-gate break; 8675295Srandyf 8685295Srandyf case DDI_SUSPEND: 8695295Srandyf /* 8705295Srandyf * Following code causes the fdc (floppy controller) 8715295Srandyf * to suspend as long as there are no floppy drives 8725295Srandyf * attached to it. 8735295Srandyf * At present the floppy driver does not support 8745295Srandyf * SUSPEND/RESUME. 8755295Srandyf * 8765295Srandyf * Check if any FD units are attached 8775295Srandyf * 8785295Srandyf * For now, SUSPEND/RESUME is not supported 8795295Srandyf * if a floppy drive is present. 8805295Srandyf * So if any FD unit is attached return DDI_FAILURE 8815295Srandyf */ 8825295Srandyf for (unit = 0; unit < NFDUN; unit++) { 8835295Srandyf fjp = fcp->c_unit[unit]; 8845295Srandyf if (fjp->fj_flags & FUNIT_DRVATCH) { 8855295Srandyf cmn_err(CE_WARN, 8865295Srandyf "fdc_detach: fd attached, failing SUSPEND"); 8875295Srandyf return (DDI_FAILURE); 8885295Srandyf } 8895295Srandyf } 8905295Srandyf 8915295Srandyf cmn_err(CE_NOTE, "fdc_detach: SUSPEND fdc"); 8925295Srandyf 8935295Srandyf rval = DDI_SUCCESS; 8945295Srandyf break; 8955295Srandyf 8960Sstevel@tonic-gate default: 8970Sstevel@tonic-gate rval = EINVAL; 8980Sstevel@tonic-gate break; 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate return (rval); 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate /* ARGSUSED */ 9050Sstevel@tonic-gate int 9060Sstevel@tonic-gate fdc_start(struct fcu_obj *fjp) 9070Sstevel@tonic-gate { 9080Sstevel@tonic-gate return (ENOSYS); 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate int 9120Sstevel@tonic-gate fdc_abort(struct fcu_obj *fjp) 9130Sstevel@tonic-gate { 9140Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 9150Sstevel@tonic-gate int unit = fjp->fj_unit & 3; 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_RESE, (CE_WARN, "fdc_abort")); 9180Sstevel@tonic-gate if (fcp->c_curunit == unit) { 9190Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 9200Sstevel@tonic-gate if (fcp->c_flags & FCFLG_WAITING) { 9210Sstevel@tonic-gate /* 9220Sstevel@tonic-gate * this can cause data corruption ! 9230Sstevel@tonic-gate */ 9240Sstevel@tonic-gate fdcquiesce(fcp); 9250Sstevel@tonic-gate fcp->c_csb.csb_xstate = FXS_RESET; 9260Sstevel@tonic-gate fcp->c_flags |= FCFLG_TIMEOUT; 9270Sstevel@tonic-gate if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != 9280Sstevel@tonic-gate DDI_SUCCESS) 9290Sstevel@tonic-gate cmn_err(CE_WARN, 9305295Srandyf "fdc_detach: dma release failed, " 9315295Srandyf "dip %p, dmachan %x\n", 9325295Srandyf (void*)fcp->c_dip, fcp->c_dmachan); 9330Sstevel@tonic-gate } 9340Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 9350Sstevel@tonic-gate drv_usecwait(500); 9360Sstevel@tonic-gate return (DDI_SUCCESS); 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate return (DDI_FAILURE); 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate /* ARGSUSED */ 9420Sstevel@tonic-gate int 9430Sstevel@tonic-gate fdc_getcap(struct fcu_obj *fjp, char *a, int i) 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate return (ENOSYS); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate /* ARGSUSED */ 9490Sstevel@tonic-gate int 9500Sstevel@tonic-gate fdc_setcap(struct fcu_obj *fjp, char *a, int i, int j) 9510Sstevel@tonic-gate { 9520Sstevel@tonic-gate return (ENOSYS); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate int 9560Sstevel@tonic-gate fdc_dkinfo(struct fcu_obj *fjp, struct dk_cinfo *dcp) 9570Sstevel@tonic-gate { 9580Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate (void) strncpy((char *)&dcp->dki_cname, ddi_get_name(fcp->c_dip), 9615295Srandyf DK_DEVLEN); 9620Sstevel@tonic-gate dcp->dki_ctype = DKC_UNKNOWN; /* no code for generic PC/AT fdc */ 9630Sstevel@tonic-gate dcp->dki_flags = DKI_FMTTRK; 9640Sstevel@tonic-gate dcp->dki_addr = fcp->c_regbase; 9650Sstevel@tonic-gate dcp->dki_space = 0; 9660Sstevel@tonic-gate dcp->dki_prio = fcp->c_intprio; 9670Sstevel@tonic-gate dcp->dki_vec = fcp->c_intvec; 9680Sstevel@tonic-gate (void) strncpy((char *)&dcp->dki_dname, ddi_driver_name(fjp->fj_dip), 9695295Srandyf DK_DEVLEN); 9700Sstevel@tonic-gate dcp->dki_slave = fjp->fj_unit & 3; 9710Sstevel@tonic-gate dcp->dki_maxtransfer = maxphys / DEV_BSIZE; 9720Sstevel@tonic-gate return (DDI_SUCCESS); 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * on=> non-zero = select, 0 = de-select 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate /* ARGSUSED */ 9790Sstevel@tonic-gate int 9800Sstevel@tonic-gate fdc_select(struct fcu_obj *fjp, int funit, int on) 9810Sstevel@tonic-gate { 9820Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 9830Sstevel@tonic-gate int unit = funit & 3; 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate if (on) { 9860Sstevel@tonic-gate /* possess controller */ 9870Sstevel@tonic-gate sema_p(&fcp->c_selsem); 9880Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_DSEL, 9890Sstevel@tonic-gate (CE_NOTE, "fdc_select unit %d: on", funit)); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) { 9920Sstevel@tonic-gate fcp->c_curunit = unit; 9930Sstevel@tonic-gate fjp->fj_flags |= FUNIT_CHAROK; 9940Sstevel@tonic-gate if (fdcspecify(fcp, 9950Sstevel@tonic-gate fjp->fj_chars->fdc_transfer_rate, 9960Sstevel@tonic-gate fjp->fj_drive->fdd_steprate, 40)) 9970Sstevel@tonic-gate cmn_err(CE_WARN, 9980Sstevel@tonic-gate "fdc_select: controller setup rejected " 9990Sstevel@tonic-gate "fdcntrl %p transfer rate %x step rate %x" 10000Sstevel@tonic-gate " head load time 40\n", (void*)fcp, 10010Sstevel@tonic-gate fjp->fj_chars->fdc_transfer_rate, 10020Sstevel@tonic-gate fjp->fj_drive->fdd_steprate); 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate /* make sure drive is not selected in case we change speed */ 10080Sstevel@tonic-gate fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | 10090Sstevel@tonic-gate (~unit & FD_DRSEL); 10100Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_STARTCMD, 10130Sstevel@tonic-gate fjp->fj_drive->fdd_motoron); 10140Sstevel@tonic-gate /* 10150Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 10160Sstevel@tonic-gate */ 10170Sstevel@tonic-gate if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) { 10180Sstevel@tonic-gate /* 3D drive requires 500 ms for speed change */ 10190Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5); 10200Sstevel@tonic-gate /* 10210Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 10220Sstevel@tonic-gate */ 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | (unit & FD_DRSEL); 10260Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 10290Sstevel@tonic-gate fcp->c_csb.csb_drive = (uchar_t)unit; 10300Sstevel@tonic-gate } else { 10310Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_DSEL, 10320Sstevel@tonic-gate (CE_NOTE, "fdc_select unit %d: off", funit)); 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate fcp->c_digout |= FD_DRSEL; 10370Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 10380Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_IDLECMD, 10390Sstevel@tonic-gate fjp->fj_drive->fdd_motoroff); 10400Sstevel@tonic-gate /* 10410Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 10420Sstevel@tonic-gate */ 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate /* give up controller */ 10470Sstevel@tonic-gate sema_v(&fcp->c_selsem); 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate return (0); 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate int 10540Sstevel@tonic-gate fdgetchng(struct fcu_obj *fjp, int funit) 10550Sstevel@tonic-gate { 10560Sstevel@tonic-gate if (fdcsense_drv(fjp->fj_fdc, funit & 3)) 10570Sstevel@tonic-gate cmn_err(CE_WARN, "fdgetchng: write protect check failed\n"); 10580Sstevel@tonic-gate return (fdcsense_chng(fjp->fj_fdc, funit & 3)); 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate int 10630Sstevel@tonic-gate fdresetchng(struct fcu_obj *fjp, int funit) 10640Sstevel@tonic-gate { 10650Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 10660Sstevel@tonic-gate int unit = funit & 3; 10670Sstevel@tonic-gate int newcyl; /* where to seek for reset of DSKCHG */ 10680Sstevel@tonic-gate 10690Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_CHEK, (CE_NOTE, "fdmediachng unit %d", funit)); 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate if (fcp->c_curpcyl[unit]) 10720Sstevel@tonic-gate newcyl = fcp->c_curpcyl[unit] - 1; 10730Sstevel@tonic-gate else 10740Sstevel@tonic-gate newcyl = 1; 10750Sstevel@tonic-gate return (fdrecalseek(fjp, funit, newcyl, 0)); 10760Sstevel@tonic-gate } 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate /* 10800Sstevel@tonic-gate * fdrecalseek 10810Sstevel@tonic-gate */ 10820Sstevel@tonic-gate int 10830Sstevel@tonic-gate fdrecalseek(struct fcu_obj *fjp, int funit, int arg, int execflg) 10840Sstevel@tonic-gate { 10850Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 10860Sstevel@tonic-gate struct fdcsb *csb; 10870Sstevel@tonic-gate int unit = funit & 3; 10880Sstevel@tonic-gate int rval; 10890Sstevel@tonic-gate 10900Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECA, (CE_NOTE, "fdrecalseek unit %d to %d", 10910Sstevel@tonic-gate funit, arg)); 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate csb = &fcp->c_csb; 10940Sstevel@tonic-gate csb->csb_cmd[1] = (uchar_t)unit; 10950Sstevel@tonic-gate if (arg < 0) { /* is recal... */ 10960Sstevel@tonic-gate *csb->csb_cmd = FO_RECAL; 10970Sstevel@tonic-gate csb->csb_ncmds = 2; 10980Sstevel@tonic-gate csb->csb_timer = 28; 10990Sstevel@tonic-gate } else { 11000Sstevel@tonic-gate *csb->csb_cmd = FO_SEEK; 11010Sstevel@tonic-gate csb->csb_cmd[2] = (uchar_t)arg; 11020Sstevel@tonic-gate csb->csb_ncmds = 3; 11030Sstevel@tonic-gate csb->csb_timer = 10; 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */ 11060Sstevel@tonic-gate csb->csb_opflags = CSB_OFINRPT; 11070Sstevel@tonic-gate csb->csb_maxretry = skretry; 11080Sstevel@tonic-gate csb->csb_dmahandle = NULL; 11090Sstevel@tonic-gate csb->csb_handle_bound = 0; 11100Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 11110Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 11120Sstevel@tonic-gate csb->csb_dmawincnt = 0; 11130Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate /* send cmd off to fdc_exec */ 11160Sstevel@tonic-gate if (rval = fdc_exec(fcp, 1, execflg)) 11170Sstevel@tonic-gate goto out; 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate if (!(*csb->csb_rslt & S0_SEKEND) || 11200Sstevel@tonic-gate (*csb->csb_rslt & S0_ICMASK) || 11210Sstevel@tonic-gate ((*csb->csb_rslt & S0_ECHK) && arg < 0) || 11220Sstevel@tonic-gate csb->csb_cmdstat) 11230Sstevel@tonic-gate rval = ENODEV; 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate if (fdcsense_drv(fcp, unit)) 11260Sstevel@tonic-gate cmn_err(CE_WARN, "fdgetchng: write protect check failed\n"); 11270Sstevel@tonic-gate out: 11280Sstevel@tonic-gate return (rval); 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate /* 11330Sstevel@tonic-gate * fdrw- used only for read/writing sectors into/from kernel buffers. 11340Sstevel@tonic-gate */ 11350Sstevel@tonic-gate int 11360Sstevel@tonic-gate fdrw(struct fcu_obj *fjp, int funit, int rw, int cyl, int head, 11370Sstevel@tonic-gate int sector, caddr_t bufp, uint_t len) 11380Sstevel@tonic-gate { 11390Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 11400Sstevel@tonic-gate struct fdcsb *csb; 11410Sstevel@tonic-gate uint_t dmar_flags = 0; 11420Sstevel@tonic-gate int unit = funit & 3; 11430Sstevel@tonic-gate int rval; 1144940Smrj ddi_acc_handle_t mem_handle = NULL; 1145940Smrj caddr_t aligned_buf; 1146940Smrj size_t real_size; 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RW, (CE_CONT, "fdrw unit %d\n", funit)); 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate csb = &fcp->c_csb; 11510Sstevel@tonic-gate if (rw) { 11520Sstevel@tonic-gate dmar_flags = DDI_DMA_READ; 11530Sstevel@tonic-gate csb->csb_opflags = CSB_OFDMARD | CSB_OFINRPT; 11540Sstevel@tonic-gate *csb->csb_cmd = FO_MT | FO_MFM | FO_SK | FO_RDDAT; 11550Sstevel@tonic-gate } else { /* write */ 11560Sstevel@tonic-gate dmar_flags = DDI_DMA_WRITE; 11570Sstevel@tonic-gate csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT; 11580Sstevel@tonic-gate *csb->csb_cmd = FO_MT | FO_MFM | FO_WRDAT; 11590Sstevel@tonic-gate } 11600Sstevel@tonic-gate csb->csb_cmd[1] = (uchar_t)(unit | ((head & 0x1) << 2)); 11610Sstevel@tonic-gate csb->csb_cmd[2] = (uchar_t)cyl; 11620Sstevel@tonic-gate csb->csb_cmd[3] = (uchar_t)head; 11630Sstevel@tonic-gate csb->csb_cmd[4] = (uchar_t)sector; 11640Sstevel@tonic-gate encode(sector_size, fjp->fj_chars->fdc_sec_size, 11650Sstevel@tonic-gate &csb->csb_cmd[5]); 11660Sstevel@tonic-gate csb->csb_cmd[6] = (uchar_t)max(fjp->fj_chars->fdc_secptrack, sector); 11670Sstevel@tonic-gate csb->csb_cmd[7] = fjp->fj_attr->fda_gapl; 11680Sstevel@tonic-gate csb->csb_cmd[8] = 0xFF; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate csb->csb_ncmds = 9; 11710Sstevel@tonic-gate csb->csb_nrslts = 7; 11720Sstevel@tonic-gate csb->csb_timer = 36; 11730Sstevel@tonic-gate if (rw == FDRDONE) 11740Sstevel@tonic-gate csb->csb_maxretry = 1; 11750Sstevel@tonic-gate else 11760Sstevel@tonic-gate csb->csb_maxretry = rwretry; 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate csb->csb_dmahandle = NULL; 11790Sstevel@tonic-gate csb->csb_handle_bound = 0; 11800Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 11810Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 11820Sstevel@tonic-gate csb->csb_dmawincnt = 0; 11830Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 11840Sstevel@tonic-gate dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL); 11850Sstevel@tonic-gate 1186940Smrj if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP, 11875295Srandyf 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 11880Sstevel@tonic-gate rval = EINVAL; 11890Sstevel@tonic-gate goto out; 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate 1192940Smrj /* 1193940Smrj * allocate a page aligned buffer to dma to/from. This way we can 1194940Smrj * ensure the cookie is a whole multiple of granularity and avoids 1195940Smrj * any alignment issues. 1196940Smrj */ 1197940Smrj rval = ddi_dma_mem_alloc(csb->csb_dmahandle, len, &fdc_accattr, 1198940Smrj DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &aligned_buf, 1199940Smrj &real_size, &mem_handle); 1200940Smrj if (rval != DDI_SUCCESS) { 1201940Smrj rval = EINVAL; 1202940Smrj goto out; 1203940Smrj } 1204940Smrj 1205940Smrj if (dmar_flags & DDI_DMA_WRITE) { 1206940Smrj bcopy(bufp, aligned_buf, len); 1207940Smrj } 1208940Smrj 1209940Smrj rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, aligned_buf, 1210940Smrj len, dmar_flags, DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, 1211940Smrj &csb->csb_dmacookiecnt); 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate if (rval == DDI_DMA_MAPPED) { 12140Sstevel@tonic-gate csb->csb_dmawincnt = 1; 12150Sstevel@tonic-gate csb->csb_handle_bound = 1; 12160Sstevel@tonic-gate } else if (rval == DDI_DMA_PARTIAL_MAP) { 12170Sstevel@tonic-gate csb->csb_handle_bound = 1; 12180Sstevel@tonic-gate if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != 12195295Srandyf DDI_SUCCESS) { 12200Sstevel@tonic-gate cmn_err(CE_WARN, "fdrw: dma numwin failed\n"); 12210Sstevel@tonic-gate rval = EINVAL; 12220Sstevel@tonic-gate goto out; 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate } else { 12250Sstevel@tonic-gate cmn_err(CE_WARN, 12265295Srandyf "fdrw: dma addr bind handle failed, rval = %d\n", rval); 12270Sstevel@tonic-gate rval = EINVAL; 12280Sstevel@tonic-gate goto out; 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate rval = fdc_exec(fcp, 1, 1); 12310Sstevel@tonic-gate 1232940Smrj if (dmar_flags & DDI_DMA_READ) { 1233940Smrj bcopy(aligned_buf, bufp, len); 1234940Smrj } 1235940Smrj 12360Sstevel@tonic-gate out: 12370Sstevel@tonic-gate if (csb->csb_dmahandle) { 12380Sstevel@tonic-gate if (csb->csb_handle_bound) { 12390Sstevel@tonic-gate if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 12400Sstevel@tonic-gate DDI_SUCCESS) 12410Sstevel@tonic-gate cmn_err(CE_WARN, "fdrw: " 12420Sstevel@tonic-gate "dma unbind handle failed\n"); 12430Sstevel@tonic-gate csb->csb_handle_bound = 0; 12440Sstevel@tonic-gate } 1245940Smrj if (mem_handle != NULL) { 1246940Smrj ddi_dma_mem_free(&mem_handle); 1247940Smrj } 12480Sstevel@tonic-gate ddi_dma_free_handle(&csb->csb_dmahandle); 12490Sstevel@tonic-gate csb->csb_dmahandle = NULL; 12500Sstevel@tonic-gate } 12510Sstevel@tonic-gate return (rval); 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate int 12560Sstevel@tonic-gate fdtrkformat(struct fcu_obj *fjp, int funit, int cyl, int head, int filldata) 12570Sstevel@tonic-gate { 12580Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 12590Sstevel@tonic-gate struct fdcsb *csb; 12600Sstevel@tonic-gate int unit = funit & 3; 12610Sstevel@tonic-gate int fmdatlen, lsector, lstart; 12620Sstevel@tonic-gate int interleave, numsctr, offset, psector; 12630Sstevel@tonic-gate uchar_t *dp; 12640Sstevel@tonic-gate int rval; 1265940Smrj ddi_acc_handle_t mem_handle = NULL; 1266940Smrj caddr_t aligned_buf; 1267940Smrj size_t real_size; 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_FORM, 12700Sstevel@tonic-gate (CE_NOTE, "fdformattrk unit %d cyl=%d, hd=%d", funit, cyl, head)); 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate csb = &fcp->c_csb; 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT; 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate *csb->csb_cmd = FO_FRMT | FO_MFM; 12770Sstevel@tonic-gate csb->csb_cmd[1] = (head << 2) | unit; 12780Sstevel@tonic-gate encode(sector_size, fjp->fj_chars->fdc_sec_size, 12790Sstevel@tonic-gate &csb->csb_cmd[2]); 12800Sstevel@tonic-gate csb->csb_cmd[3] = numsctr = fjp->fj_chars->fdc_secptrack; 12810Sstevel@tonic-gate csb->csb_cmd[4] = fjp->fj_attr->fda_gapf; 12820Sstevel@tonic-gate csb->csb_cmd[5] = (uchar_t)filldata; 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate csb->csb_npcyl = (uchar_t)(cyl * fjp->fj_chars->fdc_steps); 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate csb->csb_dmahandle = NULL; 12870Sstevel@tonic-gate csb->csb_handle_bound = 0; 12880Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 12890Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 12900Sstevel@tonic-gate csb->csb_dmawincnt = 0; 12910Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 12920Sstevel@tonic-gate csb->csb_ncmds = 6; 12930Sstevel@tonic-gate csb->csb_nrslts = 7; 12940Sstevel@tonic-gate csb->csb_timer = 32; 12950Sstevel@tonic-gate csb->csb_maxretry = rwretry; 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate /* 1298940Smrj * alloc space for format track cmd 12990Sstevel@tonic-gate */ 13000Sstevel@tonic-gate /* 13010Sstevel@tonic-gate * NOTE: have to add size of fifo also - for dummy format action 13020Sstevel@tonic-gate */ 13030Sstevel@tonic-gate fmdatlen = 4 * numsctr; 1304940Smrj 1305940Smrj if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP, 13065295Srandyf 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 1307940Smrj rval = EINVAL; 1308940Smrj goto out; 1309940Smrj } 1310940Smrj 1311940Smrj /* 1312940Smrj * allocate a page aligned buffer to dma to/from. This way we can 1313940Smrj * ensure the cookie is a whole multiple of granularity and avoids 1314940Smrj * any alignment issues. 1315940Smrj */ 1316940Smrj rval = ddi_dma_mem_alloc(csb->csb_dmahandle, fmdatlen, &fdc_accattr, 1317940Smrj DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &aligned_buf, 1318940Smrj &real_size, &mem_handle); 1319940Smrj if (rval != DDI_SUCCESS) { 1320940Smrj rval = EINVAL; 1321940Smrj goto out; 1322940Smrj } 1323940Smrj dp = (uchar_t *)aligned_buf; 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate interleave = fjp->fj_attr->fda_intrlv; 13260Sstevel@tonic-gate offset = (numsctr + interleave - 1) / interleave; 13270Sstevel@tonic-gate for (psector = lstart = 1; 13280Sstevel@tonic-gate psector <= numsctr; psector += interleave, lstart++) { 13290Sstevel@tonic-gate for (lsector = lstart; lsector <= numsctr; lsector += offset) { 13300Sstevel@tonic-gate *dp++ = (uchar_t)cyl; 13310Sstevel@tonic-gate *dp++ = (uchar_t)head; 13320Sstevel@tonic-gate *dp++ = (uchar_t)lsector; 13330Sstevel@tonic-gate *dp++ = csb->csb_cmd[2]; 13340Sstevel@tonic-gate } 13350Sstevel@tonic-gate } 13360Sstevel@tonic-gate 1337940Smrj rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, aligned_buf, 1338940Smrj fmdatlen, DDI_DMA_WRITE | DDI_DMA_STREAMING | DDI_DMA_PARTIAL, 1339940Smrj DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, &csb->csb_dmacookiecnt); 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate if (rval == DDI_DMA_MAPPED) { 13420Sstevel@tonic-gate csb->csb_dmawincnt = 1; 13430Sstevel@tonic-gate csb->csb_handle_bound = 1; 13440Sstevel@tonic-gate } else if (rval == DDI_DMA_PARTIAL_MAP) { 13450Sstevel@tonic-gate csb->csb_handle_bound = 1; 13460Sstevel@tonic-gate if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != 13475295Srandyf DDI_SUCCESS) { 13480Sstevel@tonic-gate cmn_err(CE_WARN, "fdtrkformat: dma numwin failed\n"); 13490Sstevel@tonic-gate rval = EINVAL; 13500Sstevel@tonic-gate goto out; 13510Sstevel@tonic-gate } 13520Sstevel@tonic-gate } else { 13530Sstevel@tonic-gate cmn_err(CE_WARN, 13545295Srandyf "fdtrkformat: dma buf bind handle failed, rval = %d\n", 13555295Srandyf rval); 13560Sstevel@tonic-gate rval = EINVAL; 13570Sstevel@tonic-gate goto out; 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate rval = fdc_exec(fcp, 1, 1); 13610Sstevel@tonic-gate out: 13620Sstevel@tonic-gate if (csb->csb_dmahandle) { 13630Sstevel@tonic-gate if (csb->csb_handle_bound) { 13640Sstevel@tonic-gate if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 13650Sstevel@tonic-gate DDI_SUCCESS) 13660Sstevel@tonic-gate cmn_err(CE_WARN, "fdtrkformat: " 13670Sstevel@tonic-gate "dma unbind handle failed\n"); 13680Sstevel@tonic-gate csb->csb_handle_bound = 0; 13690Sstevel@tonic-gate } 1370940Smrj if (mem_handle != NULL) { 1371940Smrj ddi_dma_mem_free(&mem_handle); 1372940Smrj } 13730Sstevel@tonic-gate ddi_dma_free_handle(&csb->csb_dmahandle); 13740Sstevel@tonic-gate csb->csb_dmahandle = NULL; 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate return (rval); 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate /* ARGSUSED */ 13800Sstevel@tonic-gate int 13810Sstevel@tonic-gate fdrawioctl(struct fcu_obj *fjp, int funit, caddr_t arg) 13820Sstevel@tonic-gate { 13830Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 13840Sstevel@tonic-gate struct fd_raw *fdrp = (struct fd_raw *)arg; 13850Sstevel@tonic-gate struct fdcsb *csb; 13860Sstevel@tonic-gate uint_t dmar_flags = 0; 13870Sstevel@tonic-gate int i; 13880Sstevel@tonic-gate int change = 1; 13890Sstevel@tonic-gate int sleep = 1; 13900Sstevel@tonic-gate int rval = 0; 13910Sstevel@tonic-gate int rval_exec = 0; 1392940Smrj ddi_acc_handle_t mem_handle = NULL; 1393940Smrj caddr_t aligned_buf; 1394940Smrj size_t real_size; 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RAWI, 13970Sstevel@tonic-gate (CE_NOTE, "fdrawioctl: cmd[0]=0x%x", fdrp->fdr_cmd[0])); 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate csb = &fcp->c_csb; 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate /* copy cmd bytes into csb */ 14020Sstevel@tonic-gate for (i = 0; i <= fdrp->fdr_cnum; i++) 14030Sstevel@tonic-gate csb->csb_cmd[i] = fdrp->fdr_cmd[i]; 14040Sstevel@tonic-gate csb->csb_ncmds = (uchar_t)fdrp->fdr_cnum; 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate csb->csb_maxretry = 0; /* let the application deal with errors */ 14070Sstevel@tonic-gate csb->csb_opflags = CSB_OFRAWIOCTL; 14080Sstevel@tonic-gate csb->csb_nrslts = 0; 14090Sstevel@tonic-gate csb->csb_timer = 50; 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate switch (fdrp->fdr_cmd[0] & 0x0f) { 14120Sstevel@tonic-gate 14130Sstevel@tonic-gate case FO_SEEK: 14140Sstevel@tonic-gate change = 0; 14150Sstevel@tonic-gate /* FALLTHROUGH */ 14160Sstevel@tonic-gate case FO_RECAL: 14170Sstevel@tonic-gate csb->csb_opflags |= CSB_OFINRPT; 14180Sstevel@tonic-gate break; 14190Sstevel@tonic-gate 14200Sstevel@tonic-gate case FO_FRMT: 14210Sstevel@tonic-gate csb->csb_npcyl = *(uchar_t *)(fdrp->fdr_addr) * 14220Sstevel@tonic-gate fjp->fj_chars->fdc_steps; 14230Sstevel@tonic-gate /* FALLTHROUGH */ 14240Sstevel@tonic-gate case FO_WRDAT: 14250Sstevel@tonic-gate case FO_WRDEL: 14260Sstevel@tonic-gate csb->csb_opflags |= CSB_OFDMAWT | CSB_OFRESLT | CSB_OFINRPT; 14270Sstevel@tonic-gate csb->csb_nrslts = 7; 14280Sstevel@tonic-gate if (fdrp->fdr_nbytes == 0) 14290Sstevel@tonic-gate return (EINVAL); 14300Sstevel@tonic-gate dmar_flags = DDI_DMA_WRITE; 14310Sstevel@tonic-gate break; 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate case FO_RDDAT: 14340Sstevel@tonic-gate case FO_RDDEL: 14350Sstevel@tonic-gate case FO_RDTRK: 14360Sstevel@tonic-gate csb->csb_opflags |= CSB_OFDMARD | CSB_OFRESLT | CSB_OFINRPT; 14370Sstevel@tonic-gate csb->csb_nrslts = 7; 14380Sstevel@tonic-gate dmar_flags = DDI_DMA_READ; 14390Sstevel@tonic-gate break; 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate case FO_RDID: 14420Sstevel@tonic-gate csb->csb_opflags |= CSB_OFRESLT | CSB_OFINRPT; 14430Sstevel@tonic-gate csb->csb_nrslts = 7; 14440Sstevel@tonic-gate break; 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate case FO_SDRV: 14470Sstevel@tonic-gate sleep = 0; 14480Sstevel@tonic-gate csb->csb_nrslts = 1; 14490Sstevel@tonic-gate break; 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate case FO_SINT: 14520Sstevel@tonic-gate sleep = 0; 14530Sstevel@tonic-gate change = 0; 14540Sstevel@tonic-gate csb->csb_nrslts = 2; 14550Sstevel@tonic-gate break; 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate case FO_SPEC: 14580Sstevel@tonic-gate sleep = 0; 14590Sstevel@tonic-gate change = 0; 14600Sstevel@tonic-gate break; 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate default: 14630Sstevel@tonic-gate return (EINVAL); 14640Sstevel@tonic-gate } 14650Sstevel@tonic-gate 14660Sstevel@tonic-gate csb->csb_dmahandle = NULL; 14670Sstevel@tonic-gate csb->csb_handle_bound = 0; 14680Sstevel@tonic-gate csb->csb_dmacookiecnt = 0; 14690Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 14700Sstevel@tonic-gate csb->csb_dmawincnt = 0; 14710Sstevel@tonic-gate csb->csb_dmacurrwin = 0; 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) { 1474940Smrj if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, 1475940Smrj DDI_DMA_SLEEP, 0, &csb->csb_dmahandle) != DDI_SUCCESS) { 14760Sstevel@tonic-gate rval = EINVAL; 14770Sstevel@tonic-gate goto out; 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate 1480940Smrj /* 1481940Smrj * allocate a page aligned buffer to dma to/from. This way we 1482940Smrj * can ensure the cookie is a whole multiple of granularity and 1483940Smrj * avoids any alignment issues. 1484940Smrj */ 1485940Smrj rval = ddi_dma_mem_alloc(csb->csb_dmahandle, 1486940Smrj (uint_t)fdrp->fdr_nbytes, &fdc_accattr, DDI_DMA_CONSISTENT, 1487940Smrj DDI_DMA_SLEEP, NULL, &aligned_buf, &real_size, &mem_handle); 1488940Smrj if (rval != DDI_SUCCESS) { 1489940Smrj rval = EINVAL; 1490940Smrj goto out; 1491940Smrj } 1492940Smrj 1493940Smrj if (dmar_flags & DDI_DMA_WRITE) { 1494940Smrj bcopy(fdrp->fdr_addr, aligned_buf, 1495940Smrj (uint_t)fdrp->fdr_nbytes); 1496940Smrj } 1497940Smrj 14980Sstevel@tonic-gate dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL); 14990Sstevel@tonic-gate rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, 1500940Smrj aligned_buf, (uint_t)fdrp->fdr_nbytes, dmar_flags, 1501940Smrj DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, 1502940Smrj &csb->csb_dmacookiecnt); 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate if (rval == DDI_DMA_MAPPED) { 15050Sstevel@tonic-gate csb->csb_dmawincnt = 1; 15060Sstevel@tonic-gate csb->csb_handle_bound = 1; 15070Sstevel@tonic-gate } else if (rval == DDI_DMA_PARTIAL_MAP) { 15080Sstevel@tonic-gate csb->csb_handle_bound = 1; 15090Sstevel@tonic-gate if (ddi_dma_numwin(csb->csb_dmahandle, 15100Sstevel@tonic-gate &csb->csb_dmawincnt) != DDI_SUCCESS) { 15110Sstevel@tonic-gate cmn_err(CE_WARN, 15120Sstevel@tonic-gate "fdrawioctl: dma numwin failed\n"); 15130Sstevel@tonic-gate rval = EINVAL; 15140Sstevel@tonic-gate goto out; 15150Sstevel@tonic-gate } 15160Sstevel@tonic-gate } else { 15170Sstevel@tonic-gate cmn_err(CE_WARN, "fdrawioctl: " 15180Sstevel@tonic-gate "dma buf bind handle failed, rval = %d\n", rval); 15190Sstevel@tonic-gate rval = EINVAL; 15200Sstevel@tonic-gate goto out; 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RAWI, 15250Sstevel@tonic-gate (CE_CONT, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmd[0], 15260Sstevel@tonic-gate csb->csb_cmd[1], csb->csb_cmd[2], csb->csb_cmd[3], 15270Sstevel@tonic-gate csb->csb_cmd[4], csb->csb_cmd[5], csb->csb_cmd[6], 15280Sstevel@tonic-gate csb->csb_cmd[7], csb->csb_cmd[8], csb->csb_cmd[9])); 15290Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RAWI, 15300Sstevel@tonic-gate (CE_CONT, "nbytes: %x, opflags: %x, addr: %p, len: %x\n", 15310Sstevel@tonic-gate csb->csb_ncmds, csb->csb_opflags, (void *)fdrp->fdr_addr, 15320Sstevel@tonic-gate fdrp->fdr_nbytes)); 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate /* 15350Sstevel@tonic-gate * Note that we ignore any error returns from fdexec. 15360Sstevel@tonic-gate * This is the way the driver has been, and it may be 15370Sstevel@tonic-gate * that the raw ioctl senders simply don't want to 15380Sstevel@tonic-gate * see any errors returned in this fashion. 15390Sstevel@tonic-gate */ 15400Sstevel@tonic-gate 15410Sstevel@tonic-gate /* 15420Sstevel@tonic-gate * VP/ix sense drive ioctl call checks for the error return. 15430Sstevel@tonic-gate */ 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate rval_exec = fdc_exec(fcp, sleep, change); 15460Sstevel@tonic-gate 1547940Smrj if (dmar_flags & DDI_DMA_READ) { 1548940Smrj bcopy(aligned_buf, fdrp->fdr_addr, (uint_t)fdrp->fdr_nbytes); 1549940Smrj } 1550940Smrj 15510Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_RAWI, 15520Sstevel@tonic-gate (CE_CONT, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0], 15530Sstevel@tonic-gate csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3], 15540Sstevel@tonic-gate csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6], 15550Sstevel@tonic-gate csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9])); 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate /* copy results into fdr */ 15580Sstevel@tonic-gate for (i = 0; i <= (int)csb->csb_nrslts; i++) 15590Sstevel@tonic-gate fdrp->fdr_result[i] = csb->csb_rslt[i]; 15600Sstevel@tonic-gate /* fdrp->fdr_nbytes = fdc->c_csb.csb_rlen; return resid */ 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate out: 15630Sstevel@tonic-gate if (csb->csb_dmahandle) { 15640Sstevel@tonic-gate if (csb->csb_handle_bound) { 15650Sstevel@tonic-gate if (ddi_dma_unbind_handle(csb->csb_dmahandle) != 15660Sstevel@tonic-gate DDI_SUCCESS) 15670Sstevel@tonic-gate cmn_err(CE_WARN, "fdrawioctl: " 15680Sstevel@tonic-gate "dma unbind handle failed\n"); 15690Sstevel@tonic-gate csb->csb_handle_bound = 0; 15700Sstevel@tonic-gate } 1571940Smrj if (mem_handle != NULL) { 1572940Smrj ddi_dma_mem_free(&mem_handle); 1573940Smrj } 15740Sstevel@tonic-gate ddi_dma_free_handle(&csb->csb_dmahandle); 15750Sstevel@tonic-gate csb->csb_dmahandle = NULL; 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate if ((fdrp->fdr_cmd[0] & 0x0f) == FO_SDRV) { 15780Sstevel@tonic-gate return (rval_exec); 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate return (rval); 15810Sstevel@tonic-gate } 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate void 15840Sstevel@tonic-gate encode(xlate_tbl_t *tablep, int val, uchar_t *rcode) 15850Sstevel@tonic-gate { 15860Sstevel@tonic-gate do { 15870Sstevel@tonic-gate if (tablep->value >= val) { 15880Sstevel@tonic-gate *rcode = tablep->code; 15890Sstevel@tonic-gate return; 15900Sstevel@tonic-gate } 15910Sstevel@tonic-gate } while ((++tablep)->value); 15920Sstevel@tonic-gate *rcode = tablep->code; 15930Sstevel@tonic-gate cmn_err(CE_WARN, "fdc encode failed, table %p val %x code %x\n", 15940Sstevel@tonic-gate (void *)tablep, val, (uint_t)*rcode); 15950Sstevel@tonic-gate } 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate int 15980Sstevel@tonic-gate decode(xlate_tbl_t *tablep, int kode, int *rvalue) 15990Sstevel@tonic-gate { 16000Sstevel@tonic-gate do { 16010Sstevel@tonic-gate if (tablep->code == kode) { 16020Sstevel@tonic-gate *rvalue = tablep->value; 16030Sstevel@tonic-gate return (0); 16040Sstevel@tonic-gate } 16050Sstevel@tonic-gate } while ((++tablep)->value); 16060Sstevel@tonic-gate return (-1); 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate 1609*7656SSherry.Moore@Sun.COM /* 1610*7656SSherry.Moore@Sun.COM * quiesce(9E) entry point. 1611*7656SSherry.Moore@Sun.COM * 1612*7656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high 1613*7656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 1614*7656SSherry.Moore@Sun.COM * blocked. 1615*7656SSherry.Moore@Sun.COM * 1616*7656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 1617*7656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 1618*7656SSherry.Moore@Sun.COM */ 1619*7656SSherry.Moore@Sun.COM int 1620*7656SSherry.Moore@Sun.COM fdc_quiesce(dev_info_t *dip) 1621*7656SSherry.Moore@Sun.COM { 1622*7656SSherry.Moore@Sun.COM struct fdcntlr *fcp; 1623*7656SSherry.Moore@Sun.COM int ctlr = ddi_get_instance(dip); 1624*7656SSherry.Moore@Sun.COM int unit; 1625*7656SSherry.Moore@Sun.COM 1626*7656SSherry.Moore@Sun.COM fcp = ddi_get_soft_state(fdc_state_head, ctlr); 1627*7656SSherry.Moore@Sun.COM 1628*7656SSherry.Moore@Sun.COM if (fcp == NULL) 1629*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 1630*7656SSherry.Moore@Sun.COM 1631*7656SSherry.Moore@Sun.COM /* 1632*7656SSherry.Moore@Sun.COM * If no FD units are attached, there is no need to quiesce. 1633*7656SSherry.Moore@Sun.COM */ 1634*7656SSherry.Moore@Sun.COM for (unit = 0; unit < NFDUN; unit++) { 1635*7656SSherry.Moore@Sun.COM struct fcu_obj *fjp = fcp->c_unit[unit]; 1636*7656SSherry.Moore@Sun.COM if (fjp->fj_flags & FUNIT_DRVATCH) { 1637*7656SSherry.Moore@Sun.COM break; 1638*7656SSherry.Moore@Sun.COM } 1639*7656SSherry.Moore@Sun.COM } 1640*7656SSherry.Moore@Sun.COM 1641*7656SSherry.Moore@Sun.COM if (unit == NFDUN) 1642*7656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 1643*7656SSherry.Moore@Sun.COM 1644*7656SSherry.Moore@Sun.COM (void) ddi_dmae_disable(fcp->c_dip, fcp->c_dmachan); 1645*7656SSherry.Moore@Sun.COM 1646*7656SSherry.Moore@Sun.COM fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE; 1647*7656SSherry.Moore@Sun.COM outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1648*7656SSherry.Moore@Sun.COM drv_usecwait(20); 1649*7656SSherry.Moore@Sun.COM fcp->c_digout |= FD_RSETZ; 1650*7656SSherry.Moore@Sun.COM outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 1651*7656SSherry.Moore@Sun.COM 1652*7656SSherry.Moore@Sun.COM if (fcp->c_chip >= i82077) { 1653*7656SSherry.Moore@Sun.COM int count = 4; 1654*7656SSherry.Moore@Sun.COM uchar_t *oplistp = configurecmd; 1655*7656SSherry.Moore@Sun.COM do { 1656*7656SSherry.Moore@Sun.COM int ntries = FDC_RQM_RETRY; 1657*7656SSherry.Moore@Sun.COM do { 1658*7656SSherry.Moore@Sun.COM if ((inb(fcp->c_regbase + FCR_MSR) & 1659*7656SSherry.Moore@Sun.COM (MS_RQM|MS_DIO)) == MS_RQM) 1660*7656SSherry.Moore@Sun.COM break; 1661*7656SSherry.Moore@Sun.COM else 1662*7656SSherry.Moore@Sun.COM drv_usecwait(1); 1663*7656SSherry.Moore@Sun.COM } while (--ntries); 1664*7656SSherry.Moore@Sun.COM if (ntries == 0) { 1665*7656SSherry.Moore@Sun.COM break; 1666*7656SSherry.Moore@Sun.COM } 1667*7656SSherry.Moore@Sun.COM outb(fcp->c_regbase + FCR_DATA, *oplistp++); 1668*7656SSherry.Moore@Sun.COM drv_usecwait(16); /* See comment in fdc_result() */ 1669*7656SSherry.Moore@Sun.COM } while (--count); 1670*7656SSherry.Moore@Sun.COM } 1671*7656SSherry.Moore@Sun.COM 1672*7656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 1673*7656SSherry.Moore@Sun.COM } 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate void 16760Sstevel@tonic-gate fdcquiesce(struct fdcntlr *fcp) 16770Sstevel@tonic-gate { 16780Sstevel@tonic-gate int unit; 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RESE, (CE_NOTE, "fdcquiesce fcp %p", 16815295Srandyf (void*)fcp)); 1682*7656SSherry.Moore@Sun.COM 16830Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_lock)); 16840Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 16850Sstevel@tonic-gate 16860Sstevel@tonic-gate if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS) 16870Sstevel@tonic-gate cmn_err(CE_WARN, "fdcquiesce: dmae stop failed, " 16885295Srandyf "dip %p, dmachan %x\n", 16895295Srandyf (void*)fcp->c_dip, fcp->c_dmachan); 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE; 16920Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 16930Sstevel@tonic-gate drv_usecwait(20); 16940Sstevel@tonic-gate fcp->c_digout |= FD_RSETZ; 16950Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 16980Sstevel@tonic-gate 16990Sstevel@tonic-gate /* count resets */ 17000Sstevel@tonic-gate fcp->fdstats.reset++; 17010Sstevel@tonic-gate fcp->c_curunit = -1; 17020Sstevel@tonic-gate for (unit = 0; unit < NFDUN; unit++) 17030Sstevel@tonic-gate fcp->c_curpcyl[unit] = -1; 17040Sstevel@tonic-gate 17050Sstevel@tonic-gate if (fcp->c_chip >= i82077) { 17060Sstevel@tonic-gate (void) fdc_docmd(fcp, configurecmd, 4); 17070Sstevel@tonic-gate /* 17080Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 17090Sstevel@tonic-gate */ 17100Sstevel@tonic-gate } 17110Sstevel@tonic-gate } 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate void 17140Sstevel@tonic-gate fdcreadid(struct fdcntlr *fcp, struct fdcsb *csb) 17150Sstevel@tonic-gate { 17160Sstevel@tonic-gate static uchar_t readidcmd[2] = {FO_RDID | FO_MFM, 0}; 17170Sstevel@tonic-gate 17180Sstevel@tonic-gate readidcmd[1] = csb->csb_cmd[1]; 17190Sstevel@tonic-gate (void) fdc_docmd(fcp, readidcmd, 2); 17200Sstevel@tonic-gate } 17210Sstevel@tonic-gate 17220Sstevel@tonic-gate int 17230Sstevel@tonic-gate fdcseek(struct fdcntlr *fcp, int unit, int cyl) 17240Sstevel@tonic-gate { 17250Sstevel@tonic-gate static uchar_t seekabscmd[3] = {FO_SEEK, 0, 0}; 17260Sstevel@tonic-gate 17270Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_RECA, (CE_CONT, "fdcseek unit %d to cyl %d\n", 17280Sstevel@tonic-gate unit, cyl)); 17290Sstevel@tonic-gate seekabscmd[1] = (uchar_t)unit; 17300Sstevel@tonic-gate seekabscmd[2] = (uchar_t)cyl; 17310Sstevel@tonic-gate return (fdc_docmd(fcp, seekabscmd, 3)); 17320Sstevel@tonic-gate } 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate /* 17350Sstevel@tonic-gate * Returns status of disk change line of selected drive. 17360Sstevel@tonic-gate * = 0 means diskette is present 17370Sstevel@tonic-gate * != 0 means diskette was removed and current state is unknown 17380Sstevel@tonic-gate */ 17390Sstevel@tonic-gate int 17400Sstevel@tonic-gate fdcsense_chng(struct fdcntlr *fcp, int unit) 17410Sstevel@tonic-gate { 17420Sstevel@tonic-gate int digital_input; 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_SCHG, 17450Sstevel@tonic-gate (CE_CONT, "fdcsense_chng unit %d\n", unit)); 17460Sstevel@tonic-gate digital_input = inb(fcp->c_regbase + FCR_DIR); 17470Sstevel@tonic-gate if (fcp->c_mode == FDCMODE_30) 17480Sstevel@tonic-gate digital_input ^= FDI_DKCHG; 17490Sstevel@tonic-gate return (digital_input & FDI_DKCHG); 17500Sstevel@tonic-gate } 17510Sstevel@tonic-gate 17520Sstevel@tonic-gate int 17530Sstevel@tonic-gate fdcsense_drv(struct fdcntlr *fcp, int unit) 17540Sstevel@tonic-gate { 17550Sstevel@tonic-gate static uchar_t sensedrvcmd[2] = {FO_SDRV, 0}; 17560Sstevel@tonic-gate uchar_t senser; 17570Sstevel@tonic-gate int rval; 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate sensedrvcmd[1] = (uchar_t)unit; 17600Sstevel@tonic-gate (void) fdc_docmd(fcp, sensedrvcmd, 2); 17610Sstevel@tonic-gate /* 17620Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 17630Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 17640Sstevel@tonic-gate */ 17650Sstevel@tonic-gate if (rval = fdc_result(fcp, &senser, 1)) 17660Sstevel@tonic-gate goto done; 17670Sstevel@tonic-gate if (senser & S3_WPROT) 17680Sstevel@tonic-gate fcp->c_unit[unit]->fj_flags |= FUNIT_WPROT; 17690Sstevel@tonic-gate else 17700Sstevel@tonic-gate fcp->c_unit[unit]->fj_flags &= ~FUNIT_WPROT; 17710Sstevel@tonic-gate done: 17720Sstevel@tonic-gate return (rval); 17730Sstevel@tonic-gate } 17740Sstevel@tonic-gate 17750Sstevel@tonic-gate int 17760Sstevel@tonic-gate fdcsense_int(struct fdcntlr *fcp, int *unitp, int *cylp) 17770Sstevel@tonic-gate { 17780Sstevel@tonic-gate uchar_t senser[2]; 17790Sstevel@tonic-gate int rval; 17800Sstevel@tonic-gate 17810Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 17820Sstevel@tonic-gate /* 17830Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 17840Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 17850Sstevel@tonic-gate */ 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate if (!(rval = fdc_result(fcp, senser, 2))) { 17880Sstevel@tonic-gate if ((*senser & (S0_IVCMD | S0_SEKEND | S0_ECHK)) != S0_SEKEND) 17890Sstevel@tonic-gate rval = 1; 17900Sstevel@tonic-gate if (unitp) 17910Sstevel@tonic-gate *unitp = *senser & 3; 17920Sstevel@tonic-gate if (cylp) 17930Sstevel@tonic-gate *cylp = senser[1]; 17940Sstevel@tonic-gate } 17950Sstevel@tonic-gate return (rval); 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate int 17990Sstevel@tonic-gate fdcspecify(struct fdcntlr *fcp, int xferrate, int steprate, int hlt) 18000Sstevel@tonic-gate { 18010Sstevel@tonic-gate static uchar_t perpindcmd[2] = {FO_PERP, 0}; 18020Sstevel@tonic-gate static uchar_t specifycmd[3] = {FO_SPEC, 0, 0}; 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate encode(drate_mfm, xferrate, &fcp->c_config); 18050Sstevel@tonic-gate outb(fcp->c_regbase + FCR_CCR, fcp->c_config); 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate if (fcp->c_chip >= i82077) { 18080Sstevel@tonic-gate /* 18090Sstevel@tonic-gate * Use old style perpendicular mode command of 82077. 18100Sstevel@tonic-gate */ 18110Sstevel@tonic-gate if (xferrate == 1000) { 18120Sstevel@tonic-gate /* Set GAP and WGATE */ 18130Sstevel@tonic-gate perpindcmd[1] = 3; 18140Sstevel@tonic-gate /* double step rate because xlate table is for 500Kb */ 18150Sstevel@tonic-gate steprate <<= 1; 18160Sstevel@tonic-gate hlt <<= 1; 18170Sstevel@tonic-gate } else 18180Sstevel@tonic-gate perpindcmd[1] = 0; 18190Sstevel@tonic-gate (void) fdc_docmd(fcp, perpindcmd, 2); 18200Sstevel@tonic-gate /* 18210Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 18220Sstevel@tonic-gate */ 18230Sstevel@tonic-gate } 18240Sstevel@tonic-gate encode(step_rate, steprate, &fcp->c_hutsrt); 18250Sstevel@tonic-gate specifycmd[1] = fcp->c_hutsrt |= 0x0F; /* use max head unload time */ 18260Sstevel@tonic-gate hlt = (hlt >= 256) ? 0 : (hlt >> 1); /* encode head load time */ 18270Sstevel@tonic-gate specifycmd[2] = fcp->c_hlt = hlt << 1; /* make room for DMA bit */ 18280Sstevel@tonic-gate return (fdc_docmd(fcp, specifycmd, 3)); 18290Sstevel@tonic-gate } 18300Sstevel@tonic-gate 18310Sstevel@tonic-gate int 18320Sstevel@tonic-gate fdcspdchange(struct fdcntlr *fcp, struct fcu_obj *fjp, int rpm) 18330Sstevel@tonic-gate { 18340Sstevel@tonic-gate int retcode = 0; 18350Sstevel@tonic-gate uint_t ddic; 18360Sstevel@tonic-gate uchar_t deselect = 0; 18370Sstevel@tonic-gate uchar_t ds_code; 18380Sstevel@tonic-gate uchar_t enable_code; 18390Sstevel@tonic-gate uchar_t save; 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate if (((fcp->c_flags & FCFLG_DSOUT) == 0 && rpm <= fjp->fj_rotspd) || 18420Sstevel@tonic-gate ((fcp->c_flags & FCFLG_DSOUT) && (fjp->fj_flags & FUNIT_3DMODE) && 18430Sstevel@tonic-gate rpm > fjp->fj_rotspd)) { 18440Sstevel@tonic-gate return (0); 18450Sstevel@tonic-gate } 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_SCHG, 18480Sstevel@tonic-gate (CE_CONT, "fdcspdchange: %d rpm\n", rpm)); 18490Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_dorlock)); 18500Sstevel@tonic-gate 18510Sstevel@tonic-gate switch (fcp->c_chip) { 18520Sstevel@tonic-gate default: 18530Sstevel@tonic-gate break; 18540Sstevel@tonic-gate case i82077: 18550Sstevel@tonic-gate break; 18560Sstevel@tonic-gate 18570Sstevel@tonic-gate case PC87322: 18580Sstevel@tonic-gate { 18590Sstevel@tonic-gate uchar_t nscmodecmd[5] = {FO_MODE, 0x02, 0x00, 0xC8, 0x00}; 18600Sstevel@tonic-gate 18610Sstevel@tonic-gate if (rpm > fjp->fj_rotspd) { 18620Sstevel@tonic-gate nscmodecmd[3] ^= 0xC0; 18630Sstevel@tonic-gate retcode = (fcp->c_flags ^ FCFLG_DSOUT) || 18640Sstevel@tonic-gate (fjp->fj_flags ^ FUNIT_3DMODE); 18650Sstevel@tonic-gate fcp->c_flags |= FCFLG_DSOUT; 18660Sstevel@tonic-gate fjp->fj_flags |= FUNIT_3DMODE; 18670Sstevel@tonic-gate } else { 18680Sstevel@tonic-gate /* program DENSEL to default output */ 18690Sstevel@tonic-gate fcp->c_flags &= ~FCFLG_DSOUT; 18700Sstevel@tonic-gate retcode = fjp->fj_flags & FUNIT_3DMODE; 18710Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_3DMODE; 18720Sstevel@tonic-gate } 18730Sstevel@tonic-gate if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) { 18740Sstevel@tonic-gate /* de-select drive while changing speed */ 18750Sstevel@tonic-gate deselect = fcp->c_digout ^ FD_DRSEL; 18760Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, deselect); 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate 18790Sstevel@tonic-gate (void) fdc_docmd(fcp, nscmodecmd, 5); 18800Sstevel@tonic-gate /* 18810Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 18820Sstevel@tonic-gate */ 18830Sstevel@tonic-gate break; 18840Sstevel@tonic-gate } 18850Sstevel@tonic-gate 18860Sstevel@tonic-gate case FDC37C665: 18870Sstevel@tonic-gate enable_code = FSA_ENA5; 18880Sstevel@tonic-gate goto SMC_config; 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate case FDC37C666: 18910Sstevel@tonic-gate enable_code = FSA_ENA6; 18920Sstevel@tonic-gate SMC_config: 18930Sstevel@tonic-gate if (rpm > fjp->fj_rotspd) { 18940Sstevel@tonic-gate /* force DENSEL output to active LOW */ 18950Sstevel@tonic-gate ds_code = FSB_DSHI; 18960Sstevel@tonic-gate retcode = (fcp->c_flags ^ FCFLG_DSOUT) || 18970Sstevel@tonic-gate (fjp->fj_flags ^ FUNIT_3DMODE); 18980Sstevel@tonic-gate fcp->c_flags |= FCFLG_DSOUT; 18990Sstevel@tonic-gate fjp->fj_flags |= FUNIT_3DMODE; 19000Sstevel@tonic-gate } else { 19010Sstevel@tonic-gate /* program DENSEL to default output */ 19020Sstevel@tonic-gate ds_code = 0; 19030Sstevel@tonic-gate fcp->c_flags &= ~FCFLG_DSOUT; 19040Sstevel@tonic-gate retcode = fjp->fj_flags & FUNIT_3DMODE; 19050Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_3DMODE; 19060Sstevel@tonic-gate } 19070Sstevel@tonic-gate if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) { 19080Sstevel@tonic-gate /* de-select drive while changing speed */ 19090Sstevel@tonic-gate deselect = fcp->c_digout ^ FD_DRSEL; 19100Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, deselect); 19110Sstevel@tonic-gate } 19120Sstevel@tonic-gate save = inb(fcp->c_regbase + FCR_SRA); 19130Sstevel@tonic-gate 19140Sstevel@tonic-gate /* enter configuration mode */ 19150Sstevel@tonic-gate ddic = ddi_enter_critical(); 19160Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, enable_code); 19170Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, enable_code); 19180Sstevel@tonic-gate ddi_exit_critical(ddic); 19190Sstevel@tonic-gate 19200Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_CR5); 19210Sstevel@tonic-gate enable_code = inb(fcp->c_regbase + FCR_SRB) & FSB_DSDEF; 19220Sstevel@tonic-gate /* update DENSEL mode bits */ 19230Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRB, enable_code | ds_code); 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate /* exit configuration mode */ 19260Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, FSA_DISB); 19270Sstevel@tonic-gate drv_usecwait(10); 19280Sstevel@tonic-gate outb(fcp->c_regbase + FCR_SRA, save); 19290Sstevel@tonic-gate break; 19300Sstevel@tonic-gate } 19310Sstevel@tonic-gate if (deselect) 19320Sstevel@tonic-gate /* reselect drive */ 19330Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 19340Sstevel@tonic-gate return (retcode); 19350Sstevel@tonic-gate } 19360Sstevel@tonic-gate 19370Sstevel@tonic-gate static int 19380Sstevel@tonic-gate fdc_motorsm(struct fcu_obj *fjp, int input, int timeval) 19390Sstevel@tonic-gate { 19400Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 19410Sstevel@tonic-gate int unit = fjp->fj_unit & 3; 19420Sstevel@tonic-gate int old_mstate; 19430Sstevel@tonic-gate int rval = 0; 19440Sstevel@tonic-gate uchar_t motorbit; 19450Sstevel@tonic-gate 19460Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_dorlock)); 19470Sstevel@tonic-gate old_mstate = fcp->c_mtrstate[unit]; 19480Sstevel@tonic-gate encode(motor_onbits, unit, &motorbit); 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate switch (input) { 19510Sstevel@tonic-gate case FMI_TIMER: /* timer expired */ 19520Sstevel@tonic-gate fcp->c_motort[unit] = 0; 19530Sstevel@tonic-gate switch (old_mstate) { 19540Sstevel@tonic-gate case FMS_START: 19550Sstevel@tonic-gate case FMS_DELAY: 19560Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_ON; 19570Sstevel@tonic-gate break; 19580Sstevel@tonic-gate case FMS_KILLST: 19590Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 19600Sstevel@tonic-gate drv_usectohz(1000000)); 19610Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_IDLE; 19620Sstevel@tonic-gate break; 19630Sstevel@tonic-gate case FMS_IDLE: 19640Sstevel@tonic-gate fcp->c_digout &= ~motorbit; 19650Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 19660Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_OFF; 19670Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_3DMODE; 19680Sstevel@tonic-gate break; 19690Sstevel@tonic-gate case 86: 19700Sstevel@tonic-gate rval = -1; 19710Sstevel@tonic-gate break; 19720Sstevel@tonic-gate case FMS_OFF: 19730Sstevel@tonic-gate case FMS_ON: 19740Sstevel@tonic-gate default: 19750Sstevel@tonic-gate rval = -2; 19760Sstevel@tonic-gate } 19770Sstevel@tonic-gate break; 19780Sstevel@tonic-gate 19790Sstevel@tonic-gate case FMI_STARTCMD: /* start command */ 19800Sstevel@tonic-gate switch (old_mstate) { 19810Sstevel@tonic-gate case FMS_IDLE: 19820Sstevel@tonic-gate fcp->c_mtrstate[unit] = 86; 19830Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 19840Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 19850Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 19860Sstevel@tonic-gate fcp->c_motort[unit] = 0; 19870Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_ON; 19880Sstevel@tonic-gate break; 19890Sstevel@tonic-gate case FMS_OFF: 19900Sstevel@tonic-gate fcp->c_digout |= motorbit; 19910Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); 19920Sstevel@tonic-gate 19930Sstevel@tonic-gate /* start motor_spinup_timer */ 19940Sstevel@tonic-gate ASSERT(timeval > 0); 19950Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 19960Sstevel@tonic-gate drv_usectohz(100000 * timeval)); 19970Sstevel@tonic-gate /* FALLTHROUGH */ 19980Sstevel@tonic-gate case FMS_KILLST: 19990Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_START; 20000Sstevel@tonic-gate break; 20010Sstevel@tonic-gate default: 20020Sstevel@tonic-gate rval = -2; 20030Sstevel@tonic-gate } 20040Sstevel@tonic-gate break; 20050Sstevel@tonic-gate 20060Sstevel@tonic-gate case FMI_RSTARTCMD: /* restart command */ 20070Sstevel@tonic-gate if (fcp->c_motort[unit] != 0) { 20080Sstevel@tonic-gate fcp->c_mtrstate[unit] = 86; 20090Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20100Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 20110Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20120Sstevel@tonic-gate } 20130Sstevel@tonic-gate ASSERT(timeval > 0); 20140Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 20150Sstevel@tonic-gate drv_usectohz(100000 * timeval)); 20160Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_START; 20170Sstevel@tonic-gate break; 20180Sstevel@tonic-gate 20190Sstevel@tonic-gate case FMI_DELAYCMD: /* delay command */ 20200Sstevel@tonic-gate if (fcp->c_motort[unit] == 0) 20210Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 20220Sstevel@tonic-gate drv_usectohz(15000)); 20230Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_DELAY; 20240Sstevel@tonic-gate break; 20250Sstevel@tonic-gate 20260Sstevel@tonic-gate case FMI_IDLECMD: /* idle command */ 20270Sstevel@tonic-gate switch (old_mstate) { 20280Sstevel@tonic-gate case FMS_DELAY: 20290Sstevel@tonic-gate fcp->c_mtrstate[unit] = 86; 20300Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20310Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 20320Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20330Sstevel@tonic-gate /* FALLTHROUGH */ 20340Sstevel@tonic-gate case FMS_ON: 20350Sstevel@tonic-gate ASSERT(timeval > 0); 20360Sstevel@tonic-gate fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp, 20370Sstevel@tonic-gate drv_usectohz(100000 * timeval)); 20380Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_IDLE; 20390Sstevel@tonic-gate break; 20400Sstevel@tonic-gate case FMS_START: 20410Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_KILLST; 20420Sstevel@tonic-gate break; 20430Sstevel@tonic-gate default: 20440Sstevel@tonic-gate rval = -2; 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate break; 20470Sstevel@tonic-gate 20480Sstevel@tonic-gate default: 20490Sstevel@tonic-gate rval = -3; 20500Sstevel@tonic-gate } 20510Sstevel@tonic-gate if (rval) { 20520Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_EXEC, (CE_WARN, 20530Sstevel@tonic-gate "fdc_motorsm: unit %d bad input %d or bad state %d", 20540Sstevel@tonic-gate (int)fjp->fj_unit, input, old_mstate)); 20550Sstevel@tonic-gate #if 0 20560Sstevel@tonic-gate cmn_err(CE_WARN, 20570Sstevel@tonic-gate "fdc_motorsm: unit %d bad input %d or bad state %d\n", 20580Sstevel@tonic-gate (int)fjp->fj_unit, input, old_mstate); 20590Sstevel@tonic-gate fcp->c_mtrstate[unit] = FMS_OFF; 20600Sstevel@tonic-gate if (fcp->c_motort[unit] != 0) { 20610Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20620Sstevel@tonic-gate (void) untimeout(fcp->c_motort[unit]); 20630Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20640Sstevel@tonic-gate fcp->c_motort[unit] = 0; 20650Sstevel@tonic-gate } 20660Sstevel@tonic-gate #endif 20670Sstevel@tonic-gate } else 20680Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_EXEC, 20690Sstevel@tonic-gate (CE_CONT, "fdc_motorsm unit %d: input %d, %d -> %d\n", 20700Sstevel@tonic-gate (int)fjp->fj_unit, input, old_mstate, 20710Sstevel@tonic-gate fcp->c_mtrstate[unit])); 20720Sstevel@tonic-gate return (rval); 20730Sstevel@tonic-gate } 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate /* 20760Sstevel@tonic-gate * fdmotort 20770Sstevel@tonic-gate * is called from timeout() when a motor timer has expired. 20780Sstevel@tonic-gate */ 20790Sstevel@tonic-gate static void 20800Sstevel@tonic-gate fdmotort(void *arg) 20810Sstevel@tonic-gate { 20820Sstevel@tonic-gate struct fcu_obj *fjp = (struct fcu_obj *)arg; 20830Sstevel@tonic-gate struct fdcntlr *fcp = fjp->fj_fdc; 20840Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 20850Sstevel@tonic-gate int unit = fjp->fj_unit & 3; 20860Sstevel@tonic-gate int mval; 20870Sstevel@tonic-gate int newxstate = 0; 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 20900Sstevel@tonic-gate mval = fdc_motorsm(fjp, FMI_TIMER, 0); 20910Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 20920Sstevel@tonic-gate if (mval < 0) 20930Sstevel@tonic-gate return; 20940Sstevel@tonic-gate 20950Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 20960Sstevel@tonic-gate 20970Sstevel@tonic-gate if ((fcp->c_flags & FCFLG_WAITING) && 20980Sstevel@tonic-gate fcp->c_mtrstate[unit] == FMS_ON && 20990Sstevel@tonic-gate (csb->csb_xstate == FXS_MTRON || csb->csb_xstate == FXS_HDST || 21000Sstevel@tonic-gate csb->csb_xstate == FXS_DKCHGX)) 21010Sstevel@tonic-gate newxstate = fdc_statemach(fcp); 21020Sstevel@tonic-gate if (newxstate == -1) { 21030Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 21040Sstevel@tonic-gate (CE_WARN, 21050Sstevel@tonic-gate "fdc_motort unit %d: motor ready but bad xstate", 21060Sstevel@tonic-gate (int)fjp->fj_unit)); 21070Sstevel@tonic-gate fcp->c_csb.csb_cmdstat = EIO; 21080Sstevel@tonic-gate } 21090Sstevel@tonic-gate if (newxstate == -1 || newxstate == FXS_END) { 21100Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 21110Sstevel@tonic-gate cv_signal(&fcp->c_iocv); 21120Sstevel@tonic-gate } 21130Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 21140Sstevel@tonic-gate } 21150Sstevel@tonic-gate 21160Sstevel@tonic-gate /* 21170Sstevel@tonic-gate * DMA interrupt service routine 21180Sstevel@tonic-gate * 21190Sstevel@tonic-gate * Called by EISA dma interrupt service routine when buffer chaining 21200Sstevel@tonic-gate * is required. 21210Sstevel@tonic-gate */ 21220Sstevel@tonic-gate 21230Sstevel@tonic-gate ddi_dma_cookie_t * 21240Sstevel@tonic-gate fdc_dmae_isr(struct fdcntlr *fcp) 21250Sstevel@tonic-gate { 21260Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 21270Sstevel@tonic-gate off_t off; 21280Sstevel@tonic-gate size_t len; 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate if (csb->csb_dmahandle && !csb->csb_cmdstat) { 21310Sstevel@tonic-gate if (++csb->csb_dmacurrcookie < csb->csb_dmacookiecnt) { 21320Sstevel@tonic-gate ddi_dma_nextcookie(csb->csb_dmahandle, 21330Sstevel@tonic-gate &csb->csb_dmacookie); 21340Sstevel@tonic-gate return (&csb->csb_dmacookie); 21350Sstevel@tonic-gate } else if (++csb->csb_dmacurrwin < csb->csb_dmawincnt) { 21360Sstevel@tonic-gate if (ddi_dma_getwin(csb->csb_dmahandle, 21370Sstevel@tonic-gate csb->csb_dmacurrwin, &off, &len, 21380Sstevel@tonic-gate &csb->csb_dmacookie, 21390Sstevel@tonic-gate &csb->csb_dmacookiecnt) != DDI_SUCCESS) { 21400Sstevel@tonic-gate return (NULL); 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 21430Sstevel@tonic-gate return (&csb->csb_dmacookie); 21440Sstevel@tonic-gate } 21450Sstevel@tonic-gate } else 21460Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: unsolicited DMA interrupt\n"); 21470Sstevel@tonic-gate return (NULL); 21480Sstevel@tonic-gate } 21490Sstevel@tonic-gate 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate /* 21520Sstevel@tonic-gate * returns: 21530Sstevel@tonic-gate * 0 if all ok, 21540Sstevel@tonic-gate * ENXIO - diskette not in drive 21550Sstevel@tonic-gate * ETIMEDOUT - for immediate operations that timed out 21560Sstevel@tonic-gate * EBUSY - if stupid chip is locked busy??? 21570Sstevel@tonic-gate * ENOEXEC - for timeout during sending cmds to chip 21580Sstevel@tonic-gate * 21590Sstevel@tonic-gate * to sleep: set sleep 21600Sstevel@tonic-gate * to check for disk changed: set change 21610Sstevel@tonic-gate */ 21620Sstevel@tonic-gate static int 21630Sstevel@tonic-gate fdc_exec(struct fdcntlr *fcp, int sleep, int change) 21640Sstevel@tonic-gate { 21650Sstevel@tonic-gate struct ddi_dmae_req dmaereq; 21660Sstevel@tonic-gate struct fcu_obj *fjp; 21670Sstevel@tonic-gate struct fdcsb *csb; 21680Sstevel@tonic-gate off_t off; 21690Sstevel@tonic-gate size_t len; 21700Sstevel@tonic-gate int unit; 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 21730Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_EXEC, 21740Sstevel@tonic-gate (CE_CONT, "fdc_exec: sleep %x change %x\n", sleep, change)); 21750Sstevel@tonic-gate csb = &fcp->c_csb; 21760Sstevel@tonic-gate unit = csb->csb_drive; 21770Sstevel@tonic-gate fjp = fcp->c_unit[unit]; 21780Sstevel@tonic-gate 21790Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFINRPT) { 21800Sstevel@tonic-gate if (*csb->csb_cmd == FO_RECAL) 21810Sstevel@tonic-gate csb->csb_npcyl = 0; 21820Sstevel@tonic-gate else if ((*csb->csb_cmd & ~FO_MFM) != FO_FRMT) 21830Sstevel@tonic-gate csb->csb_npcyl = 21840Sstevel@tonic-gate csb->csb_cmd[2] * fjp->fj_chars->fdc_steps; 21850Sstevel@tonic-gate csb->csb_xstate = FXS_START; 21860Sstevel@tonic-gate } else 21870Sstevel@tonic-gate csb->csb_xstate = FXS_DOIT; 21880Sstevel@tonic-gate csb->csb_retrys = 0; 21890Sstevel@tonic-gate csb->csb_ourtrys = 0; 21900Sstevel@tonic-gate 21910Sstevel@tonic-gate if (csb->csb_dmahandle) { 21920Sstevel@tonic-gate /* ensure that entire format xfer is in one cookie */ 21930Sstevel@tonic-gate /* 21940Sstevel@tonic-gate * The change from ddi_dma_buf/addr_setup() to 21950Sstevel@tonic-gate * ddi_dma_buf/addr_bind_handle() has already loaded 21960Sstevel@tonic-gate * the first DMA window and cookie. 21970Sstevel@tonic-gate */ 21980Sstevel@tonic-gate if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT && 21990Sstevel@tonic-gate (4 * csb->csb_cmd[3]) != csb->csb_dmacookie.dmac_size) { 22000Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 22010Sstevel@tonic-gate return (EINVAL); 22020Sstevel@tonic-gate } 22030Sstevel@tonic-gate } 22040Sstevel@tonic-gate 22050Sstevel@tonic-gate retry: 22060Sstevel@tonic-gate if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) { 22070Sstevel@tonic-gate fcp->c_curunit = unit; 22080Sstevel@tonic-gate fjp->fj_flags |= FUNIT_CHAROK; 22090Sstevel@tonic-gate if (fjp->fj_chars->fdc_transfer_rate == 417) { 22100Sstevel@tonic-gate /* XXX hack for fdformat */ 22110Sstevel@tonic-gate /* fjp->fj_chars->fdc_transfer_rate == 500; */ 22120Sstevel@tonic-gate fjp->fj_attr->fda_rotatespd = 360; 22130Sstevel@tonic-gate } 22140Sstevel@tonic-gate if (fdcspecify(fcp, fjp->fj_chars->fdc_transfer_rate, 22150Sstevel@tonic-gate fjp->fj_drive->fdd_steprate, 40)) 22160Sstevel@tonic-gate cmn_err(CE_WARN, 22170Sstevel@tonic-gate "fdc_select: controller setup rejected " 22180Sstevel@tonic-gate "fdcntrl %p transfer rate %x step rate %x " 22190Sstevel@tonic-gate "head load time 40\n", (void*)fcp, 22200Sstevel@tonic-gate fjp->fj_chars->fdc_transfer_rate, 22210Sstevel@tonic-gate fjp->fj_drive->fdd_steprate); 22220Sstevel@tonic-gate 22230Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 22240Sstevel@tonic-gate if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) { 22250Sstevel@tonic-gate /* 3D drive requires 500 ms for speed change */ 22260Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5); 22270Sstevel@tonic-gate /* 22280Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 22290Sstevel@tonic-gate */ 22300Sstevel@tonic-gate } 22310Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 22320Sstevel@tonic-gate } 22330Sstevel@tonic-gate 22340Sstevel@tonic-gate /* 22350Sstevel@tonic-gate * If checking for disk_change is enabled 22360Sstevel@tonic-gate * (i.e. not seeking in fdresetchng), 22370Sstevel@tonic-gate * we sample the DSKCHG line to see if the diskette has wandered away. 22380Sstevel@tonic-gate */ 22390Sstevel@tonic-gate if (change && fdcsense_chng(fcp, unit)) { 22400Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 22410Sstevel@tonic-gate (CE_WARN, "diskette %d changed!!!", csb->csb_drive)); 22420Sstevel@tonic-gate fcp->c_unit[unit]->fj_flags |= FUNIT_CHANGED; 22430Sstevel@tonic-gate /* 22440Sstevel@tonic-gate * If the diskette is still gone... so are we, adios! 22450Sstevel@tonic-gate */ 22460Sstevel@tonic-gate if (fdcheckdisk(fcp, unit)) { 22470Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 22480Sstevel@tonic-gate 22490Sstevel@tonic-gate /* VP/ix expects an EBUSY return here */ 22500Sstevel@tonic-gate if (*csb->csb_cmd == FO_SDRV) { 22510Sstevel@tonic-gate return (EBUSY); 22520Sstevel@tonic-gate } 22530Sstevel@tonic-gate return (ENXIO); 22540Sstevel@tonic-gate } 22550Sstevel@tonic-gate /* 22560Sstevel@tonic-gate * delay to ensure that new diskette is up to speed 22570Sstevel@tonic-gate */ 22580Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 22590Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 22605295Srandyf fjp->fj_drive->fdd_motoron); 22610Sstevel@tonic-gate /* 22620Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 22630Sstevel@tonic-gate */ 22640Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 22650Sstevel@tonic-gate } 22660Sstevel@tonic-gate 22670Sstevel@tonic-gate /* 22680Sstevel@tonic-gate * gather some statistics 22690Sstevel@tonic-gate */ 22700Sstevel@tonic-gate switch (csb->csb_cmd[0] & 0x1f) { 22710Sstevel@tonic-gate case FO_RDDAT: 22720Sstevel@tonic-gate fcp->fdstats.rd++; 22730Sstevel@tonic-gate break; 22740Sstevel@tonic-gate case FO_WRDAT: 22750Sstevel@tonic-gate fcp->fdstats.wr++; 22760Sstevel@tonic-gate break; 22770Sstevel@tonic-gate case FO_RECAL: 22780Sstevel@tonic-gate fcp->fdstats.recal++; 22790Sstevel@tonic-gate break; 22800Sstevel@tonic-gate case FO_FRMT: 22810Sstevel@tonic-gate fcp->fdstats.form++; 22820Sstevel@tonic-gate break; 22830Sstevel@tonic-gate default: 22840Sstevel@tonic-gate fcp->fdstats.other++; 22850Sstevel@tonic-gate break; 22860Sstevel@tonic-gate } 22870Sstevel@tonic-gate 22880Sstevel@tonic-gate bzero(csb->csb_rslt, 10); 22890Sstevel@tonic-gate csb->csb_cmdstat = 0; 22900Sstevel@tonic-gate 22910Sstevel@tonic-gate if (csb->csb_dmahandle) { 22920Sstevel@tonic-gate bzero(&dmaereq, sizeof (struct ddi_dmae_req)); 22930Sstevel@tonic-gate dmaereq.der_command = (csb->csb_opflags & CSB_OFDMAWT) ? 22940Sstevel@tonic-gate DMAE_CMD_WRITE : DMAE_CMD_READ; 22950Sstevel@tonic-gate /* 22960Sstevel@tonic-gate * setup for dma buffer chaining regardless of bus capability 22970Sstevel@tonic-gate */ 22980Sstevel@tonic-gate dmaereq.der_bufprocess = DMAE_BUF_CHAIN; 22990Sstevel@tonic-gate dmaereq.proc = fdc_dmae_isr; 23000Sstevel@tonic-gate dmaereq.procparms = (void *)fcp; 23010Sstevel@tonic-gate if (ddi_dmae_prog(fcp->c_dip, &dmaereq, &csb->csb_dmacookie, 23020Sstevel@tonic-gate fcp->c_dmachan) != DDI_SUCCESS) 23030Sstevel@tonic-gate cmn_err(CE_WARN, "fdc_exec: dmae prog failed, " 23045295Srandyf "dip %p, dmachan %x\n", 23055295Srandyf (void*)fcp->c_dip, fcp->c_dmachan); 23060Sstevel@tonic-gate } 23070Sstevel@tonic-gate 23080Sstevel@tonic-gate if ((fdc_statemach(fcp) == FXS_DOWT) && !sleep) { 23090Sstevel@tonic-gate /* 23100Sstevel@tonic-gate * If the operation has no results - then just return 23110Sstevel@tonic-gate */ 23120Sstevel@tonic-gate if (!csb->csb_nrslts) { 23130Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23140Sstevel@tonic-gate return (0); 23150Sstevel@tonic-gate } 23160Sstevel@tonic-gate /* 23170Sstevel@tonic-gate * this operation has no interrupt and an immediate result 23180Sstevel@tonic-gate * so wait for the results and stuff them into the csb 23190Sstevel@tonic-gate */ 23200Sstevel@tonic-gate if (fdc_statemach(fcp) == -1) { 23210Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23220Sstevel@tonic-gate return (EIO); 23230Sstevel@tonic-gate } 23240Sstevel@tonic-gate } else { 23250Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 23260Sstevel@tonic-gate /* 23270Sstevel@tonic-gate * wait for completion interrupt 23280Sstevel@tonic-gate */ 23290Sstevel@tonic-gate while (fcp->c_flags & FCFLG_WAITING) { 23300Sstevel@tonic-gate cv_wait(&fcp->c_iocv, &fcp->c_lock); 23310Sstevel@tonic-gate } 23320Sstevel@tonic-gate } 23330Sstevel@tonic-gate 23340Sstevel@tonic-gate /* 23350Sstevel@tonic-gate * See if there was an error detected, if so, fdrecover() 23360Sstevel@tonic-gate * will check it out and say what to do. 23370Sstevel@tonic-gate * 23380Sstevel@tonic-gate * Don't do this, though, if this was the Sense Drive Status 23390Sstevel@tonic-gate * or the Dump Registers command. 23400Sstevel@tonic-gate */ 23410Sstevel@tonic-gate if (csb->csb_cmdstat && *csb->csb_cmd != FO_SDRV) { 23420Sstevel@tonic-gate /* if it can restarted OK, then do so, else return error */ 23430Sstevel@tonic-gate if (fdrecover(fcp)) { 23440Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23450Sstevel@tonic-gate return (EIO); 23460Sstevel@tonic-gate } 23470Sstevel@tonic-gate /* ASSUMES that cmd is still intact in csb */ 23480Sstevel@tonic-gate if (csb->csb_xstate == FXS_END) 23490Sstevel@tonic-gate csb->csb_xstate = FXS_START; 23500Sstevel@tonic-gate if (fdc_dma_attr.dma_attr_sgllen > 1 && csb->csb_dmahandle) { 23510Sstevel@tonic-gate /* 23520Sstevel@tonic-gate * restarted read/write operation requires 23530Sstevel@tonic-gate * first DMA cookie of current window 23540Sstevel@tonic-gate */ 23550Sstevel@tonic-gate if (ddi_dma_getwin(csb->csb_dmahandle, 23560Sstevel@tonic-gate csb->csb_dmacurrwin, &off, &len, 23570Sstevel@tonic-gate &csb->csb_dmacookie, 23580Sstevel@tonic-gate &csb->csb_dmacookiecnt) != DDI_SUCCESS) { 23590Sstevel@tonic-gate 23600Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23610Sstevel@tonic-gate return (EIO); 23620Sstevel@tonic-gate } 23630Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 23640Sstevel@tonic-gate } 23650Sstevel@tonic-gate goto retry; 23660Sstevel@tonic-gate } 23670Sstevel@tonic-gate /* things went ok */ 23680Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 23690Sstevel@tonic-gate return (0); 23700Sstevel@tonic-gate } 23710Sstevel@tonic-gate 23720Sstevel@tonic-gate /* 23730Sstevel@tonic-gate * fdcheckdisk 23740Sstevel@tonic-gate * called by fdc_exec to check if the disk is still there - do a seek 23750Sstevel@tonic-gate * then see if DSKCHG line went away; if so, diskette is in; else 23760Sstevel@tonic-gate * it's (still) out. 23770Sstevel@tonic-gate */ 23780Sstevel@tonic-gate int 23790Sstevel@tonic-gate fdcheckdisk(struct fdcntlr *fcp, int unit) 23800Sstevel@tonic-gate { 23810Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 23820Sstevel@tonic-gate int newcyl; /* where to seek for reset of DSKCHG */ 23830Sstevel@tonic-gate int rval; 23840Sstevel@tonic-gate enum fxstate save_xstate; 23850Sstevel@tonic-gate uchar_t save_cmd, save_cd1, save_npcyl; 23860Sstevel@tonic-gate 23870Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_lock)); 23880Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_CHEK, 23890Sstevel@tonic-gate (CE_CONT, "fdcheckdisk unit %d\n", unit)); 23900Sstevel@tonic-gate 23910Sstevel@tonic-gate if (fcp->c_curpcyl[unit]) 23920Sstevel@tonic-gate newcyl = fcp->c_curpcyl[unit] - 1; 23930Sstevel@tonic-gate else 23940Sstevel@tonic-gate newcyl = 1; 23950Sstevel@tonic-gate 23960Sstevel@tonic-gate save_cmd = *csb->csb_cmd; 23970Sstevel@tonic-gate save_cd1 = csb->csb_cmd[1]; 23980Sstevel@tonic-gate save_npcyl = csb->csb_npcyl; 23990Sstevel@tonic-gate save_xstate = csb->csb_xstate; 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate *csb->csb_cmd = FO_SEEK; 24020Sstevel@tonic-gate csb->csb_cmd[1] = (uchar_t)unit; 24030Sstevel@tonic-gate csb->csb_npcyl = (uchar_t)newcyl; 24040Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 24050Sstevel@tonic-gate 24060Sstevel@tonic-gate if (fcp->c_mtrstate[unit] != FMS_ON && fcp->c_motort[unit] != 0) 24070Sstevel@tonic-gate /* 24080Sstevel@tonic-gate * wait for motor to get up to speed, 24090Sstevel@tonic-gate * and let motor_timer issue seek cmd 24100Sstevel@tonic-gate */ 24110Sstevel@tonic-gate csb->csb_xstate = FXS_DKCHGX; 24120Sstevel@tonic-gate else { 24130Sstevel@tonic-gate /* 24140Sstevel@tonic-gate * motor is up to speed; issue seek cmd now 24150Sstevel@tonic-gate */ 24160Sstevel@tonic-gate csb->csb_xstate = FXS_SEEK; 24170Sstevel@tonic-gate if (rval = fdcseek(fcp, unit, newcyl)) { 24180Sstevel@tonic-gate /* 24190Sstevel@tonic-gate * any recal/seek errors are too serious to attend to 24200Sstevel@tonic-gate */ 24210Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_CHEK, 24220Sstevel@tonic-gate (CE_WARN, "fdcheckdisk err %d", rval)); 24230Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 24240Sstevel@tonic-gate } 24250Sstevel@tonic-gate } 24260Sstevel@tonic-gate /* 24270Sstevel@tonic-gate * wait for completion interrupt 24280Sstevel@tonic-gate * XXX This should be backed up with a watchdog timer! 24290Sstevel@tonic-gate */ 24300Sstevel@tonic-gate while (fcp->c_flags & FCFLG_WAITING) { 24310Sstevel@tonic-gate cv_wait(&fcp->c_iocv, &fcp->c_lock); 24320Sstevel@tonic-gate } 24330Sstevel@tonic-gate 24340Sstevel@tonic-gate /* 24350Sstevel@tonic-gate * if disk change still asserted, no diskette in drive! 24360Sstevel@tonic-gate */ 24370Sstevel@tonic-gate if (rval = fdcsense_chng(fcp, unit)) { 24380Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_CHEK, 24390Sstevel@tonic-gate (CE_WARN, "fdcheckdisk no disk %d", unit)); 24400Sstevel@tonic-gate } 24410Sstevel@tonic-gate 24420Sstevel@tonic-gate *csb->csb_cmd = save_cmd; 24430Sstevel@tonic-gate csb->csb_cmd[1] = save_cd1; 24440Sstevel@tonic-gate csb->csb_npcyl = save_npcyl; 24450Sstevel@tonic-gate csb->csb_xstate = save_xstate; 24460Sstevel@tonic-gate return (rval); 24470Sstevel@tonic-gate } 24480Sstevel@tonic-gate 24490Sstevel@tonic-gate static int 24500Sstevel@tonic-gate fdrecover(struct fdcntlr *fcp) 24510Sstevel@tonic-gate { 24520Sstevel@tonic-gate struct fcu_obj *fjp; 24530Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 24540Sstevel@tonic-gate int residual; 24550Sstevel@tonic-gate int unit; 24560Sstevel@tonic-gate char *failure; 24570Sstevel@tonic-gate 24580Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 24590Sstevel@tonic-gate (CE_NOTE, "fdrecover unit %d", csb->csb_drive)); 24600Sstevel@tonic-gate 24610Sstevel@tonic-gate unit = csb->csb_drive; 24620Sstevel@tonic-gate fjp = fcp->c_unit[unit]; 24630Sstevel@tonic-gate if (fcp->c_flags & FCFLG_TIMEOUT) { 24640Sstevel@tonic-gate fcp->c_flags ^= FCFLG_TIMEOUT; 24650Sstevel@tonic-gate csb->csb_rslt[1] |= 0x08; 24660Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_RECO, 24670Sstevel@tonic-gate (CE_WARN, "fd unit %d: %s timed out", csb->csb_drive, 24680Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname)); 24690Sstevel@tonic-gate } 24700Sstevel@tonic-gate 24710Sstevel@tonic-gate if (csb->csb_status & S0_SEKEND) 24720Sstevel@tonic-gate fcp->c_curpcyl[unit] = -1; 24730Sstevel@tonic-gate 24740Sstevel@tonic-gate switch (csb->csb_oldxs) { 24750Sstevel@tonic-gate case FXS_RCAL: /* recalibrate */ 24760Sstevel@tonic-gate case FXS_SEEK: /* seek */ 24770Sstevel@tonic-gate case FXS_RESET: /* cntlr reset */ 24780Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN, 24790Sstevel@tonic-gate "fd unit %d: %s error: st0=0x%x pcn=%d", csb->csb_drive, 24800Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, 24810Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1])); 24820Sstevel@tonic-gate if (csb->csb_retrys++ < skretry && 24830Sstevel@tonic-gate !(csb->csb_opflags & CSB_OFRAWIOCTL)) 24840Sstevel@tonic-gate return (0); 24850Sstevel@tonic-gate break; 24860Sstevel@tonic-gate 24870Sstevel@tonic-gate case FXS_RDID: /* read ID */ 24880Sstevel@tonic-gate if (!(csb->csb_status & S0_SEKEND)) 24890Sstevel@tonic-gate csb->csb_xstate = FXS_HDST; 24900Sstevel@tonic-gate /* FALLTHROUGH */ 24910Sstevel@tonic-gate case FXS_DOIT: /* original operation */ 24920Sstevel@tonic-gate case FXS_DOWT: /* waiting on operation */ 24930Sstevel@tonic-gate if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) { 24940Sstevel@tonic-gate if (ddi_dmae_getcnt(fcp->c_dip, fcp->c_dmachan, 24950Sstevel@tonic-gate &residual) != DDI_SUCCESS) 24960Sstevel@tonic-gate cmn_err(CE_WARN, 24970Sstevel@tonic-gate "fdc_recover: dmae getcnt failed, " 24980Sstevel@tonic-gate "dip %p dmachan %x residual %x\n", 24990Sstevel@tonic-gate (void*)fcp->c_dip, fcp->c_dmachan, 25000Sstevel@tonic-gate residual); 25010Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 25025295Srandyf (CE_NOTE, 25035295Srandyf "fd unit %d: %s error: " 25045295Srandyf "dma count=0x%lx residual=0x%x", 25050Sstevel@tonic-gate csb->csb_drive, 25060Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, 25070Sstevel@tonic-gate csb->csb_dmacookie.dmac_size, residual)); 25080Sstevel@tonic-gate } 25090Sstevel@tonic-gate if (csb->csb_rslt[1] == S1_OVRUN) 25100Sstevel@tonic-gate /* 25110Sstevel@tonic-gate * handle retries of over/underrun 25120Sstevel@tonic-gate * with a secondary retry counter 25130Sstevel@tonic-gate */ 25140Sstevel@tonic-gate if (++csb->csb_ourtrys <= OURUN_TRIES) { 25150Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 25165295Srandyf (CE_NOTE, 25175295Srandyf "fd unit %d: %s error: over/under-run", 25185295Srandyf csb->csb_drive, 25195295Srandyf fdcmds[*csb->csb_cmd & 0x1f].cmdname)); 25200Sstevel@tonic-gate return (0); 25210Sstevel@tonic-gate } else 25220Sstevel@tonic-gate /* 25230Sstevel@tonic-gate * count 1 set of over/underruns 25240Sstevel@tonic-gate * as 1 primary retry effort 25250Sstevel@tonic-gate */ 25260Sstevel@tonic-gate csb->csb_ourtrys = 0; 25270Sstevel@tonic-gate 25280Sstevel@tonic-gate if ((fjp->fj_flags & (FUNIT_UNLABELED | FUNIT_LABELOK)) && 25290Sstevel@tonic-gate !(csb->csb_opflags & CSB_OFRAWIOCTL)) { 25300Sstevel@tonic-gate /* 25310Sstevel@tonic-gate * device is open so keep trying and 25320Sstevel@tonic-gate * gather statistics on errors 25330Sstevel@tonic-gate */ 25340Sstevel@tonic-gate if (csb->csb_rslt[1] & S1_CRCER) 25350Sstevel@tonic-gate fcp->fdstats.de++; 25360Sstevel@tonic-gate if (csb->csb_rslt[1] & S1_OVRUN) 25370Sstevel@tonic-gate fcp->fdstats.run++; 25380Sstevel@tonic-gate if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK)) 25390Sstevel@tonic-gate fcp->fdstats.bfmt++; 25400Sstevel@tonic-gate if (csb->csb_rslt[1] & 0x08) 25410Sstevel@tonic-gate fcp->fdstats.to++; 25420Sstevel@tonic-gate 25430Sstevel@tonic-gate /* 25440Sstevel@tonic-gate * if we have not run out of retries, return 0 25450Sstevel@tonic-gate */ 25460Sstevel@tonic-gate if (csb->csb_retrys++ < csb->csb_maxretry && 25470Sstevel@tonic-gate (*csb->csb_cmd & ~FO_MFM) != FO_FRMT) { 25480Sstevel@tonic-gate if (csb->csb_opflags & 25490Sstevel@tonic-gate (CSB_OFDMARD | CSB_OFDMAWT)) { 25500Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_RECO, 25515295Srandyf (CE_WARN, 25525295Srandyf "fd unit %d: %s error: " 25535295Srandyf "st0=0x%x st1=0x%x st2=0x%x", 25540Sstevel@tonic-gate csb->csb_drive, 25555295Srandyf fdcmds[*csb->csb_cmd & 25565295Srandyf 0x1f].cmdname, 25570Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], 25580Sstevel@tonic-gate csb->csb_rslt[2])); 25590Sstevel@tonic-gate } 25600Sstevel@tonic-gate if ((csb->csb_retrys & 1) && 25610Sstevel@tonic-gate csb->csb_xstate == FXS_END) 25620Sstevel@tonic-gate csb->csb_xstate = FXS_DOIT; 25630Sstevel@tonic-gate else if (csb->csb_retrys == 3) 25640Sstevel@tonic-gate csb->csb_xstate = FXS_RESTART; 25650Sstevel@tonic-gate return (0); 25660Sstevel@tonic-gate } 25670Sstevel@tonic-gate if (csb->csb_rslt[1] & S1_CRCER) 25680Sstevel@tonic-gate failure = "crc error"; 25690Sstevel@tonic-gate else if (csb->csb_rslt[1] & S1_OVRUN) 25700Sstevel@tonic-gate failure = "over/under-run"; 25710Sstevel@tonic-gate else if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK)) 25720Sstevel@tonic-gate failure = "bad format"; 25730Sstevel@tonic-gate else if (csb->csb_rslt[1] & 0x08) 25740Sstevel@tonic-gate failure = "timeout"; 25750Sstevel@tonic-gate else 25760Sstevel@tonic-gate failure = "failed"; 25770Sstevel@tonic-gate cmn_err(CE_NOTE, "!fd unit %d: %s %s (%x %x %x)", 25780Sstevel@tonic-gate csb->csb_drive, 25790Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, failure, 25800Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2]); 25810Sstevel@tonic-gate } else { 25820Sstevel@tonic-gate FCERRPRINT(FDEP_L2, FDEM_RECO, 25830Sstevel@tonic-gate (CE_NOTE, "fd unit %d: %s failed (%x %x %x)", 25840Sstevel@tonic-gate csb->csb_drive, 25850Sstevel@tonic-gate fdcmds[*csb->csb_cmd & 0x1f].cmdname, 25860Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], 25870Sstevel@tonic-gate csb->csb_rslt[2])); 25880Sstevel@tonic-gate } 25890Sstevel@tonic-gate break; 25900Sstevel@tonic-gate 25910Sstevel@tonic-gate default: 25920Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN, 25930Sstevel@tonic-gate "fd unit %d: %s failed: st0=0x%x st1=0x%x st2=0x%x", 25940Sstevel@tonic-gate csb->csb_drive, fdcmds[*csb->csb_cmd & 0x1f].cmdname, 25950Sstevel@tonic-gate *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2])); 25960Sstevel@tonic-gate break; 25970Sstevel@tonic-gate } 25980Sstevel@tonic-gate return (1); 25990Sstevel@tonic-gate } 26000Sstevel@tonic-gate 26010Sstevel@tonic-gate 26020Sstevel@tonic-gate /* Autovector Interrupt Entry Point */ 26030Sstevel@tonic-gate /* ARGSUSED */ 26040Sstevel@tonic-gate static uint_t 26050Sstevel@tonic-gate fdc_intr(caddr_t arg) 26060Sstevel@tonic-gate { 26070Sstevel@tonic-gate struct fdcntlr *fcp = (struct fdcntlr *)arg; 26080Sstevel@tonic-gate struct fdcsb *csb; 26090Sstevel@tonic-gate off_t off; 26100Sstevel@tonic-gate size_t blklen; 26110Sstevel@tonic-gate int drive; 26120Sstevel@tonic-gate int newstate; 26130Sstevel@tonic-gate int pendstate; 26140Sstevel@tonic-gate int rval = DDI_DMA_DONE; 26150Sstevel@tonic-gate int state; 26160Sstevel@tonic-gate int maxspin = 10; 26170Sstevel@tonic-gate 26180Sstevel@tonic-gate csb = &fcp->c_csb; 26190Sstevel@tonic-gate 26200Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 26210Sstevel@tonic-gate /* 26220Sstevel@tonic-gate * Wait for the RQM bit to be set, or until we've tested it 26230Sstevel@tonic-gate * a bunch of times (which may imply this isn't our interrupt). 26240Sstevel@tonic-gate */ 26250Sstevel@tonic-gate state = inb(fcp->c_regbase + FCR_MSR); 26260Sstevel@tonic-gate pendstate = state & (MS_RQM | MS_DIO | MS_CB); 26270Sstevel@tonic-gate while (((pendstate & MS_RQM) == 0) && (maxspin-- > 0)) { 26280Sstevel@tonic-gate /* Small pause in between reading the status port */ 26290Sstevel@tonic-gate drv_usecwait(10); 26300Sstevel@tonic-gate /* Reread the status port */ 26310Sstevel@tonic-gate state = inb(fcp->c_regbase + FCR_MSR); 26320Sstevel@tonic-gate pendstate = state & (MS_RQM | MS_DIO | MS_CB); 26330Sstevel@tonic-gate } 26340Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_INTR, 26350Sstevel@tonic-gate (CE_CONT, "fdc_intr unit %d: xstate=%d MSR=0x%x\n", 26360Sstevel@tonic-gate csb->csb_drive, csb->csb_xstate, state)); 26370Sstevel@tonic-gate 26380Sstevel@tonic-gate /* 26390Sstevel@tonic-gate * If there is an operation outstanding AND the controller is ready 26400Sstevel@tonic-gate * to receive a command or send us the result of a command (OR if the 26410Sstevel@tonic-gate * controller is ready to accept a new command), AND if 26420Sstevel@tonic-gate * someone has been waiting for a command to finish AND (if no unit 26430Sstevel@tonic-gate * is BUSY OR if the unit that we're waiting for is BUSY (i.e. it's in 26440Sstevel@tonic-gate * the middle of a seek/recalibrate)) then this interrupt is for us. 26450Sstevel@tonic-gate */ 26460Sstevel@tonic-gate if ((pendstate == (MS_RQM | MS_DIO | MS_CB) || pendstate == MS_RQM) && 26470Sstevel@tonic-gate (fcp->c_flags & FCFLG_WAITING) && 26480Sstevel@tonic-gate (!(state & 0x0f) || ((1 << csb->csb_drive) & state))) { 26490Sstevel@tonic-gate /* 26500Sstevel@tonic-gate * Remove one of the conditions for entering this code. 26510Sstevel@tonic-gate * The state_machine will release the c_lock if it 26520Sstevel@tonic-gate * calls untimeout() 26530Sstevel@tonic-gate */ 26540Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 26550Sstevel@tonic-gate 26560Sstevel@tonic-gate if ((newstate = fdc_statemach(fcp)) == -1) { 26570Sstevel@tonic-gate /* restore waiting flag */ 26580Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 26590Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 26600Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 26610Sstevel@tonic-gate } 26620Sstevel@tonic-gate 26630Sstevel@tonic-gate if (fcp->c_intrstat) 26640Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 26650Sstevel@tonic-gate if (newstate == FXS_END) { 26660Sstevel@tonic-gate 26670Sstevel@tonic-gate if (csb->csb_dmahandle && !csb->csb_cmdstat && 26680Sstevel@tonic-gate /* 26690Sstevel@tonic-gate * read/write operation may have multiple DMA 26700Sstevel@tonic-gate * cookies: process next one 26710Sstevel@tonic-gate */ 26720Sstevel@tonic-gate ((csb->csb_dmacurrcookie < 26730Sstevel@tonic-gate (csb->csb_dmacookiecnt - 1)) || 26740Sstevel@tonic-gate (csb->csb_dmacurrwin) < (csb->csb_dmawincnt - 1))) { 26750Sstevel@tonic-gate /* 26760Sstevel@tonic-gate * read/write operation requires another 26770Sstevel@tonic-gate * DMA cookie: process next one 26780Sstevel@tonic-gate */ 26790Sstevel@tonic-gate 26800Sstevel@tonic-gate if (++csb->csb_dmacurrcookie < 26810Sstevel@tonic-gate csb->csb_dmacookiecnt) { 26820Sstevel@tonic-gate ddi_dma_nextcookie(csb->csb_dmahandle, 26830Sstevel@tonic-gate &csb->csb_dmacookie); 26840Sstevel@tonic-gate } else if (++csb->csb_dmacurrwin < 26850Sstevel@tonic-gate csb->csb_dmawincnt) { 26860Sstevel@tonic-gate if (ddi_dma_getwin(csb->csb_dmahandle, 26870Sstevel@tonic-gate csb->csb_dmacurrwin, &off, &blklen, 26880Sstevel@tonic-gate &csb->csb_dmacookie, 26890Sstevel@tonic-gate &csb->csb_dmacookiecnt) != 26900Sstevel@tonic-gate DDI_SUCCESS) { 26910Sstevel@tonic-gate cmn_err(CE_WARN, 26920Sstevel@tonic-gate "fdc_intr: " 26930Sstevel@tonic-gate "dma getwin failed\n"); 26940Sstevel@tonic-gate } 26950Sstevel@tonic-gate csb->csb_dmacurrcookie = 0; 26960Sstevel@tonic-gate } 26970Sstevel@tonic-gate 26980Sstevel@tonic-gate if (ddi_dmae_prog(fcp->c_dip, NULL, 26990Sstevel@tonic-gate &csb->csb_dmacookie, fcp->c_dmachan) != 27000Sstevel@tonic-gate DDI_SUCCESS) 27010Sstevel@tonic-gate cmn_err(CE_WARN, 27020Sstevel@tonic-gate "fdc_intr: dmae prog failed, " 27030Sstevel@tonic-gate "dip %p dmachannel %x\n", 27040Sstevel@tonic-gate (void*)fcp->c_dip, 27050Sstevel@tonic-gate fcp->c_dmachan); 27060Sstevel@tonic-gate 27070Sstevel@tonic-gate /* 27080Sstevel@tonic-gate * status of last operation has disk 27090Sstevel@tonic-gate * address for continuation 27100Sstevel@tonic-gate */ 27110Sstevel@tonic-gate csb->csb_cmd[2] = csb->csb_rslt[3]; 27120Sstevel@tonic-gate csb->csb_cmd[3] = csb->csb_rslt[4]; 27130Sstevel@tonic-gate csb->csb_cmd[4] = csb->csb_rslt[5]; 27140Sstevel@tonic-gate csb->csb_cmd[1] = (csb->csb_cmd[1] & ~0x04) | 27150Sstevel@tonic-gate (csb->csb_cmd[3] << 2); 27160Sstevel@tonic-gate 27170Sstevel@tonic-gate csb->csb_xstate = FXS_START; 27180Sstevel@tonic-gate (void) fdc_statemach(fcp); 27190Sstevel@tonic-gate /* 27200Sstevel@tonic-gate * Ignored return. If failed, warning already 27210Sstevel@tonic-gate * posted. Returned state irrelevant. 27220Sstevel@tonic-gate */ 27230Sstevel@tonic-gate /* restore waiting flag */ 27240Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 27250Sstevel@tonic-gate goto fi_exit; 27260Sstevel@tonic-gate } 27270Sstevel@tonic-gate if (rval != DDI_DMA_DONE) 27280Sstevel@tonic-gate csb->csb_cmdstat = EIO; 27290Sstevel@tonic-gate /* 27300Sstevel@tonic-gate * somebody's waiting for completion of fdcntlr/csb, 27310Sstevel@tonic-gate * wake them 27320Sstevel@tonic-gate */ 27330Sstevel@tonic-gate cv_signal(&fcp->c_iocv); 27340Sstevel@tonic-gate } 27350Sstevel@tonic-gate else 27360Sstevel@tonic-gate /* restore waiting flag */ 27370Sstevel@tonic-gate fcp->c_flags |= FCFLG_WAITING; 27380Sstevel@tonic-gate fi_exit: 27390Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 27400Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 27410Sstevel@tonic-gate } 27420Sstevel@tonic-gate 27430Sstevel@tonic-gate if (state & MS_RQM) { 27440Sstevel@tonic-gate (void) fdcsense_int(fcp, &drive, NULL); 27450Sstevel@tonic-gate /* 27460Sstevel@tonic-gate * Ignored return - senser state already saved 27470Sstevel@tonic-gate */ 27480Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_INTR, 27490Sstevel@tonic-gate (CE_WARN, "fdc_intr unit %d: nobody sleeping 0x%x", 27500Sstevel@tonic-gate drive, state)); 27510Sstevel@tonic-gate } else { 27520Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_INTR, 27530Sstevel@tonic-gate (CE_WARN, "fdc_intr: nobody sleeping on %d 0x%x", 27540Sstevel@tonic-gate csb->csb_drive, state)); 27550Sstevel@tonic-gate } 27560Sstevel@tonic-gate /* 27570Sstevel@tonic-gate * This should probably be protected, but, what the 27580Sstevel@tonic-gate * heck...the cost isn't worth the accuracy for this 27590Sstevel@tonic-gate * statistic. 27600Sstevel@tonic-gate */ 27610Sstevel@tonic-gate if (fcp->c_intrstat) 27620Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 27630Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 27640Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 27650Sstevel@tonic-gate } 27660Sstevel@tonic-gate 27670Sstevel@tonic-gate /* 27680Sstevel@tonic-gate * fdwatch 27690Sstevel@tonic-gate * is called from timeout() when a floppy operation timer has expired. 27700Sstevel@tonic-gate */ 27710Sstevel@tonic-gate static void 27720Sstevel@tonic-gate fdwatch(void *arg) 27730Sstevel@tonic-gate { 27740Sstevel@tonic-gate struct fdcntlr *fcp = (struct fdcntlr *)arg; 27750Sstevel@tonic-gate struct fdcsb *csb; 27760Sstevel@tonic-gate 27770Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 27780Sstevel@tonic-gate 27790Sstevel@tonic-gate if (fcp->c_timeid == 0) { 27800Sstevel@tonic-gate /* 27810Sstevel@tonic-gate * fdc_intr got here first, ergo, no timeout condition.. 27820Sstevel@tonic-gate */ 27830Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 27840Sstevel@tonic-gate return; 27850Sstevel@tonic-gate } 27860Sstevel@tonic-gate 27870Sstevel@tonic-gate if (fcp->c_flags & FCFLG_WAITING) { 27880Sstevel@tonic-gate if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS) 27890Sstevel@tonic-gate cmn_err(CE_WARN, "fdwatch: dmae stop failed, " 27905295Srandyf "dip %p, dmachan %x\n", 27915295Srandyf (void*)fcp->c_dip, fcp->c_dmachan); 27920Sstevel@tonic-gate csb = &fcp->c_csb; 27930Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_WATC, 27940Sstevel@tonic-gate (CE_WARN, "fdcwatch unit %d: xstate = %d", 27950Sstevel@tonic-gate csb->csb_drive, csb->csb_xstate)); 27960Sstevel@tonic-gate drv_usecwait(50); 27970Sstevel@tonic-gate 27980Sstevel@tonic-gate if (inb(fcp->c_regbase + FCR_MSR) != MS_RQM) { 27990Sstevel@tonic-gate /* 28000Sstevel@tonic-gate * cntlr is still busy, so reset it 28010Sstevel@tonic-gate */ 28020Sstevel@tonic-gate csb->csb_xstate = FXS_KILL; 28030Sstevel@tonic-gate (void) fdc_statemach(fcp); 28040Sstevel@tonic-gate /* 28050Sstevel@tonic-gate * Ignored return. If failed, warning already 28060Sstevel@tonic-gate * posted. Returned state irrelevant. 28070Sstevel@tonic-gate */ 28080Sstevel@tonic-gate } else { 28090Sstevel@tonic-gate csb->csb_xstate = FXS_END; 28100Sstevel@tonic-gate fcp->c_timeid = 0; 28110Sstevel@tonic-gate fcp->c_flags ^= FCFLG_WAITING; 28120Sstevel@tonic-gate cv_signal(&fcp->c_iocv); 28130Sstevel@tonic-gate } 28140Sstevel@tonic-gate csb->csb_cmdstat = EIO; 28150Sstevel@tonic-gate fcp->c_flags |= FCFLG_TIMEOUT; 28160Sstevel@tonic-gate } else { 28170Sstevel@tonic-gate FCERRPRINT(FDEP_L4, FDEM_INTR, 28180Sstevel@tonic-gate (CE_WARN, "fdcwatch: not sleeping for unit %d", 28190Sstevel@tonic-gate fcp->c_csb.csb_drive)); 28200Sstevel@tonic-gate } 28210Sstevel@tonic-gate if (fcp->c_intrstat) 28220Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_WATCHDOG]++; 28230Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 28240Sstevel@tonic-gate } 28250Sstevel@tonic-gate 28260Sstevel@tonic-gate 28270Sstevel@tonic-gate static int 28280Sstevel@tonic-gate fdc_statemach(struct fdcntlr *fcp) 28290Sstevel@tonic-gate { 28300Sstevel@tonic-gate struct fcu_obj *fjp; 28310Sstevel@tonic-gate struct fdcsb *csb = &fcp->c_csb; 28320Sstevel@tonic-gate int backoff; 28330Sstevel@tonic-gate clock_t time; 28340Sstevel@tonic-gate int unit; 28350Sstevel@tonic-gate 28360Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fcp->c_lock)); 28370Sstevel@tonic-gate 28380Sstevel@tonic-gate unit = csb->csb_drive; 28390Sstevel@tonic-gate fjp = fcp->c_unit[unit]; 28400Sstevel@tonic-gate 28410Sstevel@tonic-gate csb->csb_oldxs = csb->csb_xstate; 28420Sstevel@tonic-gate switch (csb->csb_xstate) { 28430Sstevel@tonic-gate 28440Sstevel@tonic-gate case FXS_START: /* start of operation */ 28450Sstevel@tonic-gate ASSERT(fcp->c_timeid == 0); 28460Sstevel@tonic-gate time = drv_usectohz(100000 * (unsigned int)csb->csb_timer); 28470Sstevel@tonic-gate if (time == 0) 28480Sstevel@tonic-gate time = drv_usectohz(2000000); 28490Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 28500Sstevel@tonic-gate 28510Sstevel@tonic-gate if (fcp->c_mtrstate[unit] == FMS_START) { 28520Sstevel@tonic-gate /* 28530Sstevel@tonic-gate * wait for motor to get up to speed 28540Sstevel@tonic-gate */ 28550Sstevel@tonic-gate csb->csb_xstate = FXS_MTRON; 28560Sstevel@tonic-gate break; 28570Sstevel@tonic-gate } 28580Sstevel@tonic-gate /* FALLTHROUGH */ 28590Sstevel@tonic-gate 28600Sstevel@tonic-gate case FXS_MTRON: /* motor is at speed */ 28610Sstevel@tonic-gate if (fcp->c_mtrstate[unit] != FMS_ON) { 28620Sstevel@tonic-gate /* how did we get here ?? */ 28630Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: selected but motor off"); 28640Sstevel@tonic-gate return (-1); 28650Sstevel@tonic-gate } 28660Sstevel@tonic-gate if (fcp->c_curpcyl[unit] != -1 && *csb->csb_cmd != FO_RECAL) 28670Sstevel@tonic-gate goto nxs_seek; 28680Sstevel@tonic-gate recalcmd[1] = (uchar_t)unit; 28690Sstevel@tonic-gate if (fdc_docmd(fcp, recalcmd, 2) == -1) { 28700Sstevel@tonic-gate /* cntlr did not accept command bytes */ 28710Sstevel@tonic-gate fdcquiesce(fcp); 28720Sstevel@tonic-gate csb->csb_cmdstat = EIO; 28730Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 28740Sstevel@tonic-gate break; 28750Sstevel@tonic-gate } 28760Sstevel@tonic-gate fcp->c_sekdir[unit] = 0; 28770Sstevel@tonic-gate csb->csb_xstate = FXS_RCAL; 28780Sstevel@tonic-gate break; 28790Sstevel@tonic-gate 28800Sstevel@tonic-gate case FXS_RCAL: /* forced recalibrate is complete */ 28810Sstevel@tonic-gate #if 0 /* #ifdef _VPIX */ 28820Sstevel@tonic-gate /* WARNING: this code breaks SPARC compatibility */ 28830Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFRAWIOCTL && 28840Sstevel@tonic-gate *csb->csb_cmd == FO_RECAL) { 28850Sstevel@tonic-gate fcp->c_curpcyl[unit] = 0; 28860Sstevel@tonic-gate csb->csb_status = 0; 28870Sstevel@tonic-gate goto nxs_cmpl; 28880Sstevel@tonic-gate } 28890Sstevel@tonic-gate #endif 28900Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 28910Sstevel@tonic-gate /* 28920Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 28930Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 28940Sstevel@tonic-gate */ 28950Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 2); 28960Sstevel@tonic-gate /* 28970Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 28980Sstevel@tonic-gate * Actual results checked below 28990Sstevel@tonic-gate */ 29000Sstevel@tonic-gate if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 29010Sstevel@tonic-gate (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) { 29020Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 29030Sstevel@tonic-gate (CE_WARN, "fdc_statemach unit %d: recal result %x", 29040Sstevel@tonic-gate csb->csb_drive, *csb->csb_rslt)); 29050Sstevel@tonic-gate fdcquiesce(fcp); 29060Sstevel@tonic-gate csb->csb_cmdstat = EIO; 29070Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 29080Sstevel@tonic-gate break; 29090Sstevel@tonic-gate } 29100Sstevel@tonic-gate if (unit != (*csb->csb_rslt & 3) || csb->csb_rslt[1]) { 29110Sstevel@tonic-gate csb->csb_status = S0_SEKEND; 29120Sstevel@tonic-gate goto nxs_cmpl; 29130Sstevel@tonic-gate } 29140Sstevel@tonic-gate fcp->c_curpcyl[unit] = csb->csb_rslt[1]; 29150Sstevel@tonic-gate if (*csb->csb_cmd == FO_RECAL) 29160Sstevel@tonic-gate goto nxs_cmpl; 29170Sstevel@tonic-gate nxs_seek: 29180Sstevel@tonic-gate if (*csb->csb_cmd != FO_SEEK && 29190Sstevel@tonic-gate csb->csb_npcyl == fcp->c_curpcyl[unit]) 29200Sstevel@tonic-gate goto nxs_doit; 29210Sstevel@tonic-gate fcp->c_sekdir[unit] = csb->csb_npcyl - fcp->c_curpcyl[unit]; 29220Sstevel@tonic-gate /* FALLTHROUGH */ 29230Sstevel@tonic-gate 29240Sstevel@tonic-gate case FXS_DKCHGX: /* reset Disk-Change latch */ 29250Sstevel@tonic-gate (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl); 29260Sstevel@tonic-gate /* 29270Sstevel@tonic-gate * Ignored return. If command rejected, warnig already posted 29280Sstevel@tonic-gate * by fdc_docmd(). 29290Sstevel@tonic-gate */ 29300Sstevel@tonic-gate csb->csb_xstate = FXS_SEEK; 29310Sstevel@tonic-gate break; 29320Sstevel@tonic-gate 29330Sstevel@tonic-gate case FXS_RESTART: /* special restart of read/write operation */ 29340Sstevel@tonic-gate ASSERT(fcp->c_timeid == 0); 29350Sstevel@tonic-gate time = drv_usectohz(100000 * csb->csb_timer); 29360Sstevel@tonic-gate if (time == 0) 29370Sstevel@tonic-gate time = drv_usectohz(2000000); 29380Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 29390Sstevel@tonic-gate 29400Sstevel@tonic-gate if (fcp->c_mtrstate[unit] != FMS_ON) { 29410Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: selected but motor off"); 29420Sstevel@tonic-gate return (-1); 29430Sstevel@tonic-gate } 29440Sstevel@tonic-gate if ((csb->csb_npcyl == 0 || fcp->c_sekdir[unit] >= 0) && 29450Sstevel@tonic-gate (int)csb->csb_cmd[2] < (fjp->fj_chars->fdc_ncyl - 1)) 29460Sstevel@tonic-gate backoff = csb->csb_npcyl + 1; 29470Sstevel@tonic-gate else 29480Sstevel@tonic-gate backoff = csb->csb_npcyl - 1; 29490Sstevel@tonic-gate (void) fdcseek(fcp, csb->csb_cmd[1], backoff); 29500Sstevel@tonic-gate /* 29510Sstevel@tonic-gate * Ignored return. If command rejected, warnig already posted 29520Sstevel@tonic-gate * by fdc_docmd(). 29530Sstevel@tonic-gate */ 29540Sstevel@tonic-gate csb->csb_xstate = FXS_RESEEK; 29550Sstevel@tonic-gate break; 29560Sstevel@tonic-gate 29570Sstevel@tonic-gate case FXS_RESEEK: /* seek to backoff-cyl complete */ 29580Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 29590Sstevel@tonic-gate /* 29600Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 29610Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 29620Sstevel@tonic-gate */ 29630Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 2); 29640Sstevel@tonic-gate /* 29650Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 29660Sstevel@tonic-gate * Actual results checked below 29670Sstevel@tonic-gate */ 29680Sstevel@tonic-gate if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 29690Sstevel@tonic-gate (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) 29700Sstevel@tonic-gate goto nxs_cmpl; 29710Sstevel@tonic-gate (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl); 29720Sstevel@tonic-gate /* 29730Sstevel@tonic-gate * Ignored return. If command rejected, warnig already posted 29740Sstevel@tonic-gate * by fdc_docmd(). 29750Sstevel@tonic-gate */ 29760Sstevel@tonic-gate csb->csb_xstate = FXS_SEEK; 29770Sstevel@tonic-gate break; 29780Sstevel@tonic-gate 29790Sstevel@tonic-gate case FXS_SEEK: /* seek complete */ 29800Sstevel@tonic-gate #if 0 /* #ifdef _VPIX */ 29810Sstevel@tonic-gate /* WARNING: this code breaks SPARC compatibility and */ 29820Sstevel@tonic-gate /* rawioctls in fdformat */ 29830Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFRAWIOCTL) { 29840Sstevel@tonic-gate fcp->c_curpcyl[unit] = csb->csb_npcyl; 29850Sstevel@tonic-gate csb->csb_status = 0; 29860Sstevel@tonic-gate goto nxs_cmpl; 29870Sstevel@tonic-gate } 29880Sstevel@tonic-gate #endif 29890Sstevel@tonic-gate (void) fdc_docmd(fcp, &senseintcmd, 1); 29900Sstevel@tonic-gate /* 29910Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_docmd. 29920Sstevel@tonic-gate * fdc_results retrieves the controller/drive status 29930Sstevel@tonic-gate */ 29940Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 2); 29950Sstevel@tonic-gate /* 29960Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 29970Sstevel@tonic-gate * Actual results checked below 29980Sstevel@tonic-gate */ 29990Sstevel@tonic-gate if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) & 30000Sstevel@tonic-gate (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) 30010Sstevel@tonic-gate goto nxs_cmpl; 30020Sstevel@tonic-gate if (unit != (*csb->csb_rslt & 3) || 30030Sstevel@tonic-gate csb->csb_rslt[1] != csb->csb_npcyl) { 30040Sstevel@tonic-gate csb->csb_status = S0_SEKEND; 30050Sstevel@tonic-gate goto nxs_cmpl; 30060Sstevel@tonic-gate }; 30070Sstevel@tonic-gate fcp->c_curpcyl[unit] = csb->csb_rslt[1]; 30080Sstevel@tonic-gate /* use motor_timer to delay for head settle */ 30090Sstevel@tonic-gate mutex_enter(&fcp->c_dorlock); 30100Sstevel@tonic-gate (void) fdc_motorsm(fjp, FMI_DELAYCMD, 30110Sstevel@tonic-gate fjp->fj_drive->fdd_headsettle / 1000); 30120Sstevel@tonic-gate /* 30130Sstevel@tonic-gate * Return value ignored - fdcmotort deals with failure. 30140Sstevel@tonic-gate */ 30150Sstevel@tonic-gate mutex_exit(&fcp->c_dorlock); 30160Sstevel@tonic-gate csb->csb_xstate = FXS_HDST; 30170Sstevel@tonic-gate break; 30180Sstevel@tonic-gate 30190Sstevel@tonic-gate case FXS_HDST: /* head settle */ 30200Sstevel@tonic-gate if (*csb->csb_cmd == FO_SEEK) 30210Sstevel@tonic-gate goto nxs_cmpl; 30220Sstevel@tonic-gate if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT) 30230Sstevel@tonic-gate goto nxs_doit; 30240Sstevel@tonic-gate fdcreadid(fcp, csb); 30250Sstevel@tonic-gate csb->csb_xstate = FXS_RDID; 30260Sstevel@tonic-gate break; 30270Sstevel@tonic-gate 30280Sstevel@tonic-gate case FXS_RDID: /* read ID complete */ 30290Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, 7); 30300Sstevel@tonic-gate /* 30310Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 30320Sstevel@tonic-gate * Actual results checked below 30330Sstevel@tonic-gate */ 30340Sstevel@tonic-gate if ((csb->csb_status = (*csb->csb_rslt & 30350Sstevel@tonic-gate (S0_ICMASK | S0_ECHK | S0_NOTRDY))) != 0) 30360Sstevel@tonic-gate goto nxs_cmpl; 30370Sstevel@tonic-gate if (csb->csb_cmd[2] != csb->csb_rslt[3]) { 30380Sstevel@tonic-gate /* at wrong logical cylinder */ 30390Sstevel@tonic-gate csb->csb_status = S0_SEKEND; 30400Sstevel@tonic-gate goto nxs_cmpl; 30410Sstevel@tonic-gate }; 30420Sstevel@tonic-gate goto nxs_doit; 30430Sstevel@tonic-gate 30440Sstevel@tonic-gate case FXS_DOIT: /* do original operation */ 30450Sstevel@tonic-gate ASSERT(fcp->c_timeid == 0); 30460Sstevel@tonic-gate time = drv_usectohz(100000 * csb->csb_timer); 30470Sstevel@tonic-gate if (time == 0) 30480Sstevel@tonic-gate time = drv_usectohz(2000000); 30490Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, time); 30500Sstevel@tonic-gate nxs_doit: 30510Sstevel@tonic-gate if (fdc_docmd(fcp, csb->csb_cmd, csb->csb_ncmds) == -1) { 30520Sstevel@tonic-gate /* cntlr did not accept command bytes */ 30530Sstevel@tonic-gate fdcquiesce(fcp); 30540Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 30550Sstevel@tonic-gate csb->csb_cmdstat = EIO; 30560Sstevel@tonic-gate break; 30570Sstevel@tonic-gate } 30580Sstevel@tonic-gate csb->csb_xstate = FXS_DOWT; 30590Sstevel@tonic-gate break; 30600Sstevel@tonic-gate 30610Sstevel@tonic-gate case FXS_DOWT: /* operation complete */ 30620Sstevel@tonic-gate (void) fdc_result(fcp, csb->csb_rslt, csb->csb_nrslts); 30630Sstevel@tonic-gate /* 30640Sstevel@tonic-gate * Ignored return. If failed, warning was issued by fdc_result. 30650Sstevel@tonic-gate * Actual results checked below. 30660Sstevel@tonic-gate */ 30670Sstevel@tonic-gate if (*csb->csb_cmd == FO_SDRV) { 30680Sstevel@tonic-gate csb->csb_status = 30690Sstevel@tonic-gate (*csb->csb_rslt ^ (S3_DRRDY | S3_2SIDE)) & 30700Sstevel@tonic-gate ~(S3_HEAD | S3_UNIT); 30710Sstevel@tonic-gate } else { 30720Sstevel@tonic-gate csb->csb_status = *csb->csb_rslt & 30730Sstevel@tonic-gate (S0_ICMASK | S0_ECHK | S0_NOTRDY); 30740Sstevel@tonic-gate } 30750Sstevel@tonic-gate nxs_cmpl: 30760Sstevel@tonic-gate if (csb->csb_status) 30770Sstevel@tonic-gate csb->csb_cmdstat = EIO; 30780Sstevel@tonic-gate csb->csb_xstate = FXS_END; 30790Sstevel@tonic-gate 30800Sstevel@tonic-gate /* remove watchdog timer if armed and not already triggered */ 30810Sstevel@tonic-gate if (fcp->c_timeid != 0) { 30820Sstevel@tonic-gate timeout_id_t timeid; 30830Sstevel@tonic-gate timeid = fcp->c_timeid; 30840Sstevel@tonic-gate fcp->c_timeid = 0; 30850Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 30860Sstevel@tonic-gate (void) untimeout(timeid); 30870Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 30880Sstevel@tonic-gate } 30890Sstevel@tonic-gate break; 30900Sstevel@tonic-gate 30910Sstevel@tonic-gate case FXS_KILL: /* quiesce cntlr by reset */ 30920Sstevel@tonic-gate fdcquiesce(fcp); 30930Sstevel@tonic-gate fcp->c_timeid = timeout(fdwatch, (void *)fcp, 30940Sstevel@tonic-gate drv_usectohz(2000000)); 30950Sstevel@tonic-gate csb->csb_xstate = FXS_RESET; 30960Sstevel@tonic-gate break; 30970Sstevel@tonic-gate 30980Sstevel@tonic-gate case FXS_RESET: /* int from reset */ 30990Sstevel@tonic-gate for (unit = 0; unit < NFDUN; unit++) { 31000Sstevel@tonic-gate (void) fdcsense_int(fcp, NULL, NULL); 31010Sstevel@tonic-gate fcp->c_curpcyl[unit] = -1; 31020Sstevel@tonic-gate } 31030Sstevel@tonic-gate if (fcp->c_timeid != 0) { 31040Sstevel@tonic-gate timeout_id_t timeid; 31050Sstevel@tonic-gate timeid = fcp->c_timeid; 31060Sstevel@tonic-gate fcp->c_timeid = 0; 31070Sstevel@tonic-gate mutex_exit(&fcp->c_lock); 31080Sstevel@tonic-gate (void) untimeout(timeid); 31090Sstevel@tonic-gate mutex_enter(&fcp->c_lock); 31100Sstevel@tonic-gate } 31110Sstevel@tonic-gate csb->csb_xstate = FXS_END; 31120Sstevel@tonic-gate break; 31130Sstevel@tonic-gate 31140Sstevel@tonic-gate default: 31150Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: statemach, unknown state"); 31160Sstevel@tonic-gate return (-1); 31170Sstevel@tonic-gate } 31180Sstevel@tonic-gate FCERRPRINT(FDEP_L1, FDEM_EXEC, 31190Sstevel@tonic-gate (CE_CONT, "fdc_statemach unit %d: %d -> %d\n", 31200Sstevel@tonic-gate csb->csb_drive, csb->csb_oldxs, csb->csb_xstate)); 31210Sstevel@tonic-gate return (csb->csb_xstate); 31220Sstevel@tonic-gate } 31230Sstevel@tonic-gate 31240Sstevel@tonic-gate 31250Sstevel@tonic-gate /* 31260Sstevel@tonic-gate * routine to program a command into the floppy disk controller. 31270Sstevel@tonic-gate */ 31280Sstevel@tonic-gate int 31290Sstevel@tonic-gate fdc_docmd(struct fdcntlr *fcp, uchar_t *oplistp, uchar_t count) 31300Sstevel@tonic-gate { 31310Sstevel@tonic-gate int ntries; 31320Sstevel@tonic-gate 31330Sstevel@tonic-gate ASSERT(count >= 1); 31340Sstevel@tonic-gate FCERRPRINT(FDEP_L0, FDEM_EXEC, 31350Sstevel@tonic-gate (CE_CONT, "fdc_docmd: %x %x %x %x %x %x %x %x %x\n", 31360Sstevel@tonic-gate oplistp[0], oplistp[1], oplistp[2], oplistp[3], oplistp[4], 31370Sstevel@tonic-gate oplistp[5], oplistp[6], oplistp[7], oplistp[8])); 31380Sstevel@tonic-gate 31390Sstevel@tonic-gate do { 31400Sstevel@tonic-gate ntries = FDC_RQM_RETRY; 31410Sstevel@tonic-gate do { 31420Sstevel@tonic-gate if ((inb(fcp->c_regbase + FCR_MSR) & (MS_RQM|MS_DIO)) 31430Sstevel@tonic-gate == MS_RQM) 31440Sstevel@tonic-gate break; 31450Sstevel@tonic-gate else 31460Sstevel@tonic-gate drv_usecwait(1); 31470Sstevel@tonic-gate } while (--ntries); 31480Sstevel@tonic-gate if (ntries == 0) { 31490Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 31500Sstevel@tonic-gate (CE_WARN, "fdc_docmd: ctlr not ready")); 31510Sstevel@tonic-gate return (-1); 31520Sstevel@tonic-gate } 31530Sstevel@tonic-gate outb(fcp->c_regbase + FCR_DATA, *oplistp++); 31540Sstevel@tonic-gate drv_usecwait(16); /* See comment in fdc_result() */ 31550Sstevel@tonic-gate } while (--count); 31560Sstevel@tonic-gate return (0); 31570Sstevel@tonic-gate } 31580Sstevel@tonic-gate 31590Sstevel@tonic-gate 31600Sstevel@tonic-gate /* 31610Sstevel@tonic-gate * Routine to return controller/drive status information. 31620Sstevel@tonic-gate * The diskette-controller data-register is read the 31630Sstevel@tonic-gate * requested number of times and the results are placed in 31640Sstevel@tonic-gate * consecutive memory locations starting at the passed 31650Sstevel@tonic-gate * address. 31660Sstevel@tonic-gate */ 31670Sstevel@tonic-gate int 31680Sstevel@tonic-gate fdc_result(struct fdcntlr *fcp, uchar_t *rsltp, uchar_t rcount) 31690Sstevel@tonic-gate { 31700Sstevel@tonic-gate int ntries; 31710Sstevel@tonic-gate uchar_t *abresultp = rsltp; 31720Sstevel@tonic-gate uchar_t stat; 31730Sstevel@tonic-gate int laxative = 7; 31740Sstevel@tonic-gate 31750Sstevel@tonic-gate ntries = 10 * FDC_RQM_RETRY; 31760Sstevel@tonic-gate do { 31770Sstevel@tonic-gate do { 31780Sstevel@tonic-gate if ((inb(fcp->c_regbase + FCR_MSR) & 31790Sstevel@tonic-gate (MS_RQM | MS_DIO)) == (MS_RQM | MS_DIO)) 31800Sstevel@tonic-gate break; 31810Sstevel@tonic-gate else 31820Sstevel@tonic-gate drv_usecwait(10); 31830Sstevel@tonic-gate } while (--ntries); 31840Sstevel@tonic-gate if (!ntries) { 31850Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 31860Sstevel@tonic-gate (CE_WARN, "fdc_result: ctlr not ready")); 31870Sstevel@tonic-gate return (-2); 31880Sstevel@tonic-gate } 31890Sstevel@tonic-gate *rsltp++ = inb(fcp->c_regbase + FCR_DATA); 31900Sstevel@tonic-gate 31910Sstevel@tonic-gate /* 31920Sstevel@tonic-gate * The PRM suggests waiting for 14.5 us. 31930Sstevel@tonic-gate * Adding a bit more to cover the case of bad calibration 31940Sstevel@tonic-gate * of drv_usecwait(). 31950Sstevel@tonic-gate */ 31960Sstevel@tonic-gate drv_usecwait(16); 31970Sstevel@tonic-gate ntries = FDC_RQM_RETRY; 31980Sstevel@tonic-gate } while (--rcount); 31990Sstevel@tonic-gate while ((inb(fcp->c_regbase + FCR_MSR) & MS_CB) && laxative--) { 32000Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 32010Sstevel@tonic-gate (CE_WARN, "fdc_result: ctlr still busy")); 32020Sstevel@tonic-gate /* 32030Sstevel@tonic-gate * try to complete Result phase by purging 32040Sstevel@tonic-gate * result bytes queued for reading 32050Sstevel@tonic-gate */ 32060Sstevel@tonic-gate *abresultp = S0_IVCMD; 32070Sstevel@tonic-gate do { 32080Sstevel@tonic-gate stat = inb(fcp->c_regbase + FCR_MSR) & 32090Sstevel@tonic-gate (MS_RQM | MS_DIO); 32100Sstevel@tonic-gate if (stat == MS_RQM) { 32110Sstevel@tonic-gate /* 32120Sstevel@tonic-gate * Result phase is complete 32130Sstevel@tonic-gate * but did we get the results corresponding to 32140Sstevel@tonic-gate * the command we think we executed? 32150Sstevel@tonic-gate */ 32160Sstevel@tonic-gate return (-1); 32170Sstevel@tonic-gate } 32180Sstevel@tonic-gate if (stat == (MS_RQM | MS_DIO)) 32190Sstevel@tonic-gate break; 32200Sstevel@tonic-gate else 32210Sstevel@tonic-gate drv_usecwait(10); 32220Sstevel@tonic-gate } while (--ntries); 32230Sstevel@tonic-gate if (!ntries || !laxative) { 32240Sstevel@tonic-gate FCERRPRINT(FDEP_L3, FDEM_EXEC, 32250Sstevel@tonic-gate (CE_WARN, 32260Sstevel@tonic-gate "fdc_result: ctlr still busy and not ready")); 32270Sstevel@tonic-gate return (-3); 32280Sstevel@tonic-gate } 32290Sstevel@tonic-gate (void) inb(fcp->c_regbase + FCR_DATA); 32300Sstevel@tonic-gate 32310Sstevel@tonic-gate drv_usecwait(16); /* See comment above */ 32320Sstevel@tonic-gate ntries = FDC_RQM_RETRY; 32330Sstevel@tonic-gate } 32340Sstevel@tonic-gate return (0); 32350Sstevel@tonic-gate } 32360Sstevel@tonic-gate 32370Sstevel@tonic-gate /* 32380Sstevel@tonic-gate * Function: get_unit() 32390Sstevel@tonic-gate * 32400Sstevel@tonic-gate * Assumptions: ioaddr is either 0x3f0 or 0x370 32410Sstevel@tonic-gate */ 32420Sstevel@tonic-gate static int 32430Sstevel@tonic-gate get_unit(dev_info_t *dip, int *cntrl_num) 32440Sstevel@tonic-gate { 32450Sstevel@tonic-gate int ioaddr; 32460Sstevel@tonic-gate 32470Sstevel@tonic-gate if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS) 32480Sstevel@tonic-gate return (DDI_FAILURE); 32490Sstevel@tonic-gate 32500Sstevel@tonic-gate switch (ioaddr) { 32510Sstevel@tonic-gate case 0x3f0: 32520Sstevel@tonic-gate *cntrl_num = 0; 32530Sstevel@tonic-gate break; 32540Sstevel@tonic-gate 32550Sstevel@tonic-gate case 0x370: 32560Sstevel@tonic-gate *cntrl_num = 1; 32570Sstevel@tonic-gate break; 32580Sstevel@tonic-gate 32590Sstevel@tonic-gate default: 32600Sstevel@tonic-gate return (DDI_FAILURE); 32610Sstevel@tonic-gate } 32620Sstevel@tonic-gate return (DDI_SUCCESS); 32630Sstevel@tonic-gate } 32640Sstevel@tonic-gate 32650Sstevel@tonic-gate static int 32660Sstevel@tonic-gate get_ioaddr(dev_info_t *dip, int *ioaddr) 32670Sstevel@tonic-gate { 32680Sstevel@tonic-gate int reglen, nregs, i; 32690Sstevel@tonic-gate int status = DDI_FAILURE; 32700Sstevel@tonic-gate struct { 32710Sstevel@tonic-gate int bustype; 32720Sstevel@tonic-gate int base; 32730Sstevel@tonic-gate int size; 32740Sstevel@tonic-gate } *reglist; 32750Sstevel@tonic-gate 32760Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 32775295Srandyf "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { 32780Sstevel@tonic-gate cmn_err(CE_WARN, "fdc: reg property not found"); 32790Sstevel@tonic-gate return (DDI_FAILURE); 32800Sstevel@tonic-gate } 32810Sstevel@tonic-gate 32820Sstevel@tonic-gate nregs = reglen / sizeof (*reglist); 32830Sstevel@tonic-gate for (i = 0; i < nregs; i++) { 32840Sstevel@tonic-gate if (reglist[i].bustype == 1) { 32850Sstevel@tonic-gate *ioaddr = reglist[i].base; 32860Sstevel@tonic-gate status = DDI_SUCCESS; 32870Sstevel@tonic-gate break; 32880Sstevel@tonic-gate } 32890Sstevel@tonic-gate } 32900Sstevel@tonic-gate kmem_free(reglist, reglen); 32910Sstevel@tonic-gate 32920Sstevel@tonic-gate if (status == DDI_SUCCESS) { 32930Sstevel@tonic-gate if (*ioaddr == 0x3f2 || *ioaddr == 0x372) { 32940Sstevel@tonic-gate /* 32950Sstevel@tonic-gate * Some BIOS's (ASUS is one) don't include first 32960Sstevel@tonic-gate * two IO ports in the floppy controller resources. 32970Sstevel@tonic-gate */ 32980Sstevel@tonic-gate 32990Sstevel@tonic-gate *ioaddr -= 2; /* step back to 0x3f0 or 0x370 */ 33000Sstevel@tonic-gate 33010Sstevel@tonic-gate /* 33020Sstevel@tonic-gate * It would be nice to update the regs property as well 33030Sstevel@tonic-gate * so device pathname contains 3f0 instead of 3f2, but 33040Sstevel@tonic-gate * updating the regs now won't have this effect as that 33050Sstevel@tonic-gate * component of the device pathname has already been 33060Sstevel@tonic-gate * constructed by the ISA nexus driver. 33070Sstevel@tonic-gate * 33080Sstevel@tonic-gate * reglist[i].base -= 2; 33090Sstevel@tonic-gate * reglist[i].size += 2; 33100Sstevel@tonic-gate * dev = makedevice(ddi_driver_major(dip), 0); 33110Sstevel@tonic-gate * ddi_prop_update_int_array(dev, dip, "reg", 33120Sstevel@tonic-gate * (int *)reglist, reglen / sizeof (int)); 33130Sstevel@tonic-gate */ 33140Sstevel@tonic-gate } 33150Sstevel@tonic-gate } 33160Sstevel@tonic-gate 33170Sstevel@tonic-gate return (status); 33180Sstevel@tonic-gate } 3319