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