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