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