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