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