xref: /onnv-gate/usr/src/uts/sun/io/fd.c (revision 12779:96016f1d9837)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57656SSherry.Moore@Sun.COM  * Common Development and Distribution License (the "License").
67656SSherry.Moore@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12779SFred.Herard@Sun.COM  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Intel 82077 Floppy Disk Driver
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * Notes
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  *	0. The driver supports two flavors of hardware design:
340Sstevel@tonic-gate  *		"SUNW,fdtwo"	- sun4m	- 82077 with sun4m style Auxio
350Sstevel@tonic-gate  *		"fdthree"  - sun4u - 82077 with DMA
360Sstevel@tonic-gate  *	   In addition it supports an apparent bug in some versions of
370Sstevel@tonic-gate  *	   the 82077 controller.
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  *	1. The driver is mostly set up for multiple controllers, multiple
400Sstevel@tonic-gate  *	drives. However- we *do* assume the use of the AUXIO register, and
410Sstevel@tonic-gate  *	if we ever have > 1 fdc, we'll have to see what that means. This
420Sstevel@tonic-gate  *	is all intrinsically machine specific, but there isn't much we
430Sstevel@tonic-gate  *	can do about it.
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  *	2. The driver also is structured to deal with one drive active at
460Sstevel@tonic-gate  *	a time. This is because the 82072 chip (no longer supported) was
470Sstevel@tonic-gate  *	known to be buggy with respect to overlapped seeks.
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  *	3. The high level interrupt code is in assembler, and runs in a
500Sstevel@tonic-gate  *	sparc trap window. It acts as a pseudo-dma engine as well as
510Sstevel@tonic-gate  *	handles a couple of other interrupts. When it gets its job done,
520Sstevel@tonic-gate  *	it schedules a second stage interrupt (soft interrupt) which
530Sstevel@tonic-gate  *	is then fielded here in fd_lointr.  When DMA is used, the fdintr_dma
540Sstevel@tonic-gate  *	interrupt handler is used.
550Sstevel@tonic-gate  *
560Sstevel@tonic-gate  *	4. Nearly all locking is done on a lower level MUTEX_DRIVER
570Sstevel@tonic-gate  *	mutex. The locking is quite conservative, and is generally
580Sstevel@tonic-gate  *	established very close to any of the entries into the driver.
590Sstevel@tonic-gate  *	There is nearly no locking done of the high level MUTEX_DRIVER
600Sstevel@tonic-gate  *	mutex (which generally is a SPIN mutex because the floppy usually
610Sstevel@tonic-gate  *	interrupts above LOCK_LEVEL). The assembler high level interrupt
620Sstevel@tonic-gate  *	handler grabs the high level mutex, but the code in the driver
630Sstevel@tonic-gate  *	here is especially structured to not need to do this.
640Sstevel@tonic-gate  *
650Sstevel@tonic-gate  *	5. Fdrawioctl commands that pass data are not optimized for
660Sstevel@tonic-gate  *	speed. If they need to be faster, the driver structure will
670Sstevel@tonic-gate  *	have to be redone such that fdrawioctl calls physio after
680Sstevel@tonic-gate  *	cons'ing up a uio structure and that fdstart will be able
690Sstevel@tonic-gate  *	to detect that a particular buffer is a 'special' buffer.
700Sstevel@tonic-gate  *
710Sstevel@tonic-gate  *	6. Removable media support is not complete.
720Sstevel@tonic-gate  *
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #include <sys/param.h>
760Sstevel@tonic-gate #include <sys/buf.h>
770Sstevel@tonic-gate #include <sys/ioctl.h>
780Sstevel@tonic-gate #include <sys/uio.h>
790Sstevel@tonic-gate #include <sys/open.h>
800Sstevel@tonic-gate #include <sys/conf.h>
810Sstevel@tonic-gate #include <sys/file.h>
820Sstevel@tonic-gate #include <sys/cmn_err.h>
830Sstevel@tonic-gate #include <sys/debug.h>
840Sstevel@tonic-gate #include <sys/kmem.h>
850Sstevel@tonic-gate #include <sys/stat.h>
860Sstevel@tonic-gate #include <sys/autoconf.h>
870Sstevel@tonic-gate 
880Sstevel@tonic-gate #include <sys/dklabel.h>
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #include <sys/vtoc.h>
910Sstevel@tonic-gate #include <sys/dkio.h>
920Sstevel@tonic-gate #include <sys/fdio.h>
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #include <sys/ddi.h>
950Sstevel@tonic-gate #include <sys/sunddi.h>
960Sstevel@tonic-gate #include <sys/kstat.h>
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * included to check for ELC or SLC which report floppy controller that
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate #include <sys/cpu.h>
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate #include "sys/fdvar.h"
1040Sstevel@tonic-gate #include "sys/fdreg.h"
1050Sstevel@tonic-gate #include "sys/dma_i8237A.h"
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * Defines
1090Sstevel@tonic-gate  */
1100Sstevel@tonic-gate #define	KIOSP	KSTAT_IO_PTR(un->un_iostat)
1110Sstevel@tonic-gate #define	KIOIP	KSTAT_INTR_PTR(fdc->c_intrstat)
1120Sstevel@tonic-gate #define	MEDIUM_DENSITY	0x40
1130Sstevel@tonic-gate #define	SEC_SIZE_CODE	(fdctlr.c_csb->csb_unit]->un_chars->medium ? 3 : 2)
1140Sstevel@tonic-gate #define	CMD_READ	(MT + SK + FDRAW_RDCMD + MFM)
1150Sstevel@tonic-gate #define	CMD_WRITE	(MT + FDRAW_WRCMD + MFM)
1160Sstevel@tonic-gate #define	C		CE_CONT
1170Sstevel@tonic-gate #define	FD_POLLABLE_PROP	"pollable"	/* prom property */
1180Sstevel@tonic-gate #define	FD_MANUAL_EJECT		"manual"	/* prom property */
1190Sstevel@tonic-gate #define	FD_UNIT			"unit"		/* prom property */
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * Sony MP-F17W-50D Drive Parameters
1230Sstevel@tonic-gate  *				High Capacity
1240Sstevel@tonic-gate  *	Capacity unformatted	2Mb
1250Sstevel@tonic-gate  *	Capacity formatted	1.47Mb
1260Sstevel@tonic-gate  *	Encoding method	 MFM
1270Sstevel@tonic-gate  *	Recording density	17434 bpi
1280Sstevel@tonic-gate  *	Track density		135 tpi
1290Sstevel@tonic-gate  *	Cylinders		80
1300Sstevel@tonic-gate  *	Heads			2
1310Sstevel@tonic-gate  *	Tracks			160
1320Sstevel@tonic-gate  *	Rotational speed	300 rpm
1330Sstevel@tonic-gate  *	Transfer rate		250/500 kbps
1340Sstevel@tonic-gate  *	Latency (average)	100 ms
1350Sstevel@tonic-gate  *	Access time
1360Sstevel@tonic-gate  *		Average		95 ms
1370Sstevel@tonic-gate  *		Track to track	3 ms
1380Sstevel@tonic-gate  *	Head settling time	15 ms
1390Sstevel@tonic-gate  *	Motor start time	500 ms
1400Sstevel@tonic-gate  *	Head load time		? ms
1410Sstevel@tonic-gate  */
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate  * The max_fd_dma_len is used only when southbridge is present.
1450Sstevel@tonic-gate  * It has been observed that when IFB tests are run the floppy dma could get
1460Sstevel@tonic-gate  * starved and result in underrun errors. After experimenting it was found that
1470Sstevel@tonic-gate  * doing dma in chunks of 2048 works OK.
1480Sstevel@tonic-gate  * The reason for making this a global variable is that there could be
1490Sstevel@tonic-gate  * situations under which the customer would like to get full performance
1500Sstevel@tonic-gate  * from floppy. He may not be having IFB boards that cause underrun errors.
1510Sstevel@tonic-gate  * Under those conditions we could set this value to a much higher value
1520Sstevel@tonic-gate  * by editing /etc/system file.
1530Sstevel@tonic-gate  */
1540Sstevel@tonic-gate int	max_fd_dma_len = 2048;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate static void quiesce_fd_interrupt(struct fdctlr *);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate  * Character/block entry points function prototypes
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate static int fd_open(dev_t *, int, int, cred_t *);
1620Sstevel@tonic-gate static int fd_close(dev_t, int, int, cred_t *);
1630Sstevel@tonic-gate static int fd_strategy(struct buf *);
1640Sstevel@tonic-gate static int fd_read(dev_t, struct uio *, cred_t *);
1650Sstevel@tonic-gate static int fd_write(dev_t, struct uio *, cred_t *);
1660Sstevel@tonic-gate static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1670Sstevel@tonic-gate static int
1680Sstevel@tonic-gate fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * Device operations (dev_ops) entries function prototypes
1720Sstevel@tonic-gate  */
1730Sstevel@tonic-gate static int fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1740Sstevel@tonic-gate 		void **result);
1750Sstevel@tonic-gate static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
1760Sstevel@tonic-gate static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
1770Sstevel@tonic-gate static int fd_power(dev_info_t *dip, int component, int level);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * Internal functions
1810Sstevel@tonic-gate  */
1820Sstevel@tonic-gate static int fd_attach_check_drive(struct fdctlr *fdc);
1830Sstevel@tonic-gate static int fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc);
1840Sstevel@tonic-gate static int fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc);
1850Sstevel@tonic-gate static int fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc,
1860Sstevel@tonic-gate     int *hard);
1870Sstevel@tonic-gate static int fd_build_label_vtoc(struct fdunit *, struct vtoc *);
1880Sstevel@tonic-gate static void fd_build_user_vtoc(struct fdunit *, struct vtoc *);
1890Sstevel@tonic-gate static int fdcheckdisk(struct fdctlr *fdc, int unit);
1900Sstevel@tonic-gate static int fd_check_media(dev_t dev, enum dkio_state state);
1910Sstevel@tonic-gate static void fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard,
1920Sstevel@tonic-gate     int locks);
1930Sstevel@tonic-gate static void fdeject(struct fdctlr *, int unit);
1940Sstevel@tonic-gate static int fdexec(struct fdctlr *fdc, int flags);
1950Sstevel@tonic-gate static void fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit);
1960Sstevel@tonic-gate static int fdformat(struct fdctlr *fdc, int unit, int cyl, int hd);
1970Sstevel@tonic-gate static caddr_t fd_getauxiova();
1980Sstevel@tonic-gate static struct fdctlr *fd_getctlr(dev_t);
1990Sstevel@tonic-gate static void fdgetcsb(struct fdctlr *);
2000Sstevel@tonic-gate static int fdgetlabel(struct fdctlr *fdc, int unit);
2010Sstevel@tonic-gate enum dkio_state fd_get_media_state(struct fdctlr *, int);
2020Sstevel@tonic-gate static uint_t fdintr_dma();
2030Sstevel@tonic-gate static int fd_isauxiodip(dev_info_t *);
2040Sstevel@tonic-gate static uint_t  fd_lointr(caddr_t arg);
2050Sstevel@tonic-gate static void fd_media_watch(void *);
2060Sstevel@tonic-gate static void fdmotoff(void *);
2070Sstevel@tonic-gate static int fd_part_is_open(struct fdunit *un, int part);
2080Sstevel@tonic-gate static int fdrawioctl(struct fdctlr *, int, intptr_t, int);
2090Sstevel@tonic-gate static int fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg);
2100Sstevel@tonic-gate static int fdrecover(struct fdctlr *);
2110Sstevel@tonic-gate static void fdretcsb(struct fdctlr *);
2120Sstevel@tonic-gate static int fdreset(struct fdctlr *);
2130Sstevel@tonic-gate static int fdrw(struct fdctlr *fdc, int, int, int, int, int, caddr_t, uint_t);
2140Sstevel@tonic-gate static void fdselect(struct fdctlr *fdc, int unit, int onoff);
2150Sstevel@tonic-gate static int fdsensedrv(struct fdctlr *fdc, int unit);
2160Sstevel@tonic-gate static int fdsense_chng(struct fdctlr *, int unit);
2170Sstevel@tonic-gate static void fdstart(struct fdctlr *);
2180Sstevel@tonic-gate static int fdstart_dma(register struct fdctlr *fdc, caddr_t addr, uint_t len);
2190Sstevel@tonic-gate static int fd_unit_is_open(struct fdunit *);
2200Sstevel@tonic-gate static void fdunpacklabel(struct packed_label *, struct dk_label *);
2210Sstevel@tonic-gate static int fd_unbind_handle(struct fdctlr *);
2220Sstevel@tonic-gate static void fdwatch(void *);
2230Sstevel@tonic-gate static void set_rotational_speed(struct fdctlr *, int);
2240Sstevel@tonic-gate static int fd_get_media_info(struct fdunit *un, caddr_t buf, int flag);
2250Sstevel@tonic-gate static int fd_pm_lower_power(struct fdctlr *fdc);
2260Sstevel@tonic-gate static int fd_pm_raise_power(struct fdctlr *fdc);
2270Sstevel@tonic-gate static void create_pm_components(dev_info_t *dip);
2280Sstevel@tonic-gate static void set_data_count_register(struct fdctlr *fdc, uint32_t count);
2290Sstevel@tonic-gate static uint32_t get_data_count_register(struct fdctlr *fdc);
2300Sstevel@tonic-gate static void reset_dma_controller(struct fdctlr *fdc);
2310Sstevel@tonic-gate static void set_data_address_register(struct fdctlr *fdc, uint32_t address);
2320Sstevel@tonic-gate static uint32_t get_dma_control_register(struct fdctlr *fdc);
2330Sstevel@tonic-gate static void set_dma_mode(struct fdctlr *fdc, int val);
2340Sstevel@tonic-gate static void set_dma_control_register(struct fdctlr *fdc, uint32_t val);
2350Sstevel@tonic-gate static void release_sb_dma(struct fdctlr *fdc);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  * External functions
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate extern uint_t fd_intr(caddr_t);	/* defined in fd_asm.s */
2410Sstevel@tonic-gate extern void set_auxioreg();
2420Sstevel@tonic-gate extern void call_debug();
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate  * The following macro checks whether the device in a SUSPENDED state.
2480Sstevel@tonic-gate  * As per WDD guide lines the I/O requests to a suspended device should
2490Sstevel@tonic-gate  * be blocked until the device is resumed.
2500Sstevel@tonic-gate  * Here we cv_wait on c_suspend_cv, and there is a cv_broadcast() in
2510Sstevel@tonic-gate  * DDI_RESUME to wake up this thread.
2520Sstevel@tonic-gate  *
2530Sstevel@tonic-gate  * NOTE: This code is not tested because the kernel threads are suspended
2540Sstevel@tonic-gate  * before the device is suspended. So there can not be any I/O requests on
2550Sstevel@tonic-gate  * a suspended device until the cpr implementation changes..
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate #define	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc) 	\
2590Sstevel@tonic-gate 		{\
2600Sstevel@tonic-gate 			while (fdc->c_un->un_state == FD_STATE_SUSPENDED) {\
2610Sstevel@tonic-gate 				cv_wait(&fdc->c_suspend_cv, \
2620Sstevel@tonic-gate 							&fdc->c_lolock);\
2630Sstevel@tonic-gate 			}\
2640Sstevel@tonic-gate 		}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate  * bss (uninitialized data)
2680Sstevel@tonic-gate  */
2690Sstevel@tonic-gate struct	fdctlr	*fdctlrs;	/* linked list of controllers */
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate  * initialized data
2730Sstevel@tonic-gate  */
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate static int fd_check_media_time = 5000000;	/* 5 second state check */
2760Sstevel@tonic-gate static int fd_pollable = 0;
2770Sstevel@tonic-gate static uchar_t rwretry = 10;
2780Sstevel@tonic-gate static uchar_t skretry = 5;
2790Sstevel@tonic-gate /* This variable allows the dynamic change of the burst size */
2800Sstevel@tonic-gate static int fd_burstsize = DCSR_BURST_0 | DCSR_BURST_1;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate static struct driver_minor_data {
2830Sstevel@tonic-gate 	char	*name;
2840Sstevel@tonic-gate 	int	minor;
2850Sstevel@tonic-gate 	int	type;
2860Sstevel@tonic-gate } fd_minor [] = {
2870Sstevel@tonic-gate 	{ "a", 0, S_IFBLK},
2880Sstevel@tonic-gate 	{ "b", 1, S_IFBLK},
2890Sstevel@tonic-gate 	{ "c", 2, S_IFBLK},
2900Sstevel@tonic-gate 	{ "a,raw", 0, S_IFCHR},
2910Sstevel@tonic-gate 	{ "b,raw", 1, S_IFCHR},
2920Sstevel@tonic-gate 	{ "c,raw", 2, S_IFCHR},
2930Sstevel@tonic-gate 	{0}
2940Sstevel@tonic-gate };
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * If the interrupt handler is invoked and no controllers expect an
2980Sstevel@tonic-gate  * interrupt, the kernel panics.  The following message is printed out.
2990Sstevel@tonic-gate  */
3000Sstevel@tonic-gate char *panic_msg = "fd_intr: unexpected interrupt\n";
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate /*
3030Sstevel@tonic-gate  * Specify/Configure cmd parameters
3040Sstevel@tonic-gate  */
3050Sstevel@tonic-gate static uchar_t fdspec[2] = { 0xc2, 0x33 };	/*  "specify" parameters */
3060Sstevel@tonic-gate static uchar_t fdconf[3] = { 0x64, 0x58, 0x00 }; /*  "configure" parameters */
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate /* When DMA is used, set the ND bit to 0 */
3090Sstevel@tonic-gate #define	SPEC_DMA_MODE	0x32
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate /*
3120Sstevel@tonic-gate  * default characteristics
3130Sstevel@tonic-gate  */
3140Sstevel@tonic-gate static struct fd_char fdtypes[] = {
3150Sstevel@tonic-gate 	{	/* struct fd_char fdchar_1.7MB density */
3160Sstevel@tonic-gate 		0,		/* medium */
3170Sstevel@tonic-gate 		500,		/* transfer rate */
3180Sstevel@tonic-gate 		80,		/* number of cylinders */
3190Sstevel@tonic-gate 		2,		/* number of heads */
3200Sstevel@tonic-gate 		512,		/* sector size */
3210Sstevel@tonic-gate 		21,		/* sectors per track */
3220Sstevel@tonic-gate 		-1,		/* (NA) # steps per data track */
3230Sstevel@tonic-gate 	},
3240Sstevel@tonic-gate 	{	/* struct fd_char fdchar_highdens */
3250Sstevel@tonic-gate 		0, 		/* medium */
3260Sstevel@tonic-gate 		500, 		/* transfer rate */
3270Sstevel@tonic-gate 		80, 		/* number of cylinders */
3280Sstevel@tonic-gate 		2, 		/* number of heads */
3290Sstevel@tonic-gate 		512, 		/* sector size */
3300Sstevel@tonic-gate 		18, 		/* sectors per track */
3310Sstevel@tonic-gate 		-1, 		/* (NA) # steps per data track */
3320Sstevel@tonic-gate 	},
3330Sstevel@tonic-gate 	{	/* struct fd_char fdchar_meddens */
3340Sstevel@tonic-gate 		1, 		/* medium */
3350Sstevel@tonic-gate 		500, 		/* transfer rate */
3360Sstevel@tonic-gate 		77, 		/* number of cylinders */
3370Sstevel@tonic-gate 		2, 		/* number of heads */
3380Sstevel@tonic-gate 		1024, 		/* sector size */
3390Sstevel@tonic-gate 		8, 		/* sectors per track */
3400Sstevel@tonic-gate 		-1, 		/* (NA) # steps per data track */
3410Sstevel@tonic-gate 	},
3420Sstevel@tonic-gate 	{	/* struct fd_char fdchar_lowdens  */
3430Sstevel@tonic-gate 		0, 		/* medium */
3440Sstevel@tonic-gate 		250, 		/* transfer rate */
3450Sstevel@tonic-gate 		80, 		/* number of cylinders */
3460Sstevel@tonic-gate 		2, 		/* number of heads */
3470Sstevel@tonic-gate 		512, 		/* sector size */
3480Sstevel@tonic-gate 		9, 		/* sectors per track */
3490Sstevel@tonic-gate 		-1, 		/* (NA) # steps per data track */
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate };
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate static int nfdtypes = sizeof (fdtypes) / sizeof (fdtypes[0]);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate  * Default Label & partition maps
3590Sstevel@tonic-gate  */
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate static struct packed_label fdlbl_high_21 = {
3620Sstevel@tonic-gate 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 21" },
3630Sstevel@tonic-gate 	300,				/* rotations per minute */
3640Sstevel@tonic-gate 	80,				/* # physical cylinders */
3650Sstevel@tonic-gate 	0,				/* alternates per cylinder */
3660Sstevel@tonic-gate 	1,				/* interleave factor */
3670Sstevel@tonic-gate 	80,				/* # of data cylinders */
3680Sstevel@tonic-gate 	0,				/* # of alternate cylinders */
3690Sstevel@tonic-gate 	2,				/* # of heads in this partition */
3700Sstevel@tonic-gate 	21,				/* # of 512 byte sectors per track */
3710Sstevel@tonic-gate 	{
3720Sstevel@tonic-gate 		{ 0, 79 * 2 * 21 },	/* part 0 - all but last cyl */
3730Sstevel@tonic-gate 		{ 79, 1 * 2 * 21 },	/* part 1 - just the last cyl */
3740Sstevel@tonic-gate 		{ 0, 80 * 2 * 21 },	/* part 2 - "the whole thing" */
3750Sstevel@tonic-gate 	},
3760Sstevel@tonic-gate 	{	0,			/* version */
3770Sstevel@tonic-gate 		"",			/* volume label */
3780Sstevel@tonic-gate 		3,			/* no. of partitions */
3790Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
3800Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
3810Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
3820Sstevel@tonic-gate 		{ 0 },			/* reserved space */
3830Sstevel@tonic-gate 		0,			/* timestamp */
3840Sstevel@tonic-gate 	},
3850Sstevel@tonic-gate };
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate static struct packed_label fdlbl_high_80 = {
3880Sstevel@tonic-gate 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 18" },
3890Sstevel@tonic-gate 	300, 				/* rotations per minute */
3900Sstevel@tonic-gate 	80, 				/* # physical cylinders */
3910Sstevel@tonic-gate 	0, 				/* alternates per cylinder */
3920Sstevel@tonic-gate 	1, 				/* interleave factor */
3930Sstevel@tonic-gate 	80, 				/* # of data cylinders */
3940Sstevel@tonic-gate 	0, 				/* # of alternate cylinders */
3950Sstevel@tonic-gate 	2, 				/* # of heads in this partition */
3960Sstevel@tonic-gate 	18, 				/* # of 512 byte sectors per track */
3970Sstevel@tonic-gate 	{
3980Sstevel@tonic-gate 		{ 0, 79 * 2 * 18 }, 	/* part 0 - all but last cyl */
3990Sstevel@tonic-gate 		{ 79, 1 * 2 * 18 }, 	/* part 1 - just the last cyl */
4000Sstevel@tonic-gate 		{ 0, 80 * 2 * 18 }, 	/* part 2 - "the whole thing" */
4010Sstevel@tonic-gate 	},
4020Sstevel@tonic-gate 	{	0,			/* version */
4030Sstevel@tonic-gate 		"",			/* volume label */
4040Sstevel@tonic-gate 		3,			/* no. of partitions */
4050Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
4060Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
4070Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
4080Sstevel@tonic-gate 		{ 0 },			/* reserved space */
4090Sstevel@tonic-gate 		0,			/* timestamp */
4100Sstevel@tonic-gate 	},
4110Sstevel@tonic-gate };
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate /*
4140Sstevel@tonic-gate  * A medium density diskette has 1024 byte sectors.  The dk_label structure
4150Sstevel@tonic-gate  * assumes a sector is DEVBSIZE (512) bytes.
4160Sstevel@tonic-gate  */
4170Sstevel@tonic-gate static struct packed_label fdlbl_medium_80 = {
4180Sstevel@tonic-gate 	{ "3.5\" floppy cyl 77 alt 0 hd 2 sec 8" },
4190Sstevel@tonic-gate 	360, 				/* rotations per minute */
4200Sstevel@tonic-gate 	77, 				/* # physical cylinders */
4210Sstevel@tonic-gate 	0, 				/* alternates per cylinder */
4220Sstevel@tonic-gate 	1, 				/* interleave factor */
4230Sstevel@tonic-gate 	77, 				/* # of data cylinders */
4240Sstevel@tonic-gate 	0, 				/* # of alternate cylinders */
4250Sstevel@tonic-gate 	2, 				/* # of heads in this partition */
4260Sstevel@tonic-gate 	16, 				/* # of 512 byte sectors per track */
4270Sstevel@tonic-gate 	{
4280Sstevel@tonic-gate 		{ 0, 76 * 2 * 8 * 2 },  /* part 0 - all but last cyl */
4290Sstevel@tonic-gate 		{ 76, 1 * 2 * 8 * 2 },  /* part 1 - just the last cyl */
4300Sstevel@tonic-gate 		{ 0, 77 * 2 * 8 * 2 },  /* part 2 - "the whole thing" */
4310Sstevel@tonic-gate 	},
4320Sstevel@tonic-gate 	{	0,			/* version */
4330Sstevel@tonic-gate 		"",			/* volume label */
4340Sstevel@tonic-gate 		3,			/* no. of partitions */
4350Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
4360Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
4370Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
4380Sstevel@tonic-gate 		{ 0 },			/* reserved space */
4390Sstevel@tonic-gate 		0,			/* timestamp */
4400Sstevel@tonic-gate 	},
4410Sstevel@tonic-gate };
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate static struct packed_label fdlbl_low_80 = {
4440Sstevel@tonic-gate 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 9" },
4450Sstevel@tonic-gate 	300, 				/* rotations per minute */
4460Sstevel@tonic-gate 	80, 				/* # physical cylinders */
4470Sstevel@tonic-gate 	0, 				/* alternates per cylinder */
4480Sstevel@tonic-gate 	1, 				/* interleave factor */
4490Sstevel@tonic-gate 	80, 				/* # of data cylinders */
4500Sstevel@tonic-gate 	0, 				/* # of alternate cylinders */
4510Sstevel@tonic-gate 	2, 				/* # of heads in this partition */
4520Sstevel@tonic-gate 	9, 				/* # of 512 byte sectors per track */
4530Sstevel@tonic-gate 	{
4540Sstevel@tonic-gate 		{ 0, 79 * 2 * 9 }, 	/* part 0 - all but last cyl */
4550Sstevel@tonic-gate 		{ 79, 1 * 2 * 9 }, 	/* part 1 - just the last cyl */
4560Sstevel@tonic-gate 		{ 0, 80 * 2 * 9 }, 	/* part 2 - "the whole thing" */
4570Sstevel@tonic-gate 	},
4580Sstevel@tonic-gate 	{	0,			/* version */
4590Sstevel@tonic-gate 		"",			/* volume label */
4600Sstevel@tonic-gate 		3,			/* no. of partitions */
4610Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
4620Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
4630Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
4640Sstevel@tonic-gate 		{ 0 },			/* reserved space */
4650Sstevel@tonic-gate 		0,			/* timestamp */
4660Sstevel@tonic-gate 	},
4670Sstevel@tonic-gate };
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate static struct fdcmdinfo {
4700Sstevel@tonic-gate 	char *cmdname;		/* command name */
4710Sstevel@tonic-gate 	uchar_t ncmdbytes;	/* number of bytes of command */
4720Sstevel@tonic-gate 	uchar_t nrsltbytes;	/* number of bytes in result */
4730Sstevel@tonic-gate 	uchar_t cmdtype;		/* characteristics */
4740Sstevel@tonic-gate } fdcmds[] = {
4750Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4760Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4770Sstevel@tonic-gate 	"read_track", 9, 7, 1, 		/* 2 */
4780Sstevel@tonic-gate 	"specify", 3, 0, 3, 		/* 3 */
4790Sstevel@tonic-gate 	"sense_drv_status", 2, 1, 3, 	/* 4 */
4800Sstevel@tonic-gate 	"write", 9, 7, 1, 		/* 5 */
4810Sstevel@tonic-gate 	"read", 9, 7, 1, 		/* 6 */
4820Sstevel@tonic-gate 	"recalibrate", 2, 0, 2, 		/* 7 */
4830Sstevel@tonic-gate 	"sense_int_status", 1, 2, 3, 	/* 8 */
4840Sstevel@tonic-gate 	"write_del", 9, 7, 1, 		/* 9 */
4850Sstevel@tonic-gate 	"read_id", 2, 7, 2, 		/* A */
4860Sstevel@tonic-gate 	"motor_on/off", 1, 0, 4, 	/* B */
4870Sstevel@tonic-gate 	"read_del", 9, 7, 1, 		/* C */
4880Sstevel@tonic-gate 	"format_track", 10, 7, 1, 	/* D */
4890Sstevel@tonic-gate 	"dump_reg", 1, 10, 4, 		/* E */
4900Sstevel@tonic-gate 	"seek", 3, 0, 2, 		/* F */
4910Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4920Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4930Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4940Sstevel@tonic-gate 	"configure", 4, 0, 4, 		/* 13 */
4950Sstevel@tonic-gate 	/* relative seek */
4960Sstevel@tonic-gate };
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate static struct cb_ops fd_cb_ops = {
4990Sstevel@tonic-gate 	fd_open, 		/* open */
5000Sstevel@tonic-gate 	fd_close, 		/* close */
5010Sstevel@tonic-gate 	fd_strategy, 		/* strategy */
5020Sstevel@tonic-gate 	nodev, 			/* print */
5030Sstevel@tonic-gate 	nodev, 			/* dump */
5040Sstevel@tonic-gate 	fd_read, 		/* read */
5050Sstevel@tonic-gate 	fd_write, 		/* write */
5060Sstevel@tonic-gate 	fd_ioctl, 		/* ioctl */
5070Sstevel@tonic-gate 	nodev, 			/* devmap */
5080Sstevel@tonic-gate 	nodev, 			/* mmap */
5090Sstevel@tonic-gate 	nodev, 			/* segmap */
5100Sstevel@tonic-gate 	nochpoll, 		/* poll */
5110Sstevel@tonic-gate 	fd_prop_op, 		/* cb_prop_op */
5120Sstevel@tonic-gate 	0, 			/* streamtab  */
5130Sstevel@tonic-gate 	D_NEW | D_MP		/* Driver compatibility flag */
5140Sstevel@tonic-gate };
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate static struct dev_ops	fd_ops = {
5170Sstevel@tonic-gate 	DEVO_REV, 		/* devo_rev, */
5180Sstevel@tonic-gate 	0, 			/* refcnt  */
5190Sstevel@tonic-gate 	fd_info, 		/* info */
5200Sstevel@tonic-gate 	nulldev, 		/* identify */
5210Sstevel@tonic-gate 	nulldev, 		/* probe */
5220Sstevel@tonic-gate 	fd_attach, 		/* attach */
5230Sstevel@tonic-gate 	fd_detach, 		/* detach */
5240Sstevel@tonic-gate 	nodev, 			/* reset */
5250Sstevel@tonic-gate 	&fd_cb_ops, 		/* driver operations */
5260Sstevel@tonic-gate 	(struct bus_ops *)0,	/* bus operations */
5277656SSherry.Moore@Sun.COM 	fd_power,		/* power */
5287656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
5290Sstevel@tonic-gate };
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate  * error handling
5340Sstevel@tonic-gate  *
5350Sstevel@tonic-gate  * for debugging, set rwretry and skretry = 1
5360Sstevel@tonic-gate  *		set fderrlevel to 1
5370Sstevel@tonic-gate  *		set fderrmask  to 224  or 100644
5380Sstevel@tonic-gate  *
5390Sstevel@tonic-gate  * after debug set rwretry to 10, skretry to 5, and fderrlevel to 3
5400Sstevel@tonic-gate  * set fderrmask to FDEM_ALL
5410Sstevel@tonic-gate  * remove the define FD_DEBUG
5420Sstevel@tonic-gate  *
5430Sstevel@tonic-gate  */
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate static unsigned int fderrmask = (unsigned int)FDEM_ALL;
5460Sstevel@tonic-gate static int fderrlevel = 3;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate static int tosec = 16;  /* long timeouts for sundiag for now */
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate  * loadable module support
5520Sstevel@tonic-gate  */
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate #include <sys/modctl.h>
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate extern struct mod_ops mod_driverops;
5570Sstevel@tonic-gate static struct modldrv modldrv = {
5587656SSherry.Moore@Sun.COM 	&mod_driverops,		/* Type of module. driver here */
5597656SSherry.Moore@Sun.COM 	"Floppy Driver", 	/* Name of the module. */
5600Sstevel@tonic-gate 	&fd_ops, 		/* Driver ops vector */
5610Sstevel@tonic-gate };
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate static struct modlinkage modlinkage = {
5640Sstevel@tonic-gate 	MODREV_1,
5650Sstevel@tonic-gate 	&modldrv,
5660Sstevel@tonic-gate 	NULL
5670Sstevel@tonic-gate };
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate int
_init(void)5700Sstevel@tonic-gate _init(void)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	return (mod_install(&modlinkage));
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate int
_info(struct modinfo * modinfop)5760Sstevel@tonic-gate _info(struct modinfo *modinfop)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate int
_fini(void)5820Sstevel@tonic-gate _fini(void)
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate 	int e;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) != 0)
5870Sstevel@tonic-gate 		return (e);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/* ddi_soft_state_fini() */
5900Sstevel@tonic-gate 	return (0);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate /* ARGSUSED */
5940Sstevel@tonic-gate static int
fd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)5950Sstevel@tonic-gate fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	struct 			fdctlr *fdc;
5980Sstevel@tonic-gate 	struct 			driver_minor_data *dmdp;
5990Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
6000Sstevel@tonic-gate 	int			hard_intr_set = 0;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: start\n"));
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	switch (cmd) {
6050Sstevel@tonic-gate 		case DDI_ATTACH:
6060Sstevel@tonic-gate 			break;
6070Sstevel@tonic-gate 		case DDI_RESUME:
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 			if (!(fdc = fd_getctlr(instance << FDINSTSHIFT))) {
6100Sstevel@tonic-gate 				return (DDI_FAILURE);
6110Sstevel@tonic-gate 			}
6120Sstevel@tonic-gate 			quiesce_fd_interrupt(fdc);
6130Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB)
6147656SSherry.Moore@Sun.COM 				if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
6157656SSherry.Moore@Sun.COM 				    fdintr_dma, (caddr_t)0) != DDI_SUCCESS) {
6160Sstevel@tonic-gate 				return (DDI_FAILURE);
6170Sstevel@tonic-gate 			}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 			(void) pm_raise_power(dip, 0, PM_LEVEL_ON);
6200Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
6210Sstevel@tonic-gate 			/*
6220Sstevel@tonic-gate 			 * Wake up any thread blocked due to I/O requests
6230Sstevel@tonic-gate 			 * while the device was suspended.
6240Sstevel@tonic-gate 			 */
6250Sstevel@tonic-gate 			cv_broadcast(&fdc->c_suspend_cv);
6260Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
6270Sstevel@tonic-gate 			return (DDI_SUCCESS);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		default:
6300Sstevel@tonic-gate 			return (DDI_FAILURE);
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	/*
6350Sstevel@tonic-gate 	 * Check for the pollable property
6360Sstevel@tonic-gate 	 * A pollable floppy drive currently only exists on the
6370Sstevel@tonic-gate 	 * Sparcstation Voyager.  This drive does not need to
6380Sstevel@tonic-gate 	 * be turned on in order to sense whether or not a diskette
6390Sstevel@tonic-gate 	 * is present.
6400Sstevel@tonic-gate 	 */
6410Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, dip,
6420Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, FD_POLLABLE_PROP, 0))
6430Sstevel@tonic-gate 		fd_pollable = 1;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	fdc = kmem_zalloc(sizeof (*fdc), KM_SLEEP);
6460Sstevel@tonic-gate 	fdc->c_dip = dip;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	fdc->c_next = fdctlrs;
6500Sstevel@tonic-gate 	fdctlrs = fdc;
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	/* Determine which type of controller is present and initialize it */
6530Sstevel@tonic-gate 	if (fd_attach_det_ctlr(dip, fdc) == DDI_FAILURE) {
6540Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 0);
6550Sstevel@tonic-gate 		return (DDI_FAILURE);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	/* Finish mapping the device registers & setting up structures */
6580Sstevel@tonic-gate 	if (fd_attach_map_regs(dip, fdc) == DDI_FAILURE) {
6590Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 0);
6600Sstevel@tonic-gate 		return (DDI_FAILURE);
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	/*
6640Sstevel@tonic-gate 	 * Initialize the DMA limit structures if it's being used.
6650Sstevel@tonic-gate 	 */
6660Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
6670Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_version = DMA_ATTR_V0;
6680Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_addr_lo = 0x00000000ull;
6690Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_addr_hi = 0xfffffffeull;
6700Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_count_max = 0xffffff;
6710Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB) {
6720Sstevel@tonic-gate 			fdc->c_fd_dma_lim.dma_attr_align = FD_SB_DMA_ALIGN;
6730Sstevel@tonic-gate 		} else {
6740Sstevel@tonic-gate 			fdc->c_fd_dma_lim.dma_attr_align = 1;
6750Sstevel@tonic-gate 		}
6760Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_burstsizes = 0x0;
6770Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_minxfer = 1;
6780Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_maxxfer = 0xffff;
6790Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_seg = 0xffff;
6800Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_sgllen = 1;
6810Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_granular = 512;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dip, &fdc->c_fd_dma_lim,
6840Sstevel@tonic-gate 		    DDI_DMA_DONTWAIT, 0, &fdc->c_dmahandle) != DDI_SUCCESS) {
6850Sstevel@tonic-gate 			fd_cleanup(dip, fdc, hard_intr_set, 0);
6860Sstevel@tonic-gate 			return (DDI_FAILURE);
6870Sstevel@tonic-gate 		}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB) {
6900Sstevel@tonic-gate 			ddi_device_acc_attr_t dev_attr;
6910Sstevel@tonic-gate 			size_t	rlen;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 			dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6940Sstevel@tonic-gate 			dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
6950Sstevel@tonic-gate 			dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 			if (ddi_dma_mem_alloc(fdc->c_dmahandle,
6980Sstevel@tonic-gate 			    (size_t)(32*1024), &dev_attr, DDI_DMA_CONSISTENT,
6990Sstevel@tonic-gate 			    DDI_DMA_SLEEP, NULL, (caddr_t *)&fdc->dma_buf,
7000Sstevel@tonic-gate 			    &rlen, &fdc->c_dma_buf_handle) != DDI_SUCCESS) {
7017656SSherry.Moore@Sun.COM 				fd_cleanup(dip, fdc, hard_intr_set, 0);
7020Sstevel@tonic-gate 				return (DDI_FAILURE);
7030Sstevel@tonic-gate 			}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 		}
7060Sstevel@tonic-gate 	}
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	/* Register the interrupts */
7100Sstevel@tonic-gate 	if (fd_attach_register_interrupts(dip, fdc,
7110Sstevel@tonic-gate 	    &hard_intr_set) == DDI_FAILURE) {
7120Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 0);
7130Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
7140Sstevel@tonic-gate 		    (C, "fd_attach: registering interrupts failed\n"));
7150Sstevel@tonic-gate 		return (DDI_FAILURE);
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	/*
7200Sstevel@tonic-gate 	 * set initial controller/drive/disk "characteristics/geometry"
7210Sstevel@tonic-gate 	 *
7220Sstevel@tonic-gate 	 * NOTE:  The driver only supports one floppy drive.  The hardware
7230Sstevel@tonic-gate 	 * only supports one drive because there is only one auxio register
7240Sstevel@tonic-gate 	 * for one drive.
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	fdc->c_un = kmem_zalloc(sizeof (struct fdunit), KM_SLEEP);
7270Sstevel@tonic-gate 	fdc->c_un->un_chars = kmem_alloc(sizeof (struct fd_char), KM_SLEEP);
7280Sstevel@tonic-gate 	fdc->c_un->un_iostat = kstat_create("fd", 0, "fd0", "disk",
7290Sstevel@tonic-gate 	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
7300Sstevel@tonic-gate 	if (fdc->c_un->un_iostat) {
7310Sstevel@tonic-gate 		fdc->c_un->un_iostat->ks_lock = &fdc->c_lolock;
7320Sstevel@tonic-gate 		kstat_install(fdc->c_un->un_iostat);
7330Sstevel@tonic-gate 	}
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	fdc->c_un->un_drive = kmem_zalloc(sizeof (struct fd_drive), KM_SLEEP);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	/* check for the manual eject property */
7380Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, dip,
7390Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, FD_MANUAL_EJECT, 0)) {
7400Sstevel@tonic-gate 		fdc->c_un->un_drive->fdd_ejectable = 0;
7410Sstevel@tonic-gate 	} else {
7420Sstevel@tonic-gate 		/* an absence of the property indicates auto eject */
7430Sstevel@tonic-gate 		fdc->c_un->un_drive->fdd_ejectable = -1;
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: ejectable? %d\n",
7470Sstevel@tonic-gate 	    fdc->c_un->un_drive->fdd_ejectable));
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/*
7500Sstevel@tonic-gate 	 * Check for the drive id.  If the drive id property doesn't exist
7510Sstevel@tonic-gate 	 * then the drive id is set to 0
7520Sstevel@tonic-gate 	 */
7530Sstevel@tonic-gate 	fdc->c_un->un_unit_no = ddi_getprop(DDI_DEV_T_ANY, dip,
7540Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, FD_UNIT, 0);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB) {
7580Sstevel@tonic-gate 		fdc->sb_dma_channel = ddi_getprop(DDI_DEV_T_ANY, dip,
7597656SSherry.Moore@Sun.COM 		    DDI_PROP_DONTPASS, "dma-channel", 0);
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: unit %d\n",
7640Sstevel@tonic-gate 	    fdc->c_un->un_unit_no));
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	/* Initially set the characteristics to high density */
7670Sstevel@tonic-gate 	fdc->c_un->un_curfdtype = 1;
7680Sstevel@tonic-gate 	*fdc->c_un->un_chars = fdtypes[fdc->c_un->un_curfdtype];
7690Sstevel@tonic-gate 	fdunpacklabel(&fdlbl_high_80, &fdc->c_un->un_label);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/* Make sure drive is present */
7720Sstevel@tonic-gate 	if (fd_attach_check_drive(fdc) == DDI_FAILURE) {
7730Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 1);
7740Sstevel@tonic-gate 		return (DDI_FAILURE);
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
7780Sstevel@tonic-gate 		if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
7797656SSherry.Moore@Sun.COM 		    (instance << FDINSTSHIFT) | dmdp->minor,
7807656SSherry.Moore@Sun.COM 		    DDI_NT_FD, 0) == DDI_FAILURE) {
7810Sstevel@tonic-gate 			fd_cleanup(dip, fdc, hard_intr_set, 1);
7820Sstevel@tonic-gate 			return (DDI_FAILURE);
7830Sstevel@tonic-gate 		}
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	create_pm_components(dip);
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	/*
7890Sstevel@tonic-gate 	 * Add a zero-length attribute to tell the world we support
7900Sstevel@tonic-gate 	 * kernel ioctls (for layered drivers)
7910Sstevel@tonic-gate 	 */
7920Sstevel@tonic-gate 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
7930Sstevel@tonic-gate 	    DDI_KERNEL_IOCTL, NULL, 0);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	ddi_report_dev(dip);
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
7980Sstevel@tonic-gate 	    (C, "attached 0x%x\n", ddi_get_instance(dip)));
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	return (DDI_SUCCESS);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate /*
8040Sstevel@tonic-gate  * Finish mapping the registers and initializing structures
8050Sstevel@tonic-gate  */
8060Sstevel@tonic-gate static int
fd_attach_map_regs(dev_info_t * dip,struct fdctlr * fdc)8070Sstevel@tonic-gate fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8120Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
8130Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	/* Map the DMA registers of the platform supports DMA */
8160Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB) {
8170Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
8187656SSherry.Moore@Sun.COM 		    0, sizeof (struct sb_dma_reg), &attr,
8197656SSherry.Moore@Sun.COM 		    &fdc->c_handlep_dma)) {
8200Sstevel@tonic-gate 			return (DDI_FAILURE);
8210Sstevel@tonic-gate 		}
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
8250Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
8267656SSherry.Moore@Sun.COM 		    0, sizeof (struct cheerio_dma_reg), &attr,
8277656SSherry.Moore@Sun.COM 		    &fdc->c_handlep_dma)) {
8280Sstevel@tonic-gate 			return (DDI_FAILURE);
8290Sstevel@tonic-gate 		}
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	/* Reset the DMA engine and enable floppy interrupts */
8330Sstevel@tonic-gate 	reset_dma_controller(fdc);
8340Sstevel@tonic-gate 	set_dma_control_register(fdc, DCSR_INIT_BITS);
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	/* Finish initializing structures associated with the device regs */
8370Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
8380Sstevel@tonic-gate 	case FDCTYPE_82077:
8390Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "type is 82077\n"));
8400Sstevel@tonic-gate 		/*
8410Sstevel@tonic-gate 		 * Initialize addrs of key registers
8420Sstevel@tonic-gate 		 */
8430Sstevel@tonic-gate 		fdc->c_control =
8440Sstevel@tonic-gate 		    (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_control;
8450Sstevel@tonic-gate 		fdc->c_fifo = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_fifo;
8460Sstevel@tonic-gate 		fdc->c_dor = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dor;
8470Sstevel@tonic-gate 		fdc->c_dir = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dir;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, ((int)C,
8517656SSherry.Moore@Sun.COM 		    (char *)"fdattach: msr/dsr at %p\n",
8527656SSherry.Moore@Sun.COM 		    (void *)fdc->c_control));
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 		/*
8550Sstevel@tonic-gate 		 * The 82077 doesn't use the first configuration parameter
8560Sstevel@tonic-gate 		 * so let's adjust that while we know we're an 82077.
8570Sstevel@tonic-gate 		 */
8580Sstevel@tonic-gate 		fdconf[0] = 0;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		quiesce_fd_interrupt(fdc);
8610Sstevel@tonic-gate 		break;
8620Sstevel@tonic-gate 	default:
8630Sstevel@tonic-gate 		break;
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	return (0);
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate  * Determine which type of floppy controller is present and
8710Sstevel@tonic-gate  * initialize the registers accordingly
8720Sstevel@tonic-gate  */
8730Sstevel@tonic-gate static int
fd_attach_det_ctlr(dev_info_t * dip,struct fdctlr * fdc)8740Sstevel@tonic-gate fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc)
8750Sstevel@tonic-gate {
8760Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
8770Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8780Sstevel@tonic-gate 	/* DDI_NEVERSWAP_ACC since the controller has a byte interface. */
8790Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
8800Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
8837656SSherry.Moore@Sun.COM 	    (C, "fdattach_det_cltr: start \n"));
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * First, map in the controller's registers
8870Sstevel@tonic-gate 	 * The controller has an 8-bit interface, so byte
8880Sstevel@tonic-gate 	 * swapping isn't needed
8890Sstevel@tonic-gate 	 */
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&fdc->c_reg,
8927656SSherry.Moore@Sun.COM 	    0, sizeof (union fdcreg),
8937656SSherry.Moore@Sun.COM 	    &attr,
8947656SSherry.Moore@Sun.COM 	    &fdc->c_handlep_cont)) {
8957656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
8960Sstevel@tonic-gate 	}
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
8997656SSherry.Moore@Sun.COM 	    (C, "fdattach_det_cltr: mapped floppy regs\n"));
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	/*
9030Sstevel@tonic-gate 	 * Set platform specific characteristics based on the device-tree
9040Sstevel@tonic-gate 	 * node name.
9050Sstevel@tonic-gate 	 */
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	if (strcmp(ddi_get_name(dip), "SUNW,fdtwo") == 0) {
9090Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_SLAVIO;
9100Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_82077;
9110Sstevel@tonic-gate 		fdc->c_auxiova = fd_getauxiova(dip);
9120Sstevel@tonic-gate 		fdc->c_auxiodata = (uchar_t)(AUX_MBO4M|AUX_TC4M);
9130Sstevel@tonic-gate 		fdc->c_auxiodata2 = (uchar_t)AUX_TC4M;
9140Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9157656SSherry.Moore@Sun.COM 		    (C, "fdattach: slavio will be used!\n"));
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate /*
9190Sstevel@tonic-gate  * Check the binding name to identify whether it is a South bridge based
9200Sstevel@tonic-gate  * system or not.
9210Sstevel@tonic-gate  */
9220Sstevel@tonic-gate 	} else if (strcmp(ddi_get_name(dip), "pnpALI,1533,0") == 0) {
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_SB;
9250Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_82077;
9260Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_DMA;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9297656SSherry.Moore@Sun.COM 		    (C, "fdattach: southbridge will be used!\n"));
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 		/*
9320Sstevel@tonic-gate 		 * The driver assumes high density characteristics until
9330Sstevel@tonic-gate 		 * the diskette is looked at.
9340Sstevel@tonic-gate 		 */
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_DMA8237;
9370Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	} else if (strcmp(ddi_get_name(dip), "fdthree") == 0) {
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_CHEERIO;
9430Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_82077;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9467656SSherry.Moore@Sun.COM 		    (C, "fdattach: cheerio will be used!\n"));
9470Sstevel@tonic-gate 		/*
9480Sstevel@tonic-gate 		 * The cheerio auxio register should be memory mapped.  The
9490Sstevel@tonic-gate 		 * auxio register on other platforms is shared and mapped
9500Sstevel@tonic-gate 		 * elsewhere in the kernel
9510Sstevel@tonic-gate 		 */
9520Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 2, (caddr_t *)&fdc->c_auxio_reg,
9530Sstevel@tonic-gate 		    0, sizeof (uint_t), &attr, &fdc->c_handlep_aux)) {
9540Sstevel@tonic-gate 			return (DDI_FAILURE);
9550Sstevel@tonic-gate 		}
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 		/*
9580Sstevel@tonic-gate 		 * The driver assumes high density characteristics until
9590Sstevel@tonic-gate 		 * the diskette is looked at.
9600Sstevel@tonic-gate 		 */
9610Sstevel@tonic-gate 		Set_auxio(fdc, AUX_HIGH_DENSITY);
9620Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9637656SSherry.Moore@Sun.COM 		    (C, "fdattach: auxio register 0x%x\n",
9647656SSherry.Moore@Sun.COM 		    *fdc->c_auxio_reg));
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_DMA;
9670Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	if (fdc->c_fdtype == 0) {
9720Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9737656SSherry.Moore@Sun.COM 		    (C, "fdattach: no controller!\n"));
9740Sstevel@tonic-gate 		return (DDI_FAILURE);
9750Sstevel@tonic-gate 	} else {
9760Sstevel@tonic-gate 		return (0);
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate /*
9820Sstevel@tonic-gate  * Register the floppy interrupts
9830Sstevel@tonic-gate  */
9840Sstevel@tonic-gate static int
fd_attach_register_interrupts(dev_info_t * dip,struct fdctlr * fdc,int * hard)9850Sstevel@tonic-gate fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc, int *hard)
9860Sstevel@tonic-gate {
9870Sstevel@tonic-gate 	ddi_iblock_cookie_t  iblock_cookie_soft;
9880Sstevel@tonic-gate 	int status;
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	/*
9910Sstevel@tonic-gate 	 * First call ddi_get_iblock_cookie() to retrieve the
9920Sstevel@tonic-gate 	 * the interrupt block cookie so that the mutexes may
9930Sstevel@tonic-gate 	 * be initialized before adding the interrupt.  If the
9940Sstevel@tonic-gate 	 * mutexes are initialized after adding the interrupt, there
9950Sstevel@tonic-gate 	 * could be a race condition.
9960Sstevel@tonic-gate 	 */
9970Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dip, 0, &fdc->c_block) != DDI_SUCCESS) {
9980Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9997656SSherry.Moore@Sun.COM 		    (C, "fdattach: ddi_get_iblock_cookie failed\n"));
10000Sstevel@tonic-gate 		return (DDI_FAILURE);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/* Initialize high level mutex */
10050Sstevel@tonic-gate 	mutex_init(&fdc->c_hilock, NULL, MUTEX_DRIVER, fdc->c_block);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	/*
10080Sstevel@tonic-gate 	 * Try to register fast trap handler, if unable try standard
10090Sstevel@tonic-gate 	 * interrupt handler, else bad
10100Sstevel@tonic-gate 	 */
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
10130Sstevel@tonic-gate 		if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
10147656SSherry.Moore@Sun.COM 		    fdintr_dma, (caddr_t)0) == DDI_SUCCESS) {
10157656SSherry.Moore@Sun.COM 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10167656SSherry.Moore@Sun.COM 			    (C, "fdattach: standard intr\n"));
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 				/*
10190Sstevel@tonic-gate 				 * When DMA is used, the low level lock
10200Sstevel@tonic-gate 				 * is used in the hard interrupt handler.
10210Sstevel@tonic-gate 				 */
10220Sstevel@tonic-gate 				mutex_init(&fdc->c_lolock, NULL,
10237656SSherry.Moore@Sun.COM 				    MUTEX_DRIVER, fdc->c_block);
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 				*hard = 1;
10260Sstevel@tonic-gate 		} else {
10270Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10287656SSherry.Moore@Sun.COM 			    (C, "fdattach: can't add dma intr\n"));
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 			return (DDI_FAILURE);
10330Sstevel@tonic-gate 		}
10340Sstevel@tonic-gate 	} else {
10350Sstevel@tonic-gate 		/*
10360Sstevel@tonic-gate 		 * Platforms that don't support DMA have both hard
10370Sstevel@tonic-gate 		 * and soft interrupts.
10380Sstevel@tonic-gate 		 */
10390Sstevel@tonic-gate 		if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
10407656SSherry.Moore@Sun.COM 		    fd_intr, (caddr_t)0) == DDI_SUCCESS) {
10417656SSherry.Moore@Sun.COM 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10427656SSherry.Moore@Sun.COM 			    (C, "fdattach: standard intr\n"));
10437656SSherry.Moore@Sun.COM 			*hard = 1;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 			/* fast traps are not enabled */
10460Sstevel@tonic-gate 			fdc->c_fasttrap = 0;
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 		} else {
10490Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10507656SSherry.Moore@Sun.COM 			    (C, "fdattach: can't add intr\n"));
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 			return (DDI_FAILURE);
10550Sstevel@tonic-gate 		}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 		/*
10590Sstevel@tonic-gate 		 * Initialize the soft interrupt handler.  First call
10600Sstevel@tonic-gate 		 * ddi_get_soft_iblock_cookie() so that the mutex may
10610Sstevel@tonic-gate 		 * be initialized before the handler is added.
10620Sstevel@tonic-gate 		 */
10630Sstevel@tonic-gate 		status = ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
10647656SSherry.Moore@Sun.COM 		    &iblock_cookie_soft);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 		if (status != DDI_SUCCESS) {
10680Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10690Sstevel@tonic-gate 			return (DDI_FAILURE);
10700Sstevel@tonic-gate 		}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 		/*
10730Sstevel@tonic-gate 		 * Initialize low level mutex which is used in the soft
10740Sstevel@tonic-gate 		 * interrupt handler
10750Sstevel@tonic-gate 		 */
10760Sstevel@tonic-gate 		mutex_init(&fdc->c_lolock, NULL, MUTEX_DRIVER,
10777656SSherry.Moore@Sun.COM 		    iblock_cookie_soft);
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 		if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &fdc->c_softid,
10807656SSherry.Moore@Sun.COM 		    NULL, NULL,
10817656SSherry.Moore@Sun.COM 		    fd_lointr,
10827656SSherry.Moore@Sun.COM 		    (caddr_t)fdc) != DDI_SUCCESS) {
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10850Sstevel@tonic-gate 			mutex_destroy(&fdc->c_lolock);
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 			return (DDI_FAILURE);
10880Sstevel@tonic-gate 		}
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	fdc->c_intrstat = kstat_create("fd", 0, "fdc0", "controller",
10927656SSherry.Moore@Sun.COM 	    KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
10930Sstevel@tonic-gate 	if (fdc->c_intrstat) {
10940Sstevel@tonic-gate 		fdc->c_hiintct = &KIOIP->intrs[KSTAT_INTR_HARD];
10950Sstevel@tonic-gate 		kstat_install(fdc->c_intrstat);
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	/* condition variable to wait on while an io transaction occurs */
10990Sstevel@tonic-gate 	cv_init(&fdc->c_iocv, NULL, CV_DRIVER, NULL);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	/* condition variable for the csb */
11020Sstevel@tonic-gate 	cv_init(&fdc->c_csbcv, NULL, CV_DRIVER, NULL);
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	/* condition variable for motor on waiting period */
11050Sstevel@tonic-gate 	cv_init(&fdc->c_motoncv, NULL, CV_DRIVER, NULL);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	/* semaphore to serialize opens and closes */
11080Sstevel@tonic-gate 	sema_init(&fdc->c_ocsem, 1, NULL, SEMA_DRIVER, NULL);
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	/* condition variable to wait on suspended floppy controller. */
11110Sstevel@tonic-gate 	cv_init(&fdc->c_suspend_cv, NULL, CV_DRIVER, NULL);
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	return (0);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate /*
11170Sstevel@tonic-gate  * Make sure the drive is present
11180Sstevel@tonic-gate  * 	- acquires the low level lock
11190Sstevel@tonic-gate  */
11200Sstevel@tonic-gate static int
fd_attach_check_drive(struct fdctlr * fdc)11210Sstevel@tonic-gate fd_attach_check_drive(struct fdctlr *fdc)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate 	int tmp_fderrlevel;
11240Sstevel@tonic-gate 	int unit = fdc->c_un->un_unit_no;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
11277656SSherry.Moore@Sun.COM 	    (C, "fd_attach_check_drive\n"));
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
11310Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	/* insure that the eject line is reset */
11340Sstevel@tonic-gate 	case FDCTYPE_82077:
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 		/*
11370Sstevel@tonic-gate 		 * Everything but the motor enable, drive select,
11380Sstevel@tonic-gate 		 * and reset bits are turned off.  These three
11390Sstevel@tonic-gate 		 * bits remain as they are.
11400Sstevel@tonic-gate 		 */
11410Sstevel@tonic-gate 		/* LINTED */
11420Sstevel@tonic-gate 		Set_dor(fdc, ~((MOTEN(unit))|DRVSEL|RESET), 0);
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
11457656SSherry.Moore@Sun.COM 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 		drv_usecwait(5);
11480Sstevel@tonic-gate 		if (unit == 0) {
11490Sstevel@tonic-gate 			/* LINTED */
11500Sstevel@tonic-gate 			Set_dor(fdc, RESET|DRVSEL, 1);
11510Sstevel@tonic-gate 		} else {
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 			/* LINTED */
11540Sstevel@tonic-gate 			Set_dor(fdc, DRVSEL, 0);
11550Sstevel@tonic-gate 			/* LINTED */
11560Sstevel@tonic-gate 			Set_dor(fdc, RESET, 1);
11570Sstevel@tonic-gate 		}
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 		drv_usecwait(5);
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
11627656SSherry.Moore@Sun.COM 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 		if (!((fdc->c_fdtype & FDCTYPE_CHEERIO) ||
11657656SSherry.Moore@Sun.COM 		    (fdc->c_fdtype & FDCTYPE_SB))) {
11660Sstevel@tonic-gate 			set_auxioreg(AUX_TC4M, 0);
11670Sstevel@tonic-gate 		}
11680Sstevel@tonic-gate 		break;
11690Sstevel@tonic-gate 	default:
11700Sstevel@tonic-gate 		break;
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	fdgetcsb(fdc);
11750Sstevel@tonic-gate 	if (fdreset(fdc) != 0) {
11760Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
11770Sstevel@tonic-gate 		return (DDI_FAILURE);
11780Sstevel@tonic-gate 	}
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	/* check for drive present */
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	tmp_fderrlevel = fderrlevel;
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	fderrlevel = FDEP_LMAX;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
11897656SSherry.Moore@Sun.COM 	    (C, "fdattach: call fdrecalseek\n"));
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	/* Make sure the drive is present */
11920Sstevel@tonic-gate 	if (fdrecalseek(fdc, unit, -1, 0) != 0) {
11930Sstevel@tonic-gate 		timeout_id_t timeid = fdc->c_mtimeid;
11940Sstevel@tonic-gate 		fderrlevel = tmp_fderrlevel;
11950Sstevel@tonic-gate 		fdc->c_mtimeid = 0;
11960Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 		/* Do not hold the mutex over the call to untimeout */
12000Sstevel@tonic-gate 		if (timeid) {
12010Sstevel@tonic-gate 			(void) untimeout(timeid);
12020Sstevel@tonic-gate 		}
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_ATTA,
12050Sstevel@tonic-gate 		    (C, "fd_attach: no drive?\n"));
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 		return (DDI_FAILURE);
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	fderrlevel = tmp_fderrlevel;
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	fdselect(fdc, unit, 0);    /* deselect drive zero (used in fdreset) */
12130Sstevel@tonic-gate 	fdretcsb(fdc);
12140Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	return (0);
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate /*
12200Sstevel@tonic-gate  * Clean up routine used by fd_detach and fd_attach
12210Sstevel@tonic-gate  *
12220Sstevel@tonic-gate  * Note: if the soft id is non-zero, then ddi_add_softintr() completed
12230Sstevel@tonic-gate  * successfully.  I can not make the same assumption about the iblock_cookie
12240Sstevel@tonic-gate  * for the high level interrupt handler.  So, the hard parameter indicates
12250Sstevel@tonic-gate  * whether or not a high level interrupt handler has been added.
12260Sstevel@tonic-gate  *
12270Sstevel@tonic-gate  * If the locks parameter is nonzero, then all mutexes, semaphores and
12280Sstevel@tonic-gate  * condition variables will be destroyed.
12290Sstevel@tonic-gate  *
12300Sstevel@tonic-gate  * Does not assume the low level mutex is held.
12310Sstevel@tonic-gate  *
12320Sstevel@tonic-gate  */
12330Sstevel@tonic-gate static void
fd_cleanup(dev_info_t * dip,struct fdctlr * fdc,int hard,int locks)12340Sstevel@tonic-gate fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard, int locks)
12350Sstevel@tonic-gate {
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
12397656SSherry.Moore@Sun.COM 	    (C, "fd_cleanup instance: %d ctlr: 0x%p\n",
12407656SSherry.Moore@Sun.COM 	    ddi_get_instance(dip), (void *)fdc));
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	if (fdc == NULL) {
12440Sstevel@tonic-gate 		return;
12450Sstevel@tonic-gate 	}
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	/*
12480Sstevel@tonic-gate 	 * Remove interrupt handlers first before anything else
12490Sstevel@tonic-gate 	 * is deallocated.
12500Sstevel@tonic-gate 	 */
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	/* Remove hard interrupt if one is registered */
12530Sstevel@tonic-gate 	if (hard) {
12540Sstevel@tonic-gate 		ddi_remove_intr(dip, (uint_t)0, fdc->c_block);
12550Sstevel@tonic-gate 	}
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	/* Remove soft interrupt if one is registered */
12580Sstevel@tonic-gate 	if (fdc->c_softid != NULL)
12590Sstevel@tonic-gate 		ddi_remove_softintr(fdc->c_softid);
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	/* Remove timers */
12630Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_82077) {
12640Sstevel@tonic-gate 		if (fdc->c_mtimeid)
12650Sstevel@tonic-gate 			(void) untimeout(fdc->c_mtimeid);
12660Sstevel@tonic-gate 		/*
12670Sstevel@tonic-gate 		 * Need to turn off motor (includes select/LED for South Bridge
12680Sstevel@tonic-gate 		 * chipset) just in case it was on when timer was removed
12690Sstevel@tonic-gate 		 */
12700Sstevel@tonic-gate 		fdmotoff(fdc);
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate 	if (fdc->c_timeid)
12730Sstevel@tonic-gate 		(void) untimeout(fdc->c_timeid);
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	/* Remove memory handles */
12770Sstevel@tonic-gate 	if (fdc->c_handlep_cont)
12780Sstevel@tonic-gate 		ddi_regs_map_free(&fdc->c_handlep_cont);
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	if (fdc->c_handlep_aux)
12810Sstevel@tonic-gate 		ddi_regs_map_free(&fdc->c_handlep_aux);
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	if (fdc->c_handlep_dma)
12840Sstevel@tonic-gate 		ddi_regs_map_free(&fdc->c_handlep_dma);
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	if (fdc->c_dma_buf_handle != NULL)
12870Sstevel@tonic-gate 		ddi_dma_mem_free(&fdc->c_dma_buf_handle);
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	if (fdc->c_dmahandle != NULL)
12900Sstevel@tonic-gate 		ddi_dma_free_handle(&fdc->c_dmahandle);
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	/* Remove all minor nodes */
12940Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	/* Remove unit structure if one exists */
12990Sstevel@tonic-gate 	if (fdc->c_un != (struct fdunit *)NULL) {
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 		ASSERT(!mutex_owned(&fdc->c_lolock));
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 		if (fdc->c_un->un_iostat)
13040Sstevel@tonic-gate 			kstat_delete(fdc->c_un->un_iostat);
13050Sstevel@tonic-gate 		fdc->c_un->un_iostat = NULL;
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 		if (fdc->c_un->un_chars)
13080Sstevel@tonic-gate 			kmem_free(fdc->c_un->un_chars, sizeof (struct fd_char));
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 		if (fdc->c_un->un_drive)
13110Sstevel@tonic-gate 			kmem_free(fdc->c_un->un_drive,
13120Sstevel@tonic-gate 			    sizeof (struct fd_drive));
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 		kmem_free((caddr_t)fdc->c_un, sizeof (struct fdunit));
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	if (fdc->c_intrstat) {
13180Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
13197656SSherry.Moore@Sun.COM 		    (C, "fd_cleanup: delete intrstat\n"));
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 		kstat_delete(fdc->c_intrstat);
13220Sstevel@tonic-gate 	}
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	fdc->c_intrstat = NULL;
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	if (locks) {
13270Sstevel@tonic-gate 		cv_destroy(&fdc->c_iocv);
13280Sstevel@tonic-gate 		cv_destroy(&fdc->c_csbcv);
13290Sstevel@tonic-gate 		cv_destroy(&fdc->c_motoncv);
13300Sstevel@tonic-gate 		cv_destroy(&fdc->c_suspend_cv);
13310Sstevel@tonic-gate 		sema_destroy(&fdc->c_ocsem);
13320Sstevel@tonic-gate 		mutex_destroy(&fdc->c_hilock);
13330Sstevel@tonic-gate 		mutex_destroy(&fdc->c_lolock);
13340Sstevel@tonic-gate 	}
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	fdctlrs = fdc->c_next;
13380Sstevel@tonic-gate 	kmem_free(fdc, sizeof (*fdc));
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate static int
fd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)13450Sstevel@tonic-gate fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
13460Sstevel@tonic-gate {
13470Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
13480Sstevel@tonic-gate 	struct fdctlr *fdc = fd_getctlr(instance << FDINSTSHIFT);
13490Sstevel@tonic-gate 	timeout_id_t c_mtimeid;
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_detach\n"));
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	switch (cmd) {
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	case DDI_DETACH:
13560Sstevel@tonic-gate 		/*
13570Sstevel@tonic-gate 		 * The hard parameter is set to 1.  If detach is called, then
13580Sstevel@tonic-gate 		 * attach must have passed meaning that the high level
13590Sstevel@tonic-gate 		 * interrupt handler was successfully added.
13600Sstevel@tonic-gate 		 * Similarly, the locks parameter is also set to 1.
13610Sstevel@tonic-gate 		 */
13620Sstevel@tonic-gate 		fd_cleanup(dip, fdc, 1, 1);
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 		return (DDI_SUCCESS);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	case DDI_SUSPEND:
13690Sstevel@tonic-gate 		if (!fdc)
13700Sstevel@tonic-gate 			return (DDI_FAILURE);
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
13740Sstevel@tonic-gate 		fdgetcsb(fdc);	/* Wait for I/O to finish */
13750Sstevel@tonic-gate 		c_mtimeid = fdc->c_mtimeid;
13760Sstevel@tonic-gate 		fdretcsb(fdc);
13770Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 		(void) untimeout(c_mtimeid);
13800Sstevel@tonic-gate 		/*
13810Sstevel@tonic-gate 		 * After suspend, the system could be powered off.
13820Sstevel@tonic-gate 		 * When it is later powered on the southbridge floppy
13830Sstevel@tonic-gate 		 * controller will tristate the interrupt line causing
13840Sstevel@tonic-gate 		 * continuous dma interrupts.
13850Sstevel@tonic-gate 		 * To avoid getting continuous fd interrupts we will remove the
13860Sstevel@tonic-gate 		 * dma interrupt handler installed. We will re-install the
13870Sstevel@tonic-gate 		 * handler when we RESUME.
13880Sstevel@tonic-gate 		 */
13890Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB)
13900Sstevel@tonic-gate 			ddi_remove_intr(dip, 0, fdc->c_block);
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 		fdc->c_un->un_state = FD_STATE_SUSPENDED;
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 		return (DDI_SUCCESS);
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	default:
13970Sstevel@tonic-gate 		return (DDI_FAILURE);
13980Sstevel@tonic-gate 	}
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate /* ARGSUSED */
14020Sstevel@tonic-gate static int
fd_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)14030Sstevel@tonic-gate fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
14040Sstevel@tonic-gate {
14050Sstevel@tonic-gate 	register struct fdctlr *fdc;
14060Sstevel@tonic-gate 	register int error;
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	switch (infocmd) {
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
14110Sstevel@tonic-gate 		if ((fdc = fd_getctlr((dev_t)arg)) == NULL) {
14120Sstevel@tonic-gate 			error = DDI_FAILURE;
14130Sstevel@tonic-gate 		} else {
14140Sstevel@tonic-gate 			*result = fdc->c_dip;
14150Sstevel@tonic-gate 			error = DDI_SUCCESS;
14160Sstevel@tonic-gate 		}
14170Sstevel@tonic-gate 		break;
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
14200Sstevel@tonic-gate 		*result = 0;
14210Sstevel@tonic-gate 		error = DDI_SUCCESS;
14220Sstevel@tonic-gate 		break;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	default:
14250Sstevel@tonic-gate 		error = DDI_FAILURE;
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate 	return (error);
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate /*
14310Sstevel@tonic-gate  * property operation routine.  return the number of blocks for the partition
14320Sstevel@tonic-gate  * in question or forward the request to the property facilities.
14330Sstevel@tonic-gate  */
14340Sstevel@tonic-gate static int
fd_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)14350Sstevel@tonic-gate fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
14360Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
14370Sstevel@tonic-gate {
14380Sstevel@tonic-gate 	struct fdunit	*un;
14390Sstevel@tonic-gate 	struct fdctlr	*fdc;
14400Sstevel@tonic-gate 	uint64_t	nblocks64;
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	/*
14430Sstevel@tonic-gate 	 * Our dynamic properties are all device specific and size oriented.
14440Sstevel@tonic-gate 	 * Requests issued under conditions where size is valid are passed
14450Sstevel@tonic-gate 	 * to ddi_prop_op_nblocks with the size information, otherwise the
14460Sstevel@tonic-gate 	 * request is passed to ddi_prop_op.
14470Sstevel@tonic-gate 	 */
14480Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY) {
14490Sstevel@tonic-gate pass:  		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
14500Sstevel@tonic-gate 		    name, valuep, lengthp));
14510Sstevel@tonic-gate 	} else {
14520Sstevel@tonic-gate 		fdc = fd_getctlr(dev);
14530Sstevel@tonic-gate 		if (fdc == NULL)
14540Sstevel@tonic-gate 			goto pass;
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 		/* we have size if diskette opened and label read */
14570Sstevel@tonic-gate 		un = fdc->c_un;
14580Sstevel@tonic-gate 		if ((un == NULL) || !fd_unit_is_open(fdc->c_un))
14590Sstevel@tonic-gate 			goto pass;
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 		/* get nblocks value */
14620Sstevel@tonic-gate 		nblocks64 = (ulong_t)
14630Sstevel@tonic-gate 		    un->un_label.dkl_map[FDPARTITION(dev)].dkl_nblk;
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 		return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
14660Sstevel@tonic-gate 		    name, valuep, lengthp, nblocks64));
14670Sstevel@tonic-gate 	}
14680Sstevel@tonic-gate }
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate /* ARGSUSED3 */
14710Sstevel@tonic-gate static int
fd_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)14720Sstevel@tonic-gate fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	dev_t dev;
14750Sstevel@tonic-gate 	int  part;
14760Sstevel@tonic-gate 	struct fdctlr *fdc;
14770Sstevel@tonic-gate 	struct fdunit *un;
14780Sstevel@tonic-gate 	struct dk_map32 *dkm;
14790Sstevel@tonic-gate 	uchar_t	pbit;
14800Sstevel@tonic-gate 	int	err, part_is_open;
14810Sstevel@tonic-gate 	int 	unit;
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	dev = *devp;
14840Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
14850Sstevel@tonic-gate 	if ((fdc == NULL) || ((un = fdc->c_un) == NULL)) {
14860Sstevel@tonic-gate 		return (ENXIO);
14870Sstevel@tonic-gate 	}
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	/*
14920Sstevel@tonic-gate 	 * Serialize opens/closes
14930Sstevel@tonic-gate 	 */
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	sema_p(&fdc->c_ocsem);
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 	/* check partition */
14980Sstevel@tonic-gate 	part = FDPARTITION(dev);
14990Sstevel@tonic-gate 	pbit = 1 << part;
15000Sstevel@tonic-gate 	dkm = &un->un_label.dkl_map[part];
15010Sstevel@tonic-gate 	if (dkm->dkl_nblk == 0) {
15020Sstevel@tonic-gate 		sema_v(&fdc->c_ocsem);
15030Sstevel@tonic-gate 		return (ENXIO);
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
15070Sstevel@tonic-gate 	    (C, "fdopen: ctlr %d unit %d part %d\n",
15080Sstevel@tonic-gate 	    ddi_get_instance(fdc->c_dip), unit, part));
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
15110Sstevel@tonic-gate 	    (C, "fdopen: flag 0x%x", flag));
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	/*
15150Sstevel@tonic-gate 	 * Insure that drive is present with a recalibrate on first open.
15160Sstevel@tonic-gate 	 */
15170Sstevel@tonic-gate 	(void) pm_busy_component(fdc->c_dip, 0);
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
15240Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
15250Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
15267656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
15270Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
15287656SSherry.Moore@Sun.COM 			    failed. \n"));
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 				sema_v(&fdc->c_ocsem);
15310Sstevel@tonic-gate 				(void) pm_idle_component(fdc->c_dip, 0);
15320Sstevel@tonic-gate 				return (EIO);
15330Sstevel@tonic-gate 		}
15340Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
15350Sstevel@tonic-gate 	}
15360Sstevel@tonic-gate 	if (fd_unit_is_open(un) == 0) {
15370Sstevel@tonic-gate 		fdgetcsb(fdc);
15380Sstevel@tonic-gate 		/*
15390Sstevel@tonic-gate 		 * no check changed!
15400Sstevel@tonic-gate 		 */
15410Sstevel@tonic-gate 		err = fdrecalseek(fdc, unit, -1, 0);
15420Sstevel@tonic-gate 		fdretcsb(fdc);
15430Sstevel@tonic-gate 		if (err) {
15440Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_OPEN,
15450Sstevel@tonic-gate 			    (C, "fd%d: drive not ready\n", 0));
15460Sstevel@tonic-gate 			/* deselect drv on last close */
15470Sstevel@tonic-gate 			fdselect(fdc, unit, 0);
15480Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
15490Sstevel@tonic-gate 			sema_v(&fdc->c_ocsem);
15500Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
15510Sstevel@tonic-gate 			return (EIO);
15520Sstevel@tonic-gate 		}
15530Sstevel@tonic-gate 	}
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 	/*
15560Sstevel@tonic-gate 	 * Check for previous exclusive open, or trying to exclusive open
15570Sstevel@tonic-gate 	 */
15580Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
15590Sstevel@tonic-gate 		part_is_open = (un->un_lyropen[part] != 0);
15600Sstevel@tonic-gate 	} else {
15610Sstevel@tonic-gate 		part_is_open = fd_part_is_open(un, part);
15620Sstevel@tonic-gate 	}
15630Sstevel@tonic-gate 	if ((un->un_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
15640Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
15650Sstevel@tonic-gate 		sema_v(&fdc->c_ocsem);
15660Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_OPEN, (C, "fd:just return\n"));
15670Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
15680Sstevel@tonic-gate 		return (EBUSY);
15690Sstevel@tonic-gate 	}
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	/* don't attempt access, just return successfully */
15720Sstevel@tonic-gate 	if (flag & (FNDELAY | FNONBLOCK)) {
15730Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_OPEN,
15740Sstevel@tonic-gate 		    (C, "fd: return busy..\n"));
15750Sstevel@tonic-gate 		goto out;
15760Sstevel@tonic-gate 	}
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	fdc->c_csb.csb_unit = (uchar_t)unit;
15790Sstevel@tonic-gate 	if (fdgetlabel(fdc, unit)) {
15800Sstevel@tonic-gate 		/* didn't find label (couldn't read anything) */
15810Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_OPEN,
15820Sstevel@tonic-gate 		    (C,
15830Sstevel@tonic-gate 		    "fd%d: unformatted diskette or no diskette in the drive\n",
15840Sstevel@tonic-gate 		    0));
15850Sstevel@tonic-gate 		if (fd_unit_is_open(un) == 0) {
15860Sstevel@tonic-gate 			/* deselect drv on last close */
15870Sstevel@tonic-gate 			fdselect(fdc, unit, 0);
15880Sstevel@tonic-gate 		}
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
15910Sstevel@tonic-gate 		sema_v(&fdc->c_ocsem);
15920Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
15930Sstevel@tonic-gate 		return (EIO);
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	/*
15970Sstevel@tonic-gate 	 * if opening for writing, check write protect on diskette
15980Sstevel@tonic-gate 	 */
15990Sstevel@tonic-gate 	if (flag & FWRITE) {
16000Sstevel@tonic-gate 		fdgetcsb(fdc);
16010Sstevel@tonic-gate 		err = fdsensedrv(fdc, unit) & WP_SR3;
16020Sstevel@tonic-gate 		fdretcsb(fdc);
16030Sstevel@tonic-gate 		if (err) {
16040Sstevel@tonic-gate 			if (fd_unit_is_open(un) == 0)
16050Sstevel@tonic-gate 				fdselect(fdc, unit, 0);
16060Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
16070Sstevel@tonic-gate 			sema_v(&fdc->c_ocsem);
16080Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
16090Sstevel@tonic-gate 			return (EROFS);
16100Sstevel@tonic-gate 		}
16110Sstevel@tonic-gate 	}
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate out:
16140Sstevel@tonic-gate 	/*
16150Sstevel@tonic-gate 	 * mark open as having succeeded
16160Sstevel@tonic-gate 	 */
16170Sstevel@tonic-gate 	if (flag & FEXCL) {
16180Sstevel@tonic-gate 		un->un_exclmask |= pbit;
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
16210Sstevel@tonic-gate 		un->un_lyropen[part]++;
16220Sstevel@tonic-gate 	} else {
16230Sstevel@tonic-gate 		un->un_regopen[otyp] |= pbit;
16240Sstevel@tonic-gate 	}
16250Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
16260Sstevel@tonic-gate 	sema_v(&fdc->c_ocsem);
16270Sstevel@tonic-gate 	(void) pm_idle_component(fdc->c_dip, 0);
16280Sstevel@tonic-gate 	return (0);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate /*
16310Sstevel@tonic-gate  * fd_part_is_open
16320Sstevel@tonic-gate  *	return 1 if the partition is open
16330Sstevel@tonic-gate  *	return 0 otherwise
16340Sstevel@tonic-gate  */
16350Sstevel@tonic-gate static int
fd_part_is_open(struct fdunit * un,int part)16360Sstevel@tonic-gate fd_part_is_open(struct fdunit *un, int part)
16370Sstevel@tonic-gate {
16380Sstevel@tonic-gate 	int i;
16390Sstevel@tonic-gate 	for (i = 0; i < OTYPCNT - 1; i++)
16400Sstevel@tonic-gate 		if (un->un_regopen[i] & (1 << part))
16410Sstevel@tonic-gate 			return (1);
16420Sstevel@tonic-gate 	return (0);
16430Sstevel@tonic-gate }
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate /* ARGSUSED */
16470Sstevel@tonic-gate static int
fd_close(dev_t dev,int flag,int otyp,cred_t * cred_p)16480Sstevel@tonic-gate fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
16490Sstevel@tonic-gate {
16500Sstevel@tonic-gate 	int unit, part_is_closed, part;
16510Sstevel@tonic-gate 	register struct fdctlr *fdc;
16520Sstevel@tonic-gate 	register struct fdunit *un;
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
16550Sstevel@tonic-gate 	if (!fdc || !(un = fdc->c_un))
16560Sstevel@tonic-gate 		return (ENXIO);
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
16600Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CLOS, (C, "fd_close\n"));
16610Sstevel@tonic-gate 	part = FDPARTITION(dev);
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 	sema_p(&fdc->c_ocsem);
16640Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
16670Sstevel@tonic-gate 		un->un_lyropen[part]--;
16680Sstevel@tonic-gate 		part_is_closed = (un->un_lyropen[part] == 0);
16690Sstevel@tonic-gate 	} else {
16700Sstevel@tonic-gate 		un->un_regopen[otyp] &= ~(1<<part);
16710Sstevel@tonic-gate 		part_is_closed = 1;
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 	if (part_is_closed)
16740Sstevel@tonic-gate 		un->un_exclmask &= ~(1<<part);
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 	if (fd_unit_is_open(un) == 0) {
16770Sstevel@tonic-gate 		/* deselect drive on last close */
16780Sstevel@tonic-gate 		fdselect(fdc, unit, 0);
16790Sstevel@tonic-gate 		un->un_flags &= ~FDUNIT_CHANGED;
16800Sstevel@tonic-gate 	}
16810Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
16820Sstevel@tonic-gate 	sema_v(&fdc->c_ocsem);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	return (0);
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate /*
16880Sstevel@tonic-gate  * fd_strategy
16890Sstevel@tonic-gate  *	checks operation, hangs buf struct off fdctlr, calls fdstart
16900Sstevel@tonic-gate  *	if not already busy.  Note that if we call start, then the operation
16910Sstevel@tonic-gate  *	will already be done on return (start sleeps).
16920Sstevel@tonic-gate  */
16930Sstevel@tonic-gate static int
fd_strategy(register struct buf * bp)16940Sstevel@tonic-gate fd_strategy(register struct buf *bp)
16950Sstevel@tonic-gate {
16960Sstevel@tonic-gate 	struct fdctlr *fdc;
16970Sstevel@tonic-gate 	struct fdunit *un;
16980Sstevel@tonic-gate 	uint_t	phys_blkno;
16990Sstevel@tonic-gate 	struct dk_map32 *dkm;
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_STRA,
17020Sstevel@tonic-gate 	    (C, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
17030Sstevel@tonic-gate 	    (void *)bp, bp->b_edev));
17040Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_STRA,
17050Sstevel@tonic-gate 	    (C, "b_blkno=%x b_flags=%x b_count=%x\n",
17060Sstevel@tonic-gate 	    (int)bp->b_blkno, bp->b_flags, (int)bp->b_bcount));
17070Sstevel@tonic-gate 	fdc = fd_getctlr(bp->b_edev);
17080Sstevel@tonic-gate 	un = fdc->c_un;
17090Sstevel@tonic-gate 	dkm = &un->un_label.dkl_map[FDPARTITION(bp->b_edev)];
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	/*
17120Sstevel@tonic-gate 	 * If it's medium density and the block no. isn't a multiple
17130Sstevel@tonic-gate 	 * of 1K, then return an error.
17140Sstevel@tonic-gate 	 */
17150Sstevel@tonic-gate 	if (un->un_chars->fdc_medium) {
17160Sstevel@tonic-gate 		phys_blkno = (uint_t)bp->b_blkno >> 1;
17170Sstevel@tonic-gate 		if (bp->b_blkno & 1) {
17180Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_STRA,
17190Sstevel@tonic-gate 			    (C, "b_blkno=0x%lx is not 1k aligned\n",
17200Sstevel@tonic-gate 			    (long)bp->b_blkno));
17210Sstevel@tonic-gate 			bp->b_error = EINVAL;
17220Sstevel@tonic-gate 			bp->b_resid = bp->b_bcount;
17230Sstevel@tonic-gate 			bp->b_flags |= B_ERROR;
17240Sstevel@tonic-gate 			biodone(bp);
17250Sstevel@tonic-gate 			return (0);
17260Sstevel@tonic-gate 		}
17270Sstevel@tonic-gate 	} else {
17280Sstevel@tonic-gate 		phys_blkno = (uint_t)bp->b_blkno;
17290Sstevel@tonic-gate 	}
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	/* If the block number is past the end, return an error */
17330Sstevel@tonic-gate 	if ((phys_blkno > dkm->dkl_nblk)) {
17340Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
17350Sstevel@tonic-gate 		    (C, "fd%d: block %ld is past the end! (nblk=%d)\n",
17360Sstevel@tonic-gate 		    0, (long)bp->b_blkno, dkm->dkl_nblk));
17370Sstevel@tonic-gate 		bp->b_error = ENOSPC;
17380Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
17390Sstevel@tonic-gate 		bp->b_flags |= B_ERROR;
17400Sstevel@tonic-gate 		biodone(bp);
17410Sstevel@tonic-gate 		return (0);
17420Sstevel@tonic-gate 	}
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	/* if at end of file, skip out now */
17450Sstevel@tonic-gate 	if (phys_blkno == dkm->dkl_nblk) {
17460Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_STRA,
17470Sstevel@tonic-gate 		    (C, "b_blkno is at the end!\n"));
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 		if ((bp->b_flags & B_READ) == 0) {
17500Sstevel@tonic-gate 			/* a write needs to get an error! */
17510Sstevel@tonic-gate 			bp->b_error = ENOSPC;
17520Sstevel@tonic-gate 			bp->b_flags |= B_ERROR;
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRA,
17550Sstevel@tonic-gate 			    (C, "block is at end and this is a write\n"));
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 		}
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
17600Sstevel@tonic-gate 		biodone(bp);
17610Sstevel@tonic-gate 		return (0);
17620Sstevel@tonic-gate 	}
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	/* if operation not a multiple of sector size, is error! */
17650Sstevel@tonic-gate 	if (bp->b_bcount % un->un_chars->fdc_sec_size)	{
17660Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
17670Sstevel@tonic-gate 		    (C, "fd%d: requested transfer size(0x%lx) is not"
17687656SSherry.Moore@Sun.COM 		    " multiple of sector size(0x%x)\n", 0,
17697656SSherry.Moore@Sun.COM 		    bp->b_bcount, un->un_chars->fdc_sec_size));
17700Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
17710Sstevel@tonic-gate 		    (C, "	b_blkno=0x%lx b_flags=0x%x\n",
17720Sstevel@tonic-gate 		    (long)bp->b_blkno, bp->b_flags));
17730Sstevel@tonic-gate 		bp->b_error = EINVAL;
17740Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
17750Sstevel@tonic-gate 		bp->b_flags |= B_ERROR;
17760Sstevel@tonic-gate 		biodone(bp);
17770Sstevel@tonic-gate 		return (0);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	}
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	/*
17820Sstevel@tonic-gate 	 * Put the buf request in the controller's queue, FIFO.
17830Sstevel@tonic-gate 	 */
17840Sstevel@tonic-gate 	bp->av_forw = 0;
17850Sstevel@tonic-gate 	sema_p(&fdc->c_ocsem);
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	(void) pm_busy_component(fdc->c_dip, 0);
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
17940Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
17950Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
17967656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
17977656SSherry.Moore@Sun.COM 			sema_v(&fdc->c_ocsem);
17987656SSherry.Moore@Sun.COM 			(void) pm_idle_component(fdc->c_dip, 0);
17997656SSherry.Moore@Sun.COM 			bp->b_error = EIO;
18007656SSherry.Moore@Sun.COM 			bp->b_resid = bp->b_bcount;
18017656SSherry.Moore@Sun.COM 			bp->b_flags |= B_ERROR;
18027656SSherry.Moore@Sun.COM 			biodone(bp);
18037656SSherry.Moore@Sun.COM 			return (0);
18040Sstevel@tonic-gate 		} else {
18050Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
18060Sstevel@tonic-gate 		}
18070Sstevel@tonic-gate 	}
18080Sstevel@tonic-gate 	if (un->un_iostat) {
18090Sstevel@tonic-gate 		kstat_waitq_enter(KIOSP);
18100Sstevel@tonic-gate 	}
18110Sstevel@tonic-gate 	if (fdc->c_actf)
18120Sstevel@tonic-gate 		fdc->c_actl->av_forw = bp;
18130Sstevel@tonic-gate 	else
18140Sstevel@tonic-gate 		fdc->c_actf = bp;
18150Sstevel@tonic-gate 	fdc->c_actl = bp;
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	/* call fdstart to start the transfer */
18190Sstevel@tonic-gate 	fdstart(fdc);
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
18220Sstevel@tonic-gate 	sema_v(&fdc->c_ocsem);
18230Sstevel@tonic-gate 	(void) pm_idle_component(fdc->c_dip, 0);
18240Sstevel@tonic-gate 	return (0);
18250Sstevel@tonic-gate }
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate /* ARGSUSED2 */
18280Sstevel@tonic-gate static int
fd_read(dev_t dev,struct uio * uio,cred_t * cred_p)18290Sstevel@tonic-gate fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
18300Sstevel@tonic-gate {
18310Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_read\n"));
18320Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
18330Sstevel@tonic-gate }
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate /* ARGSUSED2 */
18360Sstevel@tonic-gate static int
fd_write(dev_t dev,struct uio * uio,cred_t * cred_p)18370Sstevel@tonic-gate fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
18380Sstevel@tonic-gate {
18390Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_write\n"));
18400Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate static void
fdmotoff(void * arg)18440Sstevel@tonic-gate fdmotoff(void *arg)
18450Sstevel@tonic-gate {
18460Sstevel@tonic-gate 	struct fdctlr *fdc = arg;
18470Sstevel@tonic-gate 	int unit = fdc->c_un->un_unit_no;
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	/* Just return if we're about to call untimeout */
18520Sstevel@tonic-gate 	if (fdc->c_mtimeid == 0) {
18530Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
18540Sstevel@tonic-gate 		return;
18550Sstevel@tonic-gate 	}
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_MOFF, (C, "fdmotoff\n"));
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	fdc->c_mtimeid = 0;
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	if (!(Msr(fdc) & CB) && (Dor(fdc) & (MOTEN(unit)))) {
18620Sstevel@tonic-gate 		/* LINTED */
18630Sstevel@tonic-gate 		Set_dor(fdc, MOTEN(unit), 0);
18640Sstevel@tonic-gate 	}
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
18670Sstevel@tonic-gate }
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate /* ARGSUSED */
18700Sstevel@tonic-gate static int
fd_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)18710Sstevel@tonic-gate fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
18720Sstevel@tonic-gate 	cred_t *cred_p, int *rval_p)
18730Sstevel@tonic-gate {
18740Sstevel@tonic-gate 	union {
18750Sstevel@tonic-gate 		struct dk_cinfo dki;
18760Sstevel@tonic-gate 		struct dk_geom dkg;
18770Sstevel@tonic-gate 		struct dk_allmap32 dka;
18780Sstevel@tonic-gate 		struct fd_char fdchar;
18790Sstevel@tonic-gate 		struct fd_drive drvchar;
18800Sstevel@tonic-gate 		int	temp;
18810Sstevel@tonic-gate 	} cpy;
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	struct vtoc	vtoc;
18840Sstevel@tonic-gate 	struct fdunit *un;
18850Sstevel@tonic-gate 	struct fdctlr *fdc;
18860Sstevel@tonic-gate 	int unit, dkunit;
18870Sstevel@tonic-gate 	int err = 0;
18880Sstevel@tonic-gate 	uint_t	sec_size;
18890Sstevel@tonic-gate 	enum dkio_state state;
18900Sstevel@tonic-gate 	int	transfer_rate;
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
18930Sstevel@tonic-gate 	    (C, "fd_ioctl: cmd 0x%x, arg 0x%lx\n", cmd, (long)arg));
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	/* The minor number should always be 0 */
18960Sstevel@tonic-gate 	if (FDUNIT(dev) != 0)
18970Sstevel@tonic-gate 		return (ENXIO);
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
19000Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
19010Sstevel@tonic-gate 	un = fdc->c_un;
19020Sstevel@tonic-gate 	sec_size = un->un_chars->fdc_sec_size;
19030Sstevel@tonic-gate 	bzero(&cpy, sizeof (cpy));
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 	switch (cmd) {
19060Sstevel@tonic-gate 	case DKIOCINFO:
19070Sstevel@tonic-gate 		cpy.dki.dki_addr = 0;
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 		/*
19100Sstevel@tonic-gate 		 * The meaning of the dki_slave and dki_unit fields
19110Sstevel@tonic-gate 		 * is unclear.  The sparc floppy driver follows the same
19120Sstevel@tonic-gate 		 * convention as sd.c in that the instance number is
19130Sstevel@tonic-gate 		 * returned in the dki_cnum field.  The dki_slave field is
19140Sstevel@tonic-gate 		 * ignored.
19150Sstevel@tonic-gate 		 *
19160Sstevel@tonic-gate 		 * The dki_cnum contains the controller instance
19170Sstevel@tonic-gate 		 * and its value can be any positive number. Even
19180Sstevel@tonic-gate 		 * though currently Sparc platforms only support
19190Sstevel@tonic-gate 		 * one controller, the controller instance number
19200Sstevel@tonic-gate 		 * can be any number since it is assigned by the
19210Sstevel@tonic-gate 		 * system depending on the device properties.
19220Sstevel@tonic-gate 		 */
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 		cpy.dki.dki_cnum = FDCTLR(dev);
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 		/*
19270Sstevel@tonic-gate 		 * Sparc platforms support only one floppy drive.
19280Sstevel@tonic-gate 		 * The device node for the controller is the same as
19290Sstevel@tonic-gate 		 * the device node for the drive.  The x86 driver is
19300Sstevel@tonic-gate 		 * different in that it has a node for the controller
19310Sstevel@tonic-gate 		 * and a child node for each drive. Since Sparc supports
19320Sstevel@tonic-gate 		 * only one drive, the unit number will always be zero.
19330Sstevel@tonic-gate 		 */
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 		cpy.dki.dki_unit = FDUNIT(dev);
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 		/*
19380Sstevel@tonic-gate 		 * The meaning of the dki_slave field is unclear.
19390Sstevel@tonic-gate 		 * So, I will leave it set to 0.
19400Sstevel@tonic-gate 		 */
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 		cpy.dki.dki_slave = 0;
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 		cpy.dki.dki_ctype = (ushort_t)-1;
19450Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_82077)
19460Sstevel@tonic-gate 			cpy.dki.dki_ctype = DKC_INTEL82077;
19470Sstevel@tonic-gate 		cpy.dki.dki_flags = DKI_FMTTRK;
19480Sstevel@tonic-gate 		cpy.dki.dki_partition = FDPARTITION(dev);
19490Sstevel@tonic-gate 		cpy.dki.dki_maxtransfer = maxphys / DEV_BSIZE;
19500Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.dki, (caddr_t)arg,
19517656SSherry.Moore@Sun.COM 		    sizeof (cpy.dki), flag))
19520Sstevel@tonic-gate 			err = EFAULT;
19530Sstevel@tonic-gate 		break;
19540Sstevel@tonic-gate 	case DKIOCGGEOM:
19550Sstevel@tonic-gate 		cpy.dkg.dkg_ncyl = un->un_chars->fdc_ncyl;
19560Sstevel@tonic-gate 		cpy.dkg.dkg_nhead = un->un_chars->fdc_nhead;
19570Sstevel@tonic-gate 		cpy.dkg.dkg_nsect = un->un_chars->fdc_secptrack;
19580Sstevel@tonic-gate 		cpy.dkg.dkg_intrlv = un->un_label.dkl_intrlv;
19590Sstevel@tonic-gate 		cpy.dkg.dkg_rpm = un->un_label.dkl_rpm;
19600Sstevel@tonic-gate 		cpy.dkg.dkg_pcyl = un->un_chars->fdc_ncyl;
19610Sstevel@tonic-gate 		cpy.dkg.dkg_read_reinstruct =
19620Sstevel@tonic-gate 		    (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
19630Sstevel@tonic-gate 		cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
19640Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.dkg, (caddr_t)arg,
19657656SSherry.Moore@Sun.COM 		    sizeof (cpy.dkg), flag))
19660Sstevel@tonic-gate 			err = EFAULT;
19670Sstevel@tonic-gate 		break;
19680Sstevel@tonic-gate 	case DKIOCSGEOM:
19690Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
19700Sstevel@tonic-gate 		    (C, "fd_ioctl: DKIOCSGEOM not supported\n"));
19710Sstevel@tonic-gate 		err = ENOTTY;
19720Sstevel@tonic-gate 		break;
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	/*
19750Sstevel@tonic-gate 	 * return the map of all logical partitions
19760Sstevel@tonic-gate 	 */
19770Sstevel@tonic-gate 	case DKIOCGAPART:
19780Sstevel@tonic-gate 		/*
19790Sstevel@tonic-gate 		 * We don't have anything to do if the application is ILP32
19800Sstevel@tonic-gate 		 * because the label map has a 32-bit format. Otherwise
19810Sstevel@tonic-gate 		 * convert.
19820Sstevel@tonic-gate 		 */
19830Sstevel@tonic-gate 		if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
19840Sstevel@tonic-gate 			if (ddi_copyout(&un->un_label.dkl_map,
19857656SSherry.Moore@Sun.COM 			    (void *)arg, sizeof (struct dk_allmap32), flag))
19860Sstevel@tonic-gate 				err = EFAULT;
19870Sstevel@tonic-gate 		}
19880Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
19890Sstevel@tonic-gate 		else {
19900Sstevel@tonic-gate 			struct dk_allmap dk_allmap;
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 			ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
19930Sstevel@tonic-gate 			for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
19940Sstevel@tonic-gate 				dk_allmap.dka_map[dkunit].dkl_cylno =
19950Sstevel@tonic-gate 				    un->un_label.dkl_map[dkunit].dkl_cylno;
19960Sstevel@tonic-gate 				dk_allmap.dka_map[dkunit].dkl_nblk =
19970Sstevel@tonic-gate 				    un->un_label.dkl_map[dkunit].dkl_nblk;
19980Sstevel@tonic-gate 			}
19990Sstevel@tonic-gate 			if (ddi_copyout(&dk_allmap, (void *)arg,
20007656SSherry.Moore@Sun.COM 			    sizeof (struct dk_allmap), flag))
20010Sstevel@tonic-gate 				err = EFAULT;
20020Sstevel@tonic-gate 		}
20030Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20040Sstevel@tonic-gate 		break;
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate 	/*
20070Sstevel@tonic-gate 	 * Set the map of all logical partitions
20080Sstevel@tonic-gate 	 */
20090Sstevel@tonic-gate 	case DKIOCSAPART:
20100Sstevel@tonic-gate 		if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
20110Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &cpy.dka,
20120Sstevel@tonic-gate 			    sizeof (cpy.dka), flag))
20130Sstevel@tonic-gate 				return (EFAULT);
20140Sstevel@tonic-gate 			else {
20150Sstevel@tonic-gate 				mutex_enter(&fdc->c_lolock);
20160Sstevel@tonic-gate 				for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
20170Sstevel@tonic-gate 					un->un_label.dkl_map[dkunit] =
20187656SSherry.Moore@Sun.COM 					    cpy.dka.dka_map[dkunit];
20190Sstevel@tonic-gate 				}
20200Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
20210Sstevel@tonic-gate 			}
20220Sstevel@tonic-gate 		}
20230Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20240Sstevel@tonic-gate 		else {
20250Sstevel@tonic-gate 			struct dk_allmap dk_allmap;
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 			ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
20280Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &dk_allmap,
20290Sstevel@tonic-gate 			    sizeof (dk_allmap), flag))
20300Sstevel@tonic-gate 				return (EFAULT);
20310Sstevel@tonic-gate 			else {
20320Sstevel@tonic-gate 				mutex_enter(&fdc->c_lolock);
20330Sstevel@tonic-gate 				for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
20340Sstevel@tonic-gate 					un->un_label.dkl_map[dkunit].dkl_cylno =
20350Sstevel@tonic-gate 					    dk_allmap.dka_map[dkunit].dkl_cylno;
20360Sstevel@tonic-gate 					un->un_label.dkl_map[dkunit].dkl_nblk =
20370Sstevel@tonic-gate 					    dk_allmap.dka_map[dkunit].dkl_nblk;
20380Sstevel@tonic-gate 				}
20390Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
20400Sstevel@tonic-gate 			}
20410Sstevel@tonic-gate 		}
20420Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20430Sstevel@tonic-gate 		break;
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 	case DKIOCGVTOC:
20460Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 		/*
20490Sstevel@tonic-gate 		 * Exit if the diskette has no label.
20500Sstevel@tonic-gate 		 * Also, get the label to make sure the
20510Sstevel@tonic-gate 		 * correct one is being used since the diskette
20520Sstevel@tonic-gate 		 * may have changed
20530Sstevel@tonic-gate 		 */
20540Sstevel@tonic-gate 		if (fdgetlabel(fdc, unit)) {
20550Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
20560Sstevel@tonic-gate 			err = EINVAL;
20570Sstevel@tonic-gate 			break;
20580Sstevel@tonic-gate 		}
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 		/* Build a vtoc from the diskette's label */
20610Sstevel@tonic-gate 		fd_build_user_vtoc(un, &vtoc);
20620Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20650Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
20660Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
20670Sstevel@tonic-gate 			struct vtoc32 vtoc32;
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 			vtoctovtoc32(vtoc, vtoc32);
20700Sstevel@tonic-gate 			if (ddi_copyout(&vtoc32, (void *)arg,
20710Sstevel@tonic-gate 			    sizeof (struct vtoc32), flag))
20720Sstevel@tonic-gate 				return (EFAULT);
20730Sstevel@tonic-gate 			break;
20740Sstevel@tonic-gate 		}
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate 		case DDI_MODEL_NONE:
20770Sstevel@tonic-gate 			if (ddi_copyout(&vtoc, (void *)arg,
20780Sstevel@tonic-gate 			    sizeof (vtoc), flag))
20790Sstevel@tonic-gate 				return (EFAULT);
20800Sstevel@tonic-gate 			break;
20810Sstevel@tonic-gate 		}
20820Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */
20830Sstevel@tonic-gate 		if (ddi_copyout(&vtoc, (void *)arg, sizeof (vtoc), flag))
20840Sstevel@tonic-gate 			return (EFAULT);
20850Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20860Sstevel@tonic-gate 		break;
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 	case DKIOCSVTOC:
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20910Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
20920Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
20930Sstevel@tonic-gate 			struct vtoc32 vtoc32;
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &vtoc32,
20960Sstevel@tonic-gate 			    sizeof (struct vtoc32), flag)) {
20970Sstevel@tonic-gate 				return (EFAULT);
20980Sstevel@tonic-gate 			}
20990Sstevel@tonic-gate 			vtoc32tovtoc(vtoc32, vtoc);
21000Sstevel@tonic-gate 			break;
21010Sstevel@tonic-gate 		}
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 		case DDI_MODEL_NONE:
21040Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &vtoc,
21050Sstevel@tonic-gate 			    sizeof (vtoc), flag)) {
21060Sstevel@tonic-gate 				return (EFAULT);
21070Sstevel@tonic-gate 			}
21080Sstevel@tonic-gate 			break;
21090Sstevel@tonic-gate 		}
21100Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */
21110Sstevel@tonic-gate 		if (ddi_copyin((const void *)arg, &vtoc, sizeof (vtoc), flag))
21120Sstevel@tonic-gate 			return (EFAULT);
21130Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 		/*
21180Sstevel@tonic-gate 		 * The characteristics structure must be filled in because
21190Sstevel@tonic-gate 		 * it helps build the vtoc.
21200Sstevel@tonic-gate 		 */
21210Sstevel@tonic-gate 		if ((un->un_chars->fdc_ncyl == 0) ||
21227656SSherry.Moore@Sun.COM 		    (un->un_chars->fdc_nhead == 0) ||
21237656SSherry.Moore@Sun.COM 		    (un->un_chars->fdc_secptrack == 0)) {
21240Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
21250Sstevel@tonic-gate 			err = EINVAL;
21260Sstevel@tonic-gate 			break;
21270Sstevel@tonic-gate 		}
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 		if ((err = fd_build_label_vtoc(un, &vtoc)) != 0) {
21300Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
21310Sstevel@tonic-gate 			break;
21320Sstevel@tonic-gate 		}
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 		err = fdrw(fdc, unit, FDWRITE, 0, 0, 1,
21370Sstevel@tonic-gate 		    (caddr_t)&un->un_label, sizeof (struct dk_label));
21380Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
21390Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
21400Sstevel@tonic-gate 		break;
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 	case DKIOCSTATE:
21430Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&state,
21447656SSherry.Moore@Sun.COM 		    sizeof (int), flag)) {
21450Sstevel@tonic-gate 			err = EFAULT;
21460Sstevel@tonic-gate 			break;
21470Sstevel@tonic-gate 		}
21480Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 		err = fd_check_media(dev, state);
21510Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&un->un_media_state,
21547656SSherry.Moore@Sun.COM 		    (caddr_t)arg, sizeof (int), flag))
21550Sstevel@tonic-gate 			err = EFAULT;
21560Sstevel@tonic-gate 		break;
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 	case FDIOGCHAR:
21590Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)un->un_chars, (caddr_t)arg,
21607656SSherry.Moore@Sun.COM 		    sizeof (struct fd_char), flag))
21610Sstevel@tonic-gate 			err = EFAULT;
21620Sstevel@tonic-gate 		break;
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 	case FDIOSCHAR:
21650Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.fdchar,
21660Sstevel@tonic-gate 				sizeof (struct fd_char), flag)) {
21670Sstevel@tonic-gate 			err = EFAULT;
21680Sstevel@tonic-gate 			break;
21690Sstevel@tonic-gate 		}
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 		/*
21720Sstevel@tonic-gate 		 * Check the fields in the fdchar structure that are either
21730Sstevel@tonic-gate 		 * driver or controller dependent.
21740Sstevel@tonic-gate 		 */
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 		transfer_rate = cpy.fdchar.fdc_transfer_rate;
21770Sstevel@tonic-gate 		if ((transfer_rate != 500) && (transfer_rate != 300) &&
21780Sstevel@tonic-gate 		    (transfer_rate != 250) && (transfer_rate != 1000)) {
21790Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
21807656SSherry.Moore@Sun.COM 			    (C, "fd_ioctl: FDIOSCHAR odd transfer rate %d\n",
21810Sstevel@tonic-gate 			    cpy.fdchar.fdc_transfer_rate));
21820Sstevel@tonic-gate 			err = EINVAL;
21830Sstevel@tonic-gate 			break;
21840Sstevel@tonic-gate 		}
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 		if ((cpy.fdchar.fdc_nhead < 1) ||
21877656SSherry.Moore@Sun.COM 		    (cpy.fdchar.fdc_nhead > 2)) {
21880Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
21897656SSherry.Moore@Sun.COM 			    (C, "fd_ioctl: FDIOSCHAR bad no. of heads %d\n",
21900Sstevel@tonic-gate 			    cpy.fdchar.fdc_nhead));
21910Sstevel@tonic-gate 			err = EINVAL;
21920Sstevel@tonic-gate 			break;
21930Sstevel@tonic-gate 		}
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 		/*
21960Sstevel@tonic-gate 		 * The number of cylinders must be between 0 and 255
21970Sstevel@tonic-gate 		 */
21980Sstevel@tonic-gate 		if ((cpy.fdchar.fdc_ncyl < 0) || (cpy.fdchar.fdc_ncyl > 255)) {
21990Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
22007656SSherry.Moore@Sun.COM 			    (C, "fd_ioctl: FDIOSCHAR bad cyl no %d\n",
22010Sstevel@tonic-gate 			    cpy.fdchar.fdc_ncyl));
22020Sstevel@tonic-gate 			err = EINVAL;
22030Sstevel@tonic-gate 			break;
22040Sstevel@tonic-gate 		}
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 		/* Copy the fdchar structure */
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
22090Sstevel@tonic-gate 		*(un->un_chars) = cpy.fdchar;
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 		un->un_curfdtype = -1;
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 		break;
22160Sstevel@tonic-gate 	case FDEJECT:  /* eject disk */
22170Sstevel@tonic-gate 	case DKIOCEJECT:
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 		/*
22200Sstevel@tonic-gate 		 * Fail the ioctl if auto-eject isn't supported
22210Sstevel@tonic-gate 		 */
22220Sstevel@tonic-gate 		if (fdc->c_un->un_drive->fdd_ejectable == 0) {
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 			err = ENOSYS;
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 		} else {
22270Sstevel@tonic-gate 			(void) pm_busy_component(fdc->c_dip, 0);
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
22300Sstevel@tonic-gate 
22310Sstevel@tonic-gate 			CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate 			if (fdc->c_un->un_state == FD_STATE_STOPPED) {
22340Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
22350Sstevel@tonic-gate 				if ((pm_raise_power(fdc->c_dip, 0,
22367656SSherry.Moore@Sun.COM 				    PM_LEVEL_ON)) != DDI_SUCCESS) {
22370Sstevel@tonic-gate 					(void) pm_idle_component(fdc->c_dip, 0);
22380Sstevel@tonic-gate 					err = EIO;
22390Sstevel@tonic-gate 				}
22400Sstevel@tonic-gate 				mutex_enter(&fdc->c_lolock);
22410Sstevel@tonic-gate 			}
22420Sstevel@tonic-gate 		}
22430Sstevel@tonic-gate 		if (err == 0) {
22440Sstevel@tonic-gate 			fdselect(fdc, unit, 1);
22450Sstevel@tonic-gate 			fdeject(fdc, unit);
22460Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
22470Sstevel@tonic-gate 		}
22480Sstevel@tonic-gate 
22490Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate 		/*
22520Sstevel@tonic-gate 		 * Make sure the drive is turned off
22530Sstevel@tonic-gate 		 */
22540Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_82077) {
22550Sstevel@tonic-gate 			if (fdc->c_mtimeid == 0) {
22560Sstevel@tonic-gate 				fdc->c_mtimeid = timeout(fdmotoff, fdc,
22577656SSherry.Moore@Sun.COM 				    Motoff_delay);
22580Sstevel@tonic-gate 			}
22590Sstevel@tonic-gate 		}
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 		break;
22620Sstevel@tonic-gate 	case FDGETCHANGE: /* disk changed */
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.temp,
22657656SSherry.Moore@Sun.COM 		    sizeof (int), flag)) {
22660Sstevel@tonic-gate 			err = EFAULT;
22670Sstevel@tonic-gate 			break;
22680Sstevel@tonic-gate 		}
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 		/* zero out the user's parameter */
22710Sstevel@tonic-gate 		cpy.temp = 0;
22720Sstevel@tonic-gate 
22730Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 		CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 		if (fdc->c_un->un_state == FD_STATE_STOPPED) {
22800Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
22810Sstevel@tonic-gate 			if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
22827656SSherry.Moore@Sun.COM 			    != DDI_SUCCESS) {
22830Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
22847656SSherry.Moore@Sun.COM 				    change failed. \n"));
22850Sstevel@tonic-gate 				(void) pm_idle_component(fdc->c_dip, 0);
22860Sstevel@tonic-gate 				return (EIO);
22870Sstevel@tonic-gate 			}
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
22900Sstevel@tonic-gate 		}
22910Sstevel@tonic-gate 		if (un->un_flags & FDUNIT_CHANGED)
22920Sstevel@tonic-gate 			cpy.temp |= FDGC_HISTORY;
22930Sstevel@tonic-gate 		else
22940Sstevel@tonic-gate 			cpy.temp &= ~FDGC_HISTORY;
22950Sstevel@tonic-gate 		un->un_flags &= ~FDUNIT_CHANGED;
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 		if (fd_pollable) {
22980Sstevel@tonic-gate 			/*
22990Sstevel@tonic-gate 			 * If it's a "pollable" floppy, then we don't
23000Sstevel@tonic-gate 			 * have to do all the fdcheckdisk nastyness to
23010Sstevel@tonic-gate 			 * figure out if the thing is still there.
23020Sstevel@tonic-gate 			 */
23030Sstevel@tonic-gate 			if (fdsense_chng(fdc, unit)) {
23040Sstevel@tonic-gate 				cpy.temp |= FDGC_CURRENT;
23050Sstevel@tonic-gate 			} else {
23060Sstevel@tonic-gate 				cpy.temp &= ~FDGC_CURRENT;
23070Sstevel@tonic-gate 			}
23080Sstevel@tonic-gate 		} else {
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 			if (fdsense_chng(fdc, unit)) {
23110Sstevel@tonic-gate 				/*
23120Sstevel@tonic-gate 				 * check disk change signal is asserted.
23130Sstevel@tonic-gate 				 * Now find out if the floppy is
23140Sstevel@tonic-gate 				 * inserted
23150Sstevel@tonic-gate 				 */
23160Sstevel@tonic-gate 				if (fdcheckdisk(fdc, unit)) {
23170Sstevel@tonic-gate 					cpy.temp |= FDGC_CURRENT;
23180Sstevel@tonic-gate 				} else {
23190Sstevel@tonic-gate 					/*
23200Sstevel@tonic-gate 					 * Yes, the floppy was
23210Sstevel@tonic-gate 					 * reinserted. Implies
23220Sstevel@tonic-gate 					 * floppy change.
23230Sstevel@tonic-gate 					 */
23240Sstevel@tonic-gate 					cpy.temp &= ~FDGC_CURRENT;
23250Sstevel@tonic-gate 					cpy.temp |= FDGC_HISTORY;
23260Sstevel@tonic-gate 				}
23270Sstevel@tonic-gate 			} else {
23280Sstevel@tonic-gate 				cpy.temp &= ~FDGC_CURRENT;
23290Sstevel@tonic-gate 			}
23300Sstevel@tonic-gate 		}
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 		/*
23330Sstevel@tonic-gate 		 * For a pollable floppy, the floppy_change signal
23340Sstevel@tonic-gate 		 * reflects whether the floppy is in there or not.
23350Sstevel@tonic-gate 		 * We can not detect a floppy change if we don't poll
23360Sstevel@tonic-gate 		 * this signal when the floppy is being changed.
23370Sstevel@tonic-gate 		 * Because as soon as the floppy is put back, the
23380Sstevel@tonic-gate 		 * signal is reset.
23390Sstevel@tonic-gate 		 * BUT the pollable floppies are available only on
23400Sstevel@tonic-gate 		 * Sparcstation Voyager Voyagers (Gypsy) only and
23410Sstevel@tonic-gate 		 * those are motorized floppies. For motorized floppies,
23420Sstevel@tonic-gate 		 * the floppy can only (assuming the user doesn't use a
23430Sstevel@tonic-gate 		 * pin to take out the floppy) be taken out by
23440Sstevel@tonic-gate 		 * issuing 'eject' command which sets the
23450Sstevel@tonic-gate 		 * un->un_ejected flag. So, if the following
23460Sstevel@tonic-gate 		 * condition is true, we can assume there
23470Sstevel@tonic-gate 		 * was a floppy change.
23480Sstevel@tonic-gate 		 */
23490Sstevel@tonic-gate 		if (un->un_ejected && !(cpy.temp & FDGC_CURRENT)) {
23500Sstevel@tonic-gate 			cpy.temp |= FDGC_HISTORY;
23510Sstevel@tonic-gate 		}
23520Sstevel@tonic-gate 		un->un_ejected = 0;
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 		/* return the write-protection status */
23560Sstevel@tonic-gate 		fdgetcsb(fdc);
23570Sstevel@tonic-gate 		if (fdsensedrv(fdc, unit) & WP_SR3) {
23580Sstevel@tonic-gate 			cpy.temp |= FDGC_CURWPROT;
23590Sstevel@tonic-gate 		}
23600Sstevel@tonic-gate 		fdretcsb(fdc);
23610Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.temp, (caddr_t)arg,
23647656SSherry.Moore@Sun.COM 		    sizeof (int), flag))
23650Sstevel@tonic-gate 			err = EFAULT;
23660Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
23670Sstevel@tonic-gate 		break;
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate 	case FDGETDRIVECHAR:
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.drvchar,
23720Sstevel@tonic-gate 				sizeof (struct fd_drive), flag)) {
23730Sstevel@tonic-gate 			err = EFAULT;
23740Sstevel@tonic-gate 			break;
23750Sstevel@tonic-gate 		}
23760Sstevel@tonic-gate 
23770Sstevel@tonic-gate 		/*
23780Sstevel@tonic-gate 		 * Return the ejectable value based on the FD_MANUAL_EJECT
23790Sstevel@tonic-gate 		 * property
23800Sstevel@tonic-gate 		 */
23810Sstevel@tonic-gate 		cpy.drvchar.fdd_ejectable = fdc->c_un->un_drive->fdd_ejectable;
23820Sstevel@tonic-gate 		cpy.drvchar.fdd_maxsearch = nfdtypes; /* 3 - hi m lo density */
23830Sstevel@tonic-gate 		if (fd_pollable)	/* pollable device */
23840Sstevel@tonic-gate 			cpy.drvchar.fdd_flags |= FDD_POLLABLE;
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 		/* the rest of the fd_drive struct is meaningless to us */
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.drvchar, (caddr_t)arg,
23897656SSherry.Moore@Sun.COM 		    sizeof (struct fd_drive), flag))
23900Sstevel@tonic-gate 			err = EFAULT;
23910Sstevel@tonic-gate 		break;
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	case FDSETDRIVECHAR:
23940Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
23950Sstevel@tonic-gate 		    (C, "fd_ioctl: FDSETDRIVECHAR not supportedn\n"));
23960Sstevel@tonic-gate 		err = ENOTTY;
23970Sstevel@tonic-gate 		break;
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate 	case DKIOCREMOVABLE: {
24000Sstevel@tonic-gate 		int	i = 1;
24010Sstevel@tonic-gate 
24020Sstevel@tonic-gate 		/* no brainer: floppies are always removable */
24030Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&i, (caddr_t)arg, sizeof (int),
24040Sstevel@tonic-gate 		    flag)) {
24050Sstevel@tonic-gate 			err = EFAULT;
24060Sstevel@tonic-gate 		}
24070Sstevel@tonic-gate 		break;
24080Sstevel@tonic-gate 	}
24090Sstevel@tonic-gate 	case DKIOCGMEDIAINFO:
24100Sstevel@tonic-gate 		err = fd_get_media_info(un, (caddr_t)arg, flag);
24110Sstevel@tonic-gate 		break;
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate 
24140Sstevel@tonic-gate 	case FDIOCMD:
24150Sstevel@tonic-gate 	{
24160Sstevel@tonic-gate 		struct fd_cmd fc;
24170Sstevel@tonic-gate 		int cyl, hd, spc, spt;
24180Sstevel@tonic-gate 		int nblks; /* total no. of blocks */
24190Sstevel@tonic-gate 
24200Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
24210Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
24220Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
24230Sstevel@tonic-gate 			struct fd_cmd32 fc32;
24240Sstevel@tonic-gate 
24250Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &fc32,
24260Sstevel@tonic-gate 			    sizeof (fc32), flag)) {
24270Sstevel@tonic-gate 				return (EFAULT);
24280Sstevel@tonic-gate 			}
24290Sstevel@tonic-gate 			fc.fdc_cmd	= fc32.fdc_cmd;
24300Sstevel@tonic-gate 			fc.fdc_flags	= fc32.fdc_flags;
24310Sstevel@tonic-gate 			fc.fdc_blkno	= (daddr_t)fc32.fdc_blkno;
24320Sstevel@tonic-gate 			fc.fdc_secnt	= fc32.fdc_secnt;
2433483Spc157239 			fc.fdc_bufaddr	= (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
24340Sstevel@tonic-gate 			fc.fdc_buflen	= fc32.fdc_buflen;
24350Sstevel@tonic-gate 			fc.fdc_cmd	= fc32.fdc_cmd;
24360Sstevel@tonic-gate 
24370Sstevel@tonic-gate 			break;
24380Sstevel@tonic-gate 		}
24390Sstevel@tonic-gate 
24400Sstevel@tonic-gate 		case DDI_MODEL_NONE:
24410Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &fc,
24420Sstevel@tonic-gate 			    sizeof (fc), flag)) {
24430Sstevel@tonic-gate 				return (EFAULT);
24440Sstevel@tonic-gate 			}
24450Sstevel@tonic-gate 			break;
24460Sstevel@tonic-gate 		}
24470Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */
24480Sstevel@tonic-gate 		if (ddi_copyin((const void *)arg, &fc, sizeof (fc), flag)) {
24490Sstevel@tonic-gate 			return (EFAULT);
24500Sstevel@tonic-gate 		}
24510Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
24520Sstevel@tonic-gate 
24530Sstevel@tonic-gate 		if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
24540Sstevel@tonic-gate 			auto struct iovec aiov;
24550Sstevel@tonic-gate 			auto struct uio auio;
24560Sstevel@tonic-gate 			struct uio *uio = &auio;
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 			spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate 			bzero(&auio, sizeof (struct uio));
24610Sstevel@tonic-gate 			bzero(&aiov, sizeof (struct iovec));
24620Sstevel@tonic-gate 			aiov.iov_base = fc.fdc_bufaddr;
24630Sstevel@tonic-gate 			aiov.iov_len = (uint_t)fc.fdc_secnt * sec_size;
24640Sstevel@tonic-gate 			uio->uio_iov = &aiov;
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 			uio->uio_iovcnt = 1;
24670Sstevel@tonic-gate 			uio->uio_resid = aiov.iov_len;
24680Sstevel@tonic-gate 			uio->uio_segflg = UIO_USERSPACE;
24690Sstevel@tonic-gate 			FDERRPRINT(FDEP_L2, FDEM_IOCT,
24700Sstevel@tonic-gate 			    (C, "fd_ioctl: call physio\n"));
24710Sstevel@tonic-gate 			err = physio(fd_strategy, NULL, dev,
24720Sstevel@tonic-gate 			    spc, minphys, uio);
24730Sstevel@tonic-gate 			break;
24740Sstevel@tonic-gate 		} else if (fc.fdc_cmd != FDCMD_FORMAT_TRACK) {
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 			/*
24770Sstevel@tonic-gate 			 * The manpage states that only the FDCMD_WRITE,
24780Sstevel@tonic-gate 			 * FDCMD_READ, and the FDCMD_FORMAT_TR are available.
24790Sstevel@tonic-gate 			 */
24800Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_IOCT,
24810Sstevel@tonic-gate 			    (C, "fd_ioctl: FDIOCMD invalid command\n"));
24820Sstevel@tonic-gate 			err = EINVAL;
24830Sstevel@tonic-gate 			break;
24840Sstevel@tonic-gate 		}
24850Sstevel@tonic-gate 
24860Sstevel@tonic-gate 		/* The command is FDCMD_FORMAT_TRACK */
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 		spt = un->un_chars->fdc_secptrack;	/* sec/trk */
24890Sstevel@tonic-gate 		spc = un->un_chars->fdc_nhead * spt;	/* sec/cyl */
24900Sstevel@tonic-gate 		cyl = fc.fdc_blkno / spc;
24910Sstevel@tonic-gate 		hd = (fc.fdc_blkno % spc) / spt;
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate 		/*
24940Sstevel@tonic-gate 		 * Make sure the specified block number is in the correct
24950Sstevel@tonic-gate 		 * range. (block numbers start at 0)
24960Sstevel@tonic-gate 		 */
24970Sstevel@tonic-gate 		nblks = spc * un->un_chars->fdc_ncyl;
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 		if (fc.fdc_blkno < 0 || fc.fdc_blkno > (nblks - 1)) {
25000Sstevel@tonic-gate 			err = EINVAL;
25010Sstevel@tonic-gate 			break;
25020Sstevel@tonic-gate 		}
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
25070Sstevel@tonic-gate 		CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
25080Sstevel@tonic-gate 		if (fdc->c_un->un_state == FD_STATE_STOPPED) {
25090Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
25100Sstevel@tonic-gate 			if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
25117656SSherry.Moore@Sun.COM 			    != DDI_SUCCESS) {
25120Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
25137656SSherry.Moore@Sun.COM 				    change failed. \n"));
25140Sstevel@tonic-gate 				(void) pm_idle_component(fdc->c_dip, 0);
25150Sstevel@tonic-gate 				return (EIO);
25160Sstevel@tonic-gate 			}
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
25190Sstevel@tonic-gate 		}
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate 		if (fdformat(fdc, unit, cyl, hd))
25220Sstevel@tonic-gate 			err = EIO;
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
25250Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate 		break;
25280Sstevel@tonic-gate 	}
25290Sstevel@tonic-gate 
25300Sstevel@tonic-gate 	case FDRAW:
25310Sstevel@tonic-gate 
25320Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
25330Sstevel@tonic-gate 		err = fdrawioctl(fdc, unit, arg, flag);
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 		break;
25380Sstevel@tonic-gate #ifdef FD_DEBUG
25390Sstevel@tonic-gate 	case IOCTL_DEBUG:
25400Sstevel@tonic-gate 		fderrlevel--;
25410Sstevel@tonic-gate 		if (fderrlevel < 0)
25420Sstevel@tonic-gate 			fderrlevel = 3;
25430Sstevel@tonic-gate 		cmn_err(C, "fdioctl: CHANGING debug to %d", fderrlevel);
25440Sstevel@tonic-gate 		return (0);
25450Sstevel@tonic-gate #endif /* FD_DEBUG */
25460Sstevel@tonic-gate 	default:
25470Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_IOCT,
25480Sstevel@tonic-gate 		    (C, "fd_ioctl: invalid ioctl 0x%x\n", cmd));
25490Sstevel@tonic-gate 		err = ENOTTY;
25500Sstevel@tonic-gate 		break;
25510Sstevel@tonic-gate 	}
25520Sstevel@tonic-gate 
25530Sstevel@tonic-gate 	return (err);
25540Sstevel@tonic-gate }
25550Sstevel@tonic-gate 
25560Sstevel@tonic-gate /*
25570Sstevel@tonic-gate  * fdrawioctl
25580Sstevel@tonic-gate  *
25590Sstevel@tonic-gate  * 	- acquires the low level lock
25600Sstevel@tonic-gate  */
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate static int
fdrawioctl(struct fdctlr * fdc,int unit,intptr_t arg,int mode)25630Sstevel@tonic-gate fdrawioctl(struct fdctlr *fdc, int unit, intptr_t arg, int mode)
25640Sstevel@tonic-gate {
25650Sstevel@tonic-gate 	struct fd_raw fdr;
25660Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
25670Sstevel@tonic-gate 	struct fd_raw32 fdr32;
25680Sstevel@tonic-gate #endif
25690Sstevel@tonic-gate 	struct fdcsb *csb;
25700Sstevel@tonic-gate 	int i, err, flag;
25710Sstevel@tonic-gate 	caddr_t fa;
25720Sstevel@tonic-gate 	uint_t	fc;
25730Sstevel@tonic-gate 	size_t	real_length;
25740Sstevel@tonic-gate 	int	res;
25750Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
25760Sstevel@tonic-gate 	ddi_acc_handle_t	mem_handle;
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
25790Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
25800Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
25810Sstevel@tonic-gate 
25820Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate 	flag = B_READ;
25850Sstevel@tonic-gate 	err = 0;
25860Sstevel@tonic-gate 	fa = NULL;
25870Sstevel@tonic-gate 	fc = (uint_t)0;
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 	/* Copy in the arguments */
25900Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode)) {
25910Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
25920Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
25930Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr32,
25940Sstevel@tonic-gate 		    sizeof (fdr32), mode)) {
25950Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
25967656SSherry.Moore@Sun.COM 			    (C, "fdrawioctl: copyin error, args32\n"));
25970Sstevel@tonic-gate 			return (EFAULT);
25980Sstevel@tonic-gate 		}
25990Sstevel@tonic-gate 		bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
26000Sstevel@tonic-gate 		fdr.fdr_cnum = fdr32.fdr_cnum;
26010Sstevel@tonic-gate 		bcopy(fdr32.fdr_result, fdr.fdr_result,
26020Sstevel@tonic-gate 		    sizeof (fdr.fdr_result));
26030Sstevel@tonic-gate 		fdr.fdr_nbytes = fdr32.fdr_nbytes;
2604483Spc157239 		fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
26050Sstevel@tonic-gate 		break;
26060Sstevel@tonic-gate #endif
26070Sstevel@tonic-gate 	default:
26080Sstevel@tonic-gate 	case DDI_MODEL_NONE:
26090Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr,
26100Sstevel@tonic-gate 		    sizeof (fdr), mode)) {
26110Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
26127656SSherry.Moore@Sun.COM 			    (C, "fdrawioctl: copyin error, args\n"));
26130Sstevel@tonic-gate 			return (EFAULT);
26140Sstevel@tonic-gate 		}
26150Sstevel@tonic-gate 		break;
26160Sstevel@tonic-gate 	}
26170Sstevel@tonic-gate 
2618*12779SFred.Herard@Sun.COM 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
2619*12779SFred.Herard@Sun.COM 	    (C, "fdrawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
2620*12779SFred.Herard@Sun.COM 
26210Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
26260Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
26270Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
26287656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
26290Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
26307656SSherry.Moore@Sun.COM 			    failed. \n"));
26310Sstevel@tonic-gate 
26320Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
26330Sstevel@tonic-gate 			return (EIO);
26340Sstevel@tonic-gate 		}
26350Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
26360Sstevel@tonic-gate 	}
26370Sstevel@tonic-gate 
26380Sstevel@tonic-gate 	fdgetcsb(fdc);
26390Sstevel@tonic-gate 	csb = &fdc->c_csb;
26400Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
26410Sstevel@tonic-gate 
26420Sstevel@tonic-gate 	/* copy cmd bytes into csb */
26430Sstevel@tonic-gate 	for (i = 0; i <= fdr.fdr_cnum; i++)
26440Sstevel@tonic-gate 		csb->csb_cmds[i] = fdr.fdr_cmd[i];
26450Sstevel@tonic-gate 	csb->csb_ncmds = (uchar_t)fdr.fdr_cnum;
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 	csb->csb_maxretry = 0;	/* let the application deal with errors */
26480Sstevel@tonic-gate 	csb->csb_retrys = 0;
26490Sstevel@tonic-gate 
26500Sstevel@tonic-gate 	switch (fdr.fdr_cmd[0] & 0x0f) {
26510Sstevel@tonic-gate 
26520Sstevel@tonic-gate 	case FDRAW_SPECIFY:
26530Sstevel@tonic-gate 		/*
26540Sstevel@tonic-gate 		 * Ensure that the right DMA mode is selected.  There is
26550Sstevel@tonic-gate 		 * currently no way for the user to tell if DMA is
26560Sstevel@tonic-gate 		 * happening so set the value for the user.
26570Sstevel@tonic-gate 		 */
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA)
26600Sstevel@tonic-gate 			csb->csb_cmds[2] = csb->csb_cmds[2] & 0xFE;
26610Sstevel@tonic-gate 		else
26620Sstevel@tonic-gate 			csb->csb_cmds[2] = csb->csb_cmds[2] | 0x1;
26630Sstevel@tonic-gate 
26640Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFNORESULTS;
26650Sstevel@tonic-gate 		csb->csb_nrslts = 0;
26660Sstevel@tonic-gate 		break;
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	case FDRAW_SENSE_DRV:
26690Sstevel@tonic-gate 		/* Insert the appropriate drive number */
26700Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
26710Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFIMMEDIATE;
26720Sstevel@tonic-gate 		csb->csb_nrslts = 1;
26730Sstevel@tonic-gate 		break;
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate 	case FDRAW_REZERO:
26760Sstevel@tonic-gate 	case FDRAW_SEEK:
26770Sstevel@tonic-gate 		/* Insert the appropriate drive number */
26780Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
26790Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFSEEKOPS + CSB_OFTIMEIT;
26800Sstevel@tonic-gate 		csb->csb_nrslts = 2;
26810Sstevel@tonic-gate 		break;
26820Sstevel@tonic-gate 
26830Sstevel@tonic-gate 	case FDRAW_FORMAT:
26840Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RAWI,
26857656SSherry.Moore@Sun.COM 		    (C, "fdrawioctl: cmd is fdfraw format\n"));
26860Sstevel@tonic-gate 
26870Sstevel@tonic-gate 		/* Insert the appropriate drive number */
26880Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
26890Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
26900Sstevel@tonic-gate 		csb->csb_nrslts = NRBRW;
26910Sstevel@tonic-gate 		flag = B_WRITE;
26920Sstevel@tonic-gate 
26930Sstevel@tonic-gate 		/*
26940Sstevel@tonic-gate 		 * Allocate memory for the command.
26950Sstevel@tonic-gate 		 * If PIO is being used, then add an extra 16 bytes
26960Sstevel@tonic-gate 		 */
26970Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA) {
26980Sstevel@tonic-gate 
26990Sstevel@tonic-gate 			fc = (uint_t)(fdr.fdr_nbytes);
27000Sstevel@tonic-gate 			mutex_enter(&fdc->c_hilock);
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate 			res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
27037656SSherry.Moore@Sun.COM 			    &attr, DDI_DMA_STREAMING,
27047656SSherry.Moore@Sun.COM 			    DDI_DMA_DONTWAIT, 0, &fa, &real_length,
27057656SSherry.Moore@Sun.COM 			    &mem_handle);
27060Sstevel@tonic-gate 
27070Sstevel@tonic-gate 			if (res != DDI_SUCCESS) {
27080Sstevel@tonic-gate 				fdretcsb(fdc);
27090Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
27100Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
27110Sstevel@tonic-gate 				return (EIO);
27120Sstevel@tonic-gate 			}
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate 			fdc->c_csb.csb_read = CSB_WRITE;
27150Sstevel@tonic-gate 			if (fdstart_dma(fdc, fa, fc) != 0) {
27160Sstevel@tonic-gate 				ddi_dma_mem_free(&mem_handle);
27170Sstevel@tonic-gate 				fdretcsb(fdc);
27180Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
27190Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
27200Sstevel@tonic-gate 				return (EIO);
27210Sstevel@tonic-gate 			}
27220Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 		} else {
27250Sstevel@tonic-gate 			fc = (uint_t)(fdr.fdr_nbytes + 16);
27260Sstevel@tonic-gate 			fa = kmem_zalloc(fc, KM_SLEEP);
27270Sstevel@tonic-gate 		}
27280Sstevel@tonic-gate 
27290Sstevel@tonic-gate 		/* copy in the user's command bytes */
27300Sstevel@tonic-gate 		if (ddi_copyin(fdr.fdr_addr, fa,
27317656SSherry.Moore@Sun.COM 		    (uint_t)fdr.fdr_nbytes, mode)) {
27320Sstevel@tonic-gate 			fdretcsb(fdc);
27330Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
27340Sstevel@tonic-gate 
27350Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_DMA) {
27360Sstevel@tonic-gate 				ddi_dma_mem_free(&mem_handle);
27370Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_RAWI,
27387656SSherry.Moore@Sun.COM 				    (C, "fdrawioctl: (err)free dma memory\n"));
27390Sstevel@tonic-gate 			} else {
27400Sstevel@tonic-gate 				kmem_free(fa, fc);
27410Sstevel@tonic-gate 			}
27420Sstevel@tonic-gate 
27430Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
27447656SSherry.Moore@Sun.COM 			    (C, "fdrawioctl: ddi_copyin error\n"));
27450Sstevel@tonic-gate 			return (EFAULT);
27460Sstevel@tonic-gate 		}
27470Sstevel@tonic-gate 
27480Sstevel@tonic-gate 		break;
27490Sstevel@tonic-gate 	case FDRAW_WRCMD:
27500Sstevel@tonic-gate 	case FDRAW_WRITEDEL:
27510Sstevel@tonic-gate 		flag = B_WRITE;
27520Sstevel@tonic-gate 		/* FALLTHROUGH */
27530Sstevel@tonic-gate 	case FDRAW_RDCMD:
27540Sstevel@tonic-gate 	case FDRAW_READDEL:
27550Sstevel@tonic-gate 	case FDRAW_READTRACK:
27560Sstevel@tonic-gate 		/* Insert the appropriate drive number */
27570Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
27580Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB)
27590Sstevel@tonic-gate 			csb->csb_cmds[1] |= IPS;
27600Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
27610Sstevel@tonic-gate 		csb->csb_nrslts = NRBRW;
27620Sstevel@tonic-gate 		break;
27630Sstevel@tonic-gate 
27640Sstevel@tonic-gate 	default:
27650Sstevel@tonic-gate 		fdretcsb(fdc);
27660Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
27670Sstevel@tonic-gate 		return (EINVAL);
27680Sstevel@tonic-gate 	}
27690Sstevel@tonic-gate 
27700Sstevel@tonic-gate 	if ((csb->csb_opflags & CSB_OFXFEROPS) && (fdr.fdr_nbytes == 0)) {
27710Sstevel@tonic-gate 		fdretcsb(fdc);
27720Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
27730Sstevel@tonic-gate 		return (EINVAL);
27740Sstevel@tonic-gate 	}
27750Sstevel@tonic-gate 	csb->csb_opflags |= CSB_OFRAWIOCTL;
27760Sstevel@tonic-gate 
27770Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
27787656SSherry.Moore@Sun.COM 	    (C, "fdrawioctl: nbytes = %u\n", fdr.fdr_nbytes));
27790Sstevel@tonic-gate 
27800Sstevel@tonic-gate 	if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT) {
27810Sstevel@tonic-gate 		if ((fc = (uint_t)fdr.fdr_nbytes) > 0) {
27820Sstevel@tonic-gate 			/*
27830Sstevel@tonic-gate 			 * In SunOS 4.X, we used to as_fault things in.
27840Sstevel@tonic-gate 			 * We really cannot do this in 5.0/SVr4. Unless
27850Sstevel@tonic-gate 			 * someone really believes that speed is of the
27860Sstevel@tonic-gate 			 * essence here, it is just much simpler to do
27870Sstevel@tonic-gate 			 * this in kernel space and use copyin/copyout.
27880Sstevel@tonic-gate 			 */
27890Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_DMA) {
27900Sstevel@tonic-gate 				mutex_enter(&fdc->c_hilock);
27910Sstevel@tonic-gate 				res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
27927656SSherry.Moore@Sun.COM 				    &attr, DDI_DMA_STREAMING,
27937656SSherry.Moore@Sun.COM 				    DDI_DMA_DONTWAIT, 0, &fa, &real_length,
27947656SSherry.Moore@Sun.COM 				    &mem_handle);
27950Sstevel@tonic-gate 
27960Sstevel@tonic-gate 				if (res != DDI_SUCCESS) {
27970Sstevel@tonic-gate 					fdretcsb(fdc);
27980Sstevel@tonic-gate 					mutex_exit(&fdc->c_lolock);
27990Sstevel@tonic-gate 					mutex_exit(&fdc->c_hilock);
28000Sstevel@tonic-gate 					return (EIO);
28010Sstevel@tonic-gate 				}
28020Sstevel@tonic-gate 
28030Sstevel@tonic-gate 				if (flag == B_WRITE)
28040Sstevel@tonic-gate 					fdc->c_csb.csb_read = CSB_WRITE;
28050Sstevel@tonic-gate 				else
28060Sstevel@tonic-gate 					fdc->c_csb.csb_read = CSB_READ;
28070Sstevel@tonic-gate 
28080Sstevel@tonic-gate 				if (fdstart_dma(fdc, fa, fc) != 0) {
28090Sstevel@tonic-gate 					ddi_dma_mem_free(&mem_handle);
28100Sstevel@tonic-gate 					fdretcsb(fdc);
28110Sstevel@tonic-gate 					mutex_exit(&fdc->c_lolock);
28120Sstevel@tonic-gate 					mutex_exit(&fdc->c_hilock);
28130Sstevel@tonic-gate 					return (EIO);
28140Sstevel@tonic-gate 				}
28150Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
28160Sstevel@tonic-gate 
28170Sstevel@tonic-gate 			} else {
28180Sstevel@tonic-gate 				fa = kmem_zalloc(fc, KM_SLEEP);
28190Sstevel@tonic-gate 			}
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate 			if (flag == B_WRITE) {
28220Sstevel@tonic-gate 				if (ddi_copyin(fdr.fdr_addr, fa, fc, mode)) {
28230Sstevel@tonic-gate 					if (fdc->c_fdtype & FDCTYPE_DMA)
28240Sstevel@tonic-gate 						ddi_dma_mem_free(&mem_handle);
28250Sstevel@tonic-gate 					else
28260Sstevel@tonic-gate 						kmem_free(fa, fc);
28270Sstevel@tonic-gate 					fdretcsb(fdc);
28280Sstevel@tonic-gate 					mutex_exit(&fdc->c_lolock);
28297656SSherry.Moore@Sun.COM 					FDERRPRINT(FDEP_L1, FDEM_RAWI, (C,
28307656SSherry.Moore@Sun.COM 					    "fdrawioctl: can't copy data\n"));
28310Sstevel@tonic-gate 
28320Sstevel@tonic-gate 					return (EFAULT);
28330Sstevel@tonic-gate 				}
28340Sstevel@tonic-gate 			}
28350Sstevel@tonic-gate 			csb->csb_addr = fa;
28360Sstevel@tonic-gate 			csb->csb_len = fc;
28370Sstevel@tonic-gate 		} else {
28380Sstevel@tonic-gate 			csb->csb_addr = 0;
28390Sstevel@tonic-gate 			csb->csb_len = 0;
28400Sstevel@tonic-gate 		}
28410Sstevel@tonic-gate 	} else {
28420Sstevel@tonic-gate 		csb->csb_addr = fa;
28430Sstevel@tonic-gate 		csb->csb_len = fc;
28440Sstevel@tonic-gate 	}
28450Sstevel@tonic-gate 
28460Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
28470Sstevel@tonic-gate 	    (C, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmds[0],
28480Sstevel@tonic-gate 	    csb->csb_cmds[1], csb->csb_cmds[2], csb->csb_cmds[3],
28490Sstevel@tonic-gate 	    csb->csb_cmds[4], csb->csb_cmds[5], csb->csb_cmds[6],
28500Sstevel@tonic-gate 	    csb->csb_cmds[7], csb->csb_cmds[8], csb->csb_cmds[9]));
28510Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
28520Sstevel@tonic-gate 	    (C, "nbytes: %x, opflags: %x, addr: %p, len: %x\n",
28530Sstevel@tonic-gate 	    csb->csb_ncmds, csb->csb_opflags, (void *)csb->csb_addr,
28540Sstevel@tonic-gate 	    csb->csb_len));
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 
28570Sstevel@tonic-gate 	/*
28580Sstevel@tonic-gate 	 * Note that we ignore any error return s from fdexec.
28590Sstevel@tonic-gate 	 * This is the way the driver has been, and it may be
28600Sstevel@tonic-gate 	 * that the raw ioctl senders simply don't want to
28610Sstevel@tonic-gate 	 * see any errors returned in this fashion.
28620Sstevel@tonic-gate 	 */
28630Sstevel@tonic-gate 
28640Sstevel@tonic-gate 	if ((csb->csb_opflags & CSB_OFNORESULTS) ||
28650Sstevel@tonic-gate 	    (csb->csb_opflags & CSB_OFIMMEDIATE)) {
28660Sstevel@tonic-gate 		(void) fdexec(fdc, 0); /* don't sleep, don't check change */
28670Sstevel@tonic-gate 	} else {
28680Sstevel@tonic-gate 		(void) fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG);
28690Sstevel@tonic-gate 	}
28700Sstevel@tonic-gate 
28710Sstevel@tonic-gate 
28720Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
28730Sstevel@tonic-gate 	    (C, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0],
28740Sstevel@tonic-gate 	    csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3],
28750Sstevel@tonic-gate 	    csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6],
28760Sstevel@tonic-gate 	    csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9]));
28770Sstevel@tonic-gate 
28780Sstevel@tonic-gate 	if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT && fc &&
28790Sstevel@tonic-gate 	    flag == B_READ && err == 0) {
28800Sstevel@tonic-gate 		if (ddi_copyout(fa, fdr.fdr_addr, fc, mode)) {
28810Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
28827656SSherry.Moore@Sun.COM 			    (C, "fdrawioctl: can't copy read data\n"));
28830Sstevel@tonic-gate 
28840Sstevel@tonic-gate 			err = EFAULT;
28850Sstevel@tonic-gate 		}
28860Sstevel@tonic-gate 	}
28870Sstevel@tonic-gate 
28880Sstevel@tonic-gate 
28890Sstevel@tonic-gate 	if (fc) {
28900Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA) {
28910Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
28920Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
28937656SSherry.Moore@Sun.COM 			    (C, "fdrawioctl: free dma memory\n"));
28940Sstevel@tonic-gate 		} else {
28950Sstevel@tonic-gate 			kmem_free(fa, fc);
28960Sstevel@tonic-gate 		}
28970Sstevel@tonic-gate 	}
28980Sstevel@tonic-gate 
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate 	/* copy cmd results into fdr */
29010Sstevel@tonic-gate 	for (i = 0; (int)i <= (int)csb->csb_nrslts; i++)
29020Sstevel@tonic-gate 		fdr.fdr_result[i] = csb->csb_rslt[i];
29030Sstevel@tonic-gate 	fdr.fdr_nbytes = fdc->c_csb.csb_rlen; /* return resid */
29040Sstevel@tonic-gate 
29050Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode)) {
29060Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
29070Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
29080Sstevel@tonic-gate 		bcopy(fdr.fdr_cmd, fdr32.fdr_cmd, sizeof (fdr32.fdr_cmd));
29090Sstevel@tonic-gate 		fdr32.fdr_cnum = fdr.fdr_cnum;
29100Sstevel@tonic-gate 		bcopy(fdr.fdr_result, fdr32.fdr_result,
29110Sstevel@tonic-gate 		    sizeof (fdr32.fdr_result));
29120Sstevel@tonic-gate 		fdr32.fdr_nbytes = fdr.fdr_nbytes;
2913483Spc157239 		fdr32.fdr_addr = (caddr32_t)(uintptr_t)fdr.fdr_addr;
29140Sstevel@tonic-gate 		if (ddi_copyout(&fdr32, (caddr_t)arg, sizeof (fdr32), mode)) {
29150Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
29167656SSherry.Moore@Sun.COM 			    (C, "fdrawioctl: can't copy results32\n"));
29170Sstevel@tonic-gate 			err = EFAULT;
29180Sstevel@tonic-gate 		}
29190Sstevel@tonic-gate 		break;
29200Sstevel@tonic-gate #endif
29210Sstevel@tonic-gate 	case DDI_MODEL_NONE:
29220Sstevel@tonic-gate 	default:
29230Sstevel@tonic-gate 		if (ddi_copyout(&fdr, (caddr_t)arg, sizeof (fdr), mode)) {
29240Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
29257656SSherry.Moore@Sun.COM 			    (C, "fdrawioctl: can't copy results\n"));
29260Sstevel@tonic-gate 			err = EFAULT;
29270Sstevel@tonic-gate 		}
29280Sstevel@tonic-gate 		break;
29290Sstevel@tonic-gate 	}
29300Sstevel@tonic-gate 
29310Sstevel@tonic-gate 	fdretcsb(fdc);
29320Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
29330Sstevel@tonic-gate 	return (0);
29340Sstevel@tonic-gate }
29350Sstevel@tonic-gate 
29360Sstevel@tonic-gate /*
29370Sstevel@tonic-gate  * fdformat
29380Sstevel@tonic-gate  *	format a track
29390Sstevel@tonic-gate  * For PIO, builds a table of sector data values with 16 bytes
29400Sstevel@tonic-gate  * (sizeof fdc's fifo) of dummy on end.	 This is so than when fdc->c_len
29410Sstevel@tonic-gate  * goes to 0 and fd_intr sends a TC that all the real formatting will
29420Sstevel@tonic-gate  * have already been done.
29430Sstevel@tonic-gate  *
29440Sstevel@tonic-gate  *	- called with the low level lock held
29450Sstevel@tonic-gate  */
29460Sstevel@tonic-gate static int
fdformat(struct fdctlr * fdc,int unit,int cyl,int hd)29470Sstevel@tonic-gate fdformat(struct fdctlr *fdc, int unit, int cyl, int hd)
29480Sstevel@tonic-gate {
29490Sstevel@tonic-gate 	struct fdcsb *csb;
29500Sstevel@tonic-gate 	struct fdunit *un;
29510Sstevel@tonic-gate 	struct fd_char *ch;
29520Sstevel@tonic-gate 	int	cmdresult;
29530Sstevel@tonic-gate 	uchar_t	*fmthdrs;
29540Sstevel@tonic-gate 	caddr_t fd;
29550Sstevel@tonic-gate 	int	i;
29560Sstevel@tonic-gate 	size_t	real_length;
29570Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
29580Sstevel@tonic-gate 	ddi_acc_handle_t mem_handle;
29590Sstevel@tonic-gate 
29600Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_FORM,
29610Sstevel@tonic-gate 	    (C, "fdformat cyl %d, hd %d\n", cyl, hd));
29620Sstevel@tonic-gate 	fdgetcsb(fdc);
29630Sstevel@tonic-gate 
29640Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
29650Sstevel@tonic-gate 
29660Sstevel@tonic-gate 	csb = &fdc->c_csb;
29670Sstevel@tonic-gate 	un = fdc->c_un;
29680Sstevel@tonic-gate 	ch = un->un_chars;
29690Sstevel@tonic-gate 
29700Sstevel@tonic-gate 	/* setup common things in csb */
29710Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
29720Sstevel@tonic-gate 
29730Sstevel@tonic-gate 	/*
29740Sstevel@tonic-gate 	 * The controller needs to do a seek before
29750Sstevel@tonic-gate 	 * each format to get to right cylinder.
29760Sstevel@tonic-gate 	 */
29770Sstevel@tonic-gate 	if (fdrecalseek(fdc, unit, cyl, FDXC_CHECKCHG)) {
29780Sstevel@tonic-gate 		fdretcsb(fdc);
29790Sstevel@tonic-gate 		return (EIO);
29800Sstevel@tonic-gate 	}
29810Sstevel@tonic-gate 
29820Sstevel@tonic-gate 	/*
29830Sstevel@tonic-gate 	 * now do the format itself
29840Sstevel@tonic-gate 	 */
29850Sstevel@tonic-gate 	csb->csb_nrslts = NRBRW;
29860Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
29870Sstevel@tonic-gate 
29880Sstevel@tonic-gate 	csb->csb_cmds[0] = FDRAW_FORMAT;
29890Sstevel@tonic-gate 	/* always or in MFM bit */
29900Sstevel@tonic-gate 	csb->csb_cmds[0] |= MFM;
29910Sstevel@tonic-gate 	csb->csb_cmds[1] = (hd << 2) | (unit & 0x03);
29920Sstevel@tonic-gate 	csb->csb_cmds[2] = ch->fdc_medium ? 3 : 2;
29930Sstevel@tonic-gate 	csb->csb_cmds[3] = ch->fdc_secptrack;
29940Sstevel@tonic-gate 	csb->csb_cmds[4] = GPLF;
29950Sstevel@tonic-gate 	csb->csb_cmds[5] = FDATA;
29960Sstevel@tonic-gate 	csb->csb_ncmds = 6;
29970Sstevel@tonic-gate 	csb->csb_maxretry = rwretry;
29980Sstevel@tonic-gate 	csb->csb_retrys = 0;
29990Sstevel@tonic-gate 
30000Sstevel@tonic-gate 	/*
30010Sstevel@tonic-gate 	 * NOTE: have to add size of fifo also - for dummy format action
30020Sstevel@tonic-gate 	 * if PIO is being used.
30030Sstevel@tonic-gate 	 */
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate 
30060Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
30070Sstevel@tonic-gate 
30080Sstevel@tonic-gate 		csb->csb_len = (uint_t)4 * ch->fdc_secptrack;
30090Sstevel@tonic-gate 
30100Sstevel@tonic-gate 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
30110Sstevel@tonic-gate 		attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
30120Sstevel@tonic-gate 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
30130Sstevel@tonic-gate 
30140Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
30150Sstevel@tonic-gate 
30160Sstevel@tonic-gate 		cmdresult = ddi_dma_mem_alloc(fdc->c_dmahandle, csb->csb_len,
30177656SSherry.Moore@Sun.COM 		    &attr, DDI_DMA_STREAMING,
30187656SSherry.Moore@Sun.COM 		    DDI_DMA_DONTWAIT, 0, &fd, &real_length,
30197656SSherry.Moore@Sun.COM 		    &mem_handle);
30200Sstevel@tonic-gate 
30210Sstevel@tonic-gate 		if (cmdresult != DDI_SUCCESS) {
30220Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
30230Sstevel@tonic-gate 			return (cmdresult);
30240Sstevel@tonic-gate 		}
30250Sstevel@tonic-gate 
30260Sstevel@tonic-gate 		fdc->c_csb.csb_read = CSB_WRITE;
30270Sstevel@tonic-gate 		if (fdstart_dma(fdc, fd,  csb->csb_len) != 0) {
30280Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
30290Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
30300Sstevel@tonic-gate 			return (-1);
30310Sstevel@tonic-gate 		}
30320Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
30330Sstevel@tonic-gate 
30340Sstevel@tonic-gate 
30350Sstevel@tonic-gate 	} else {
30360Sstevel@tonic-gate 		csb->csb_len = (uint_t)4 * ch->fdc_secptrack + 16;
30370Sstevel@tonic-gate 		fd = kmem_zalloc(csb->csb_len, KM_SLEEP);
30380Sstevel@tonic-gate 		fmthdrs = (uchar_t *)fd;
30390Sstevel@tonic-gate 	}
30400Sstevel@tonic-gate 
30410Sstevel@tonic-gate 	csb->csb_addr = (caddr_t)fd;
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate 	for (i = 1; i <= ch->fdc_secptrack; i++) {
30440Sstevel@tonic-gate 		*fd++ = (uchar_t)cyl;		/* cylinder */
30450Sstevel@tonic-gate 		*fd++ = (uchar_t)hd;		/* head */
30460Sstevel@tonic-gate 		*fd++ = (uchar_t)i;	/* sector number */
30470Sstevel@tonic-gate 		*fd++ = ch->fdc_medium ? 3 : 2; /* sec_size code */
30480Sstevel@tonic-gate 	}
30490Sstevel@tonic-gate 
30500Sstevel@tonic-gate 	if ((cmdresult = fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG)) == 0) {
30510Sstevel@tonic-gate 		if (csb->csb_cmdstat)
30520Sstevel@tonic-gate 			cmdresult = EIO;	/* XXX TBD NYD for now */
30530Sstevel@tonic-gate 	}
30540Sstevel@tonic-gate 
30550Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
30560Sstevel@tonic-gate 		ddi_dma_mem_free(&mem_handle);
30570Sstevel@tonic-gate 	} else {
30580Sstevel@tonic-gate 		kmem_free((caddr_t)fmthdrs, csb->csb_len);
30590Sstevel@tonic-gate 	}
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	fdretcsb(fdc);
30620Sstevel@tonic-gate 
30630Sstevel@tonic-gate 	return (cmdresult);
30640Sstevel@tonic-gate }
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate /*
30670Sstevel@tonic-gate  * fdstart
30680Sstevel@tonic-gate  *	called from fd_strategy() or from fdXXXX() to setup and
30690Sstevel@tonic-gate  *	start operations of read or write only (using buf structs).
30700Sstevel@tonic-gate  *	Because the chip doesn't handle crossing cylinder boundaries on
30710Sstevel@tonic-gate  *	the fly, this takes care of those boundary conditions.	Note that
30720Sstevel@tonic-gate  *	it sleeps until the operation is done *within fdstart* - so that
30730Sstevel@tonic-gate  *	when fdstart returns, the operation is already done.
30740Sstevel@tonic-gate  *
30750Sstevel@tonic-gate  *	- called with the low level lock held
30760Sstevel@tonic-gate  *
30770Sstevel@tonic-gate  */
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate static int slavio_index_pulse_work_around = 0;
30800Sstevel@tonic-gate 
30810Sstevel@tonic-gate static void
fdstart(struct fdctlr * fdc)30820Sstevel@tonic-gate fdstart(struct fdctlr *fdc)
30830Sstevel@tonic-gate {
30840Sstevel@tonic-gate 	struct buf *bp;
30850Sstevel@tonic-gate 	struct fdcsb *csb;
30860Sstevel@tonic-gate 	struct fdunit *un;
30870Sstevel@tonic-gate 	struct fd_char *ch;
30880Sstevel@tonic-gate 	struct dk_map32 *dkm;
30890Sstevel@tonic-gate 	uint_t	part;		/* partition number for the transfer */
30900Sstevel@tonic-gate 	uint_t	start_part;	/* starting block of the partition */
30910Sstevel@tonic-gate 	uint_t	last_part;	/* last block of the partition */
30920Sstevel@tonic-gate 	uint_t	blk;		/* starting block of transfer on diskette */
30930Sstevel@tonic-gate 	uint_t	sect;		/* starting block's offset into track */
30940Sstevel@tonic-gate 	uint_t	cyl;		/* starting cylinder of the transfer */
30950Sstevel@tonic-gate 	uint_t	bincyl;		/* starting blocks's offset into cylinder */
30960Sstevel@tonic-gate 	uint_t	secpcyl;	/* number of sectors per cylinder */
30970Sstevel@tonic-gate 	uint_t	phys_blkno;	/* no. of blocks on the diskette */
30980Sstevel@tonic-gate 	uint_t	head;		/* one of two diskette heads */
30990Sstevel@tonic-gate 	uint_t	unit;
31000Sstevel@tonic-gate 	uint_t	len, tlen;
31010Sstevel@tonic-gate 	caddr_t addr;
31020Sstevel@tonic-gate 	caddr_t temp_addr;
31030Sstevel@tonic-gate 	uint_t	partial_read = 0;
31040Sstevel@tonic-gate 	int sb_temp_buf_used = 0;
31050Sstevel@tonic-gate 
31060Sstevel@tonic-gate 	bp = fdc->c_actf;
31070Sstevel@tonic-gate 
31080Sstevel@tonic-gate 	while (bp != NULL) {
31090Sstevel@tonic-gate 
31100Sstevel@tonic-gate 		fdc->c_actf = bp->av_forw;
31110Sstevel@tonic-gate 		fdc->c_current = bp;
31120Sstevel@tonic-gate 
31130Sstevel@tonic-gate 		/*
31140Sstevel@tonic-gate 		 * Initialize the buf structure.  The residual count is
31150Sstevel@tonic-gate 		 * initially the number of bytes to be read or written
31160Sstevel@tonic-gate 		 */
31170Sstevel@tonic-gate 		bp->b_flags &= ~B_ERROR;
31180Sstevel@tonic-gate 		bp->b_error = 0;
31190Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
31200Sstevel@tonic-gate 		bp_mapin(bp);			/* map in buffers */
31210Sstevel@tonic-gate 
31220Sstevel@tonic-gate 		addr = bp->b_un.b_addr;		/* assign buffer address */
31230Sstevel@tonic-gate 
31240Sstevel@tonic-gate 		/*
31250Sstevel@tonic-gate 		 * Find the unit and partition numbers.
31260Sstevel@tonic-gate 		 */
31270Sstevel@tonic-gate 		unit = fdc->c_un->un_unit_no;
31280Sstevel@tonic-gate 		un = fdc->c_un;
31290Sstevel@tonic-gate 		ch = un->un_chars;
31300Sstevel@tonic-gate 		part = FDPARTITION(bp->b_edev);
31310Sstevel@tonic-gate 		dkm = &un->un_label.dkl_map[part];
31320Sstevel@tonic-gate 
31330Sstevel@tonic-gate 		if (un->un_chars->fdc_medium) {
31340Sstevel@tonic-gate 			phys_blkno = bp->b_blkno >> 1;
31350Sstevel@tonic-gate 		} else {
31360Sstevel@tonic-gate 			phys_blkno = bp->b_blkno;
31370Sstevel@tonic-gate 		}
31380Sstevel@tonic-gate 
31390Sstevel@tonic-gate 		if (un->un_iostat) {
31400Sstevel@tonic-gate 			kstat_waitq_to_runq(KIOSP);
31410Sstevel@tonic-gate 		}
31420Sstevel@tonic-gate 
31430Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_STRT,
31440Sstevel@tonic-gate 		    (C, "fdstart: bp=0x%p blkno=0x%x bcount=0x%x\n",
31450Sstevel@tonic-gate 		    (void *)bp, (int)bp->b_blkno, (int)bp->b_bcount));
31460Sstevel@tonic-gate 
31470Sstevel@tonic-gate 		/*
31480Sstevel@tonic-gate 		 * Get the csb and initialize the values that are the same
31490Sstevel@tonic-gate 		 * for DMA and PIO.
31500Sstevel@tonic-gate 		 */
31510Sstevel@tonic-gate 		fdgetcsb(fdc);		/* get csb (maybe wait for it) */
31520Sstevel@tonic-gate 		csb = &fdc->c_csb;
31530Sstevel@tonic-gate 		csb->csb_unit = unit;		/* floppy unit number */
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 
31560Sstevel@tonic-gate 		/*
31570Sstevel@tonic-gate 		 * bugID:4133425 : If the controller is SLAVIO, and
31580Sstevel@tonic-gate 		 * the read does not reach end of track, then modify
31590Sstevel@tonic-gate 		 * the tlen to read until the end of track to a temp
31600Sstevel@tonic-gate 		 * buffer and disable MT. After the read is over,
31610Sstevel@tonic-gate 		 * copy the useful portion of the data to 'addr'.
31620Sstevel@tonic-gate 		 * Enable this feature only when
31630Sstevel@tonic-gate 		 * slavio_index_pulse_work_aound variable is
31640Sstevel@tonic-gate 		 * set in /etc/system.
31650Sstevel@tonic-gate 		 */
31660Sstevel@tonic-gate 
31670Sstevel@tonic-gate 
31680Sstevel@tonic-gate 		if (bp->b_flags & B_READ) {
31690Sstevel@tonic-gate 			if (((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
31707656SSherry.Moore@Sun.COM 			    slavio_index_pulse_work_around) ||
31717656SSherry.Moore@Sun.COM 			    (fdc->c_fdtype & FDCTYPE_TCBUG))
31720Sstevel@tonic-gate 				csb->csb_cmds[0] = SK | FDRAW_RDCMD | MFM;
31730Sstevel@tonic-gate 			else
31740Sstevel@tonic-gate 				csb->csb_cmds[0] = MT | SK | FDRAW_RDCMD | MFM;
31750Sstevel@tonic-gate 		} else {
31760Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_TCBUG)
31770Sstevel@tonic-gate 				csb->csb_cmds[0] = FDRAW_WRCMD | MFM;
31780Sstevel@tonic-gate 			else
31790Sstevel@tonic-gate 				csb->csb_cmds[0] = MT | FDRAW_WRCMD | MFM;
31800Sstevel@tonic-gate 		}
31810Sstevel@tonic-gate 
31820Sstevel@tonic-gate 
31830Sstevel@tonic-gate 		if (bp->b_flags & B_READ)
31840Sstevel@tonic-gate 			fdc->c_csb.csb_read = CSB_READ;
31850Sstevel@tonic-gate 		else
31860Sstevel@tonic-gate 			fdc->c_csb.csb_read = CSB_WRITE;
31870Sstevel@tonic-gate 
31880Sstevel@tonic-gate 
31890Sstevel@tonic-gate 		csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size  */
31900Sstevel@tonic-gate 		csb->csb_cmds[6] = ch->fdc_secptrack; /* EOT-# of sectors/trk */
31910Sstevel@tonic-gate 		csb->csb_cmds[7] = GPLN;	/* GPL - gap 3 size code */
31920Sstevel@tonic-gate 		csb->csb_cmds[8] = SSSDTL;	/* DTL - be 0xFF if N != 0 */
31930Sstevel@tonic-gate 
31940Sstevel@tonic-gate 		csb->csb_ncmds = NCBRW;		/* number of command bytes */
31950Sstevel@tonic-gate 		csb->csb_nrslts = NRBRW;	/* number of result bytes */
31960Sstevel@tonic-gate 
31970Sstevel@tonic-gate 
31980Sstevel@tonic-gate 		/*
31990Sstevel@tonic-gate 		 * opflags for interrupt handler, et.al.
32000Sstevel@tonic-gate 		 */
32010Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
32020Sstevel@tonic-gate 
32030Sstevel@tonic-gate 
32040Sstevel@tonic-gate 		/*
32050Sstevel@tonic-gate 		 * Make sure the transfer does not go off the end
32060Sstevel@tonic-gate 		 * of the partition.  Limit the actual amount transferred
32070Sstevel@tonic-gate 		 * to fit the partition.
32080Sstevel@tonic-gate 		 */
32090Sstevel@tonic-gate 
32100Sstevel@tonic-gate 		blk = phys_blkno;
32110Sstevel@tonic-gate 		start_part = (dkm->dkl_cylno * ch->fdc_secptrack
32127656SSherry.Moore@Sun.COM 		    * ch->fdc_nhead);
32130Sstevel@tonic-gate 		blk = blk + start_part;
32140Sstevel@tonic-gate 		last_part = start_part + dkm->dkl_nblk;
32150Sstevel@tonic-gate 
32160Sstevel@tonic-gate 		if ((blk + (bp->b_bcount / ch->fdc_sec_size)) > last_part)
32170Sstevel@tonic-gate 			len = (last_part - blk) * ch->fdc_sec_size;
32180Sstevel@tonic-gate 		else
32190Sstevel@tonic-gate 			len = (uint_t)bp->b_bcount;
32200Sstevel@tonic-gate 
32210Sstevel@tonic-gate 		/*
32220Sstevel@tonic-gate 		 * now we have the real start blk,
32230Sstevel@tonic-gate 		 * addr and len for xfer op
32240Sstevel@tonic-gate 		 * sectors per cylinder
32250Sstevel@tonic-gate 		 */
32260Sstevel@tonic-gate 		secpcyl = ch->fdc_nhead * ch->fdc_secptrack;
32270Sstevel@tonic-gate 
32280Sstevel@tonic-gate 		/*
32290Sstevel@tonic-gate 		 * The controller can transfer up to a cylinder at a time.
32300Sstevel@tonic-gate 		 * Early revs of the 82077 have a bug that causes the chip to
32310Sstevel@tonic-gate 		 * fail to respond to the Terminal Count signal.  Due to this
32320Sstevel@tonic-gate 		 * bug, controllers with type FDCTYPE_TCBUG, only transfer up
32330Sstevel@tonic-gate 		 * to a track at a time.
32340Sstevel@tonic-gate 		 * See earlier comment for bugID:4133425 for index pulse
32350Sstevel@tonic-gate 		 * work around.
32360Sstevel@tonic-gate 		 */
32370Sstevel@tonic-gate 
32380Sstevel@tonic-gate 		while (len != 0) {
32390Sstevel@tonic-gate 
32400Sstevel@tonic-gate 			cyl = blk / secpcyl;	/* cylinder of transfer */
32410Sstevel@tonic-gate 			bincyl = blk % secpcyl;	/* blk within cylinder */
32420Sstevel@tonic-gate 			head = bincyl / ch->fdc_secptrack;
32430Sstevel@tonic-gate 			sect = (bincyl % ch->fdc_secptrack) + 1;
32440Sstevel@tonic-gate 						/* sect w/in track */
32450Sstevel@tonic-gate 
32460Sstevel@tonic-gate 			/*
32470Sstevel@tonic-gate 			 * If the desired block and length will go beyond the
32480Sstevel@tonic-gate 			 * cylinder end, limit it to the cylinder end.
32490Sstevel@tonic-gate 			 */
32500Sstevel@tonic-gate 
32510Sstevel@tonic-gate 			if ((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
32527656SSherry.Moore@Sun.COM 			    slavio_index_pulse_work_around &&
32537656SSherry.Moore@Sun.COM 			    (fdc->c_csb.csb_read == CSB_READ)) {
32540Sstevel@tonic-gate 
32550Sstevel@tonic-gate 				tlen = (ch->fdc_secptrack - sect + 1) *
32567656SSherry.Moore@Sun.COM 				    ch->fdc_sec_size;
32570Sstevel@tonic-gate 				if (len < tlen) {
32580Sstevel@tonic-gate 					partial_read = 1;
32590Sstevel@tonic-gate 					temp_addr = (caddr_t)kmem_alloc(tlen,
32607656SSherry.Moore@Sun.COM 					    KM_SLEEP);
32610Sstevel@tonic-gate 				}
32620Sstevel@tonic-gate 
32630Sstevel@tonic-gate 			} else if (fdc->c_fdtype & FDCTYPE_TCBUG) {
32640Sstevel@tonic-gate 				tlen = len;
32650Sstevel@tonic-gate 				if (len > ((ch->fdc_secptrack - sect + 1) *
32667656SSherry.Moore@Sun.COM 				    ch->fdc_sec_size))
32670Sstevel@tonic-gate 					tlen = (ch->fdc_secptrack - sect + 1)
32687656SSherry.Moore@Sun.COM 					    * ch->fdc_sec_size;
32690Sstevel@tonic-gate 			} else {
32700Sstevel@tonic-gate 				if (len > ((secpcyl - bincyl)
32717656SSherry.Moore@Sun.COM 				    * ch->fdc_sec_size))
32720Sstevel@tonic-gate 					tlen = (secpcyl - bincyl)
32737656SSherry.Moore@Sun.COM 					    * ch->fdc_sec_size;
32740Sstevel@tonic-gate 
32750Sstevel@tonic-gate 				else
32760Sstevel@tonic-gate 					tlen = len;
32770Sstevel@tonic-gate 			}
32780Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB) {
32790Sstevel@tonic-gate 				/*
32800Sstevel@tonic-gate 				 * To avoid underrun errors during IFB activity.
32810Sstevel@tonic-gate 				 */
32820Sstevel@tonic-gate 				if (tlen > max_fd_dma_len)
32830Sstevel@tonic-gate 					tlen = max_fd_dma_len;
32840Sstevel@tonic-gate 			}
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRT,
32870Sstevel@tonic-gate 			    (C, "	blk 0x%x, addr 0x%p, len 0x%x\n",
32880Sstevel@tonic-gate 			    blk, (void *)addr, len));
32890Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRT,
32900Sstevel@tonic-gate 			    (C, "cyl:%x, head:%x, sec:%x\n",
32910Sstevel@tonic-gate 			    cyl, head, sect));
32920Sstevel@tonic-gate 
32930Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRT,
32940Sstevel@tonic-gate 			    (C, "	resid 0x%lx, tlen %d\n",
32950Sstevel@tonic-gate 			    bp->b_resid, tlen));
32960Sstevel@tonic-gate 
32970Sstevel@tonic-gate 			/*
32980Sstevel@tonic-gate 			 * Finish programming the command
32990Sstevel@tonic-gate 			 */
33000Sstevel@tonic-gate 			csb->csb_cmds[1] = (head << 2) | unit;
33010Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB)
33020Sstevel@tonic-gate 				csb->csb_cmds[1] |= IPS;
33030Sstevel@tonic-gate 
33040Sstevel@tonic-gate 			csb->csb_cmds[2] = cyl;	/* C - cylinder address */
33050Sstevel@tonic-gate 			csb->csb_cmds[3] = head;	/* H - head number */
33060Sstevel@tonic-gate 			csb->csb_cmds[4] = sect;	/* R - sector number */
33070Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_TCBUG)
33080Sstevel@tonic-gate 				csb->csb_cmds[6] = sect +
33097656SSherry.Moore@Sun.COM 				    (tlen / ch->fdc_sec_size) - 1;
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate 			csb->csb_len = tlen;
33120Sstevel@tonic-gate 			if (partial_read)
33130Sstevel@tonic-gate 				csb->csb_addr = temp_addr;
33140Sstevel@tonic-gate 			else
33150Sstevel@tonic-gate 				csb->csb_addr = addr;
33160Sstevel@tonic-gate 
33170Sstevel@tonic-gate 			/* retry this many times max */
33180Sstevel@tonic-gate 			csb->csb_maxretry = rwretry;
33190Sstevel@tonic-gate 			csb->csb_retrys = 0;
33200Sstevel@tonic-gate 
33210Sstevel@tonic-gate 			/* If platform supports DMA, set up DMA resources */
33220Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_DMA) {
33230Sstevel@tonic-gate 				if ((fdc->c_fdtype & FDCTYPE_SB) &&
3324483Spc157239 				    (((uint32_t)(uintptr_t)addr & 0xFFFF0000) !=
3325483Spc157239 				    (((uint32_t)(uintptr_t)addr + tlen) &
3326483Spc157239 				    0xFFFF0000))) {
33270Sstevel@tonic-gate 					csb->csb_addr = fdc->dma_buf;
33280Sstevel@tonic-gate 					sb_temp_buf_used = 1;
33290Sstevel@tonic-gate 					if (csb->csb_read != CSB_READ) {
33300Sstevel@tonic-gate 						bcopy(addr, fdc->dma_buf, tlen);
33310Sstevel@tonic-gate 				}
33320Sstevel@tonic-gate 			}
33330Sstevel@tonic-gate 				mutex_enter(&fdc->c_hilock);
33340Sstevel@tonic-gate 
33350Sstevel@tonic-gate 				if (fdstart_dma(fdc, csb->csb_addr,
33367656SSherry.Moore@Sun.COM 				    tlen) != 0) {
33370Sstevel@tonic-gate 
33380Sstevel@tonic-gate 					bp->b_flags |= B_ERROR;
33390Sstevel@tonic-gate 					bp->b_error = EAGAIN;
33400Sstevel@tonic-gate 
33410Sstevel@tonic-gate 					mutex_exit(&fdc->c_hilock);
33420Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_STRT,
33437656SSherry.Moore@Sun.COM 					    (C, "fdstart: no dma resources\n"));
33440Sstevel@tonic-gate 
33450Sstevel@tonic-gate 					break;
33460Sstevel@tonic-gate 				}
33470Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
33480Sstevel@tonic-gate 
33490Sstevel@tonic-gate 			}
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate 			bp->b_error = fdexec(fdc, FDXC_SLEEP|FDXC_CHECKCHG);
33520Sstevel@tonic-gate 			if (bp->b_error != 0) {
33530Sstevel@tonic-gate 				/*
33540Sstevel@tonic-gate 				 * error in fdexec
33550Sstevel@tonic-gate 				 */
33560Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_STRT, (C,
33570Sstevel@tonic-gate 				    "fdstart: bad exec of bp: 0x%p, err %d\n",
33580Sstevel@tonic-gate 				    (void *)bp, bp->b_error));
33590Sstevel@tonic-gate 
33600Sstevel@tonic-gate 				bp->b_flags |= B_ERROR;
33610Sstevel@tonic-gate 				if (partial_read) {
33620Sstevel@tonic-gate 					partial_read = 0;
33630Sstevel@tonic-gate 					kmem_free(temp_addr, tlen);
33640Sstevel@tonic-gate 				}
33650Sstevel@tonic-gate 				break;
33660Sstevel@tonic-gate 			}
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate 			/*
33690Sstevel@tonic-gate 			 * If it was a partial read, copy the useful
33700Sstevel@tonic-gate 			 * portion of data to 'addr'.
33710Sstevel@tonic-gate 			 */
33720Sstevel@tonic-gate 			if (partial_read) {
33730Sstevel@tonic-gate 				partial_read = 0;
33740Sstevel@tonic-gate 				bcopy(temp_addr, addr, len);
33750Sstevel@tonic-gate 				kmem_free(temp_addr, tlen);
33760Sstevel@tonic-gate 				tlen = len;
33770Sstevel@tonic-gate 			}
33780Sstevel@tonic-gate 			if ((fdc->c_fdtype & FDCTYPE_SB) &&
33797656SSherry.Moore@Sun.COM 			    (csb->csb_read == CSB_READ)) {
33800Sstevel@tonic-gate 				if (sb_temp_buf_used) {
33810Sstevel@tonic-gate 					bcopy(fdc->dma_buf, addr, tlen);
33820Sstevel@tonic-gate 					sb_temp_buf_used = 0;
33830Sstevel@tonic-gate 				}
33840Sstevel@tonic-gate 			}
33850Sstevel@tonic-gate 
33860Sstevel@tonic-gate 			blk += tlen / ch->fdc_sec_size;
33870Sstevel@tonic-gate 			len -= tlen;
33880Sstevel@tonic-gate 			addr += tlen;
33890Sstevel@tonic-gate 			bp->b_resid -= tlen;
33900Sstevel@tonic-gate 
33910Sstevel@tonic-gate 		}
33920Sstevel@tonic-gate 
33930Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_STRT,
33940Sstevel@tonic-gate 		    (C, "fdstart done: b_resid %lu, b_count %lu, csb_rlen %d\n",
33950Sstevel@tonic-gate 		    bp->b_resid, bp->b_bcount, fdc->c_csb.csb_rlen));
33960Sstevel@tonic-gate 
33970Sstevel@tonic-gate 		fdc->c_current = 0;
33980Sstevel@tonic-gate 		fdretcsb(fdc);
33990Sstevel@tonic-gate 		if (un->un_iostat) {
34000Sstevel@tonic-gate 			if (bp->b_flags & B_READ) {
34010Sstevel@tonic-gate 				KIOSP->reads++;
34020Sstevel@tonic-gate 				KIOSP->nread +=
34037656SSherry.Moore@Sun.COM 				    (bp->b_bcount - bp->b_resid);
34040Sstevel@tonic-gate 			} else {
34050Sstevel@tonic-gate 				KIOSP->writes++;
34060Sstevel@tonic-gate 				KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
34070Sstevel@tonic-gate 			}
34080Sstevel@tonic-gate 			kstat_runq_exit(KIOSP);
34090Sstevel@tonic-gate 		}
34100Sstevel@tonic-gate 		biodone(bp);
34110Sstevel@tonic-gate 
34120Sstevel@tonic-gate 		/*
34130Sstevel@tonic-gate 		 * Look at the next buffer
34140Sstevel@tonic-gate 		 */
34150Sstevel@tonic-gate 		bp = fdc->c_actf;
34160Sstevel@tonic-gate 
34170Sstevel@tonic-gate 	}
34180Sstevel@tonic-gate }
34190Sstevel@tonic-gate 
34200Sstevel@tonic-gate /*
34210Sstevel@tonic-gate  * Set up DMA resources
34220Sstevel@tonic-gate  * The DMA handle was initialized in fd_attach()
34230Sstevel@tonic-gate  * Assumes the handle has already been allocated by fd_attach()
34240Sstevel@tonic-gate  */
34250Sstevel@tonic-gate static int
fdstart_dma(struct fdctlr * fdc,caddr_t addr,uint_t len)34260Sstevel@tonic-gate fdstart_dma(struct fdctlr *fdc, caddr_t addr, uint_t len)
34270Sstevel@tonic-gate {
34280Sstevel@tonic-gate 	int		flags;		/* flags for setting up resources */
34290Sstevel@tonic-gate 	int		res;
34300Sstevel@tonic-gate 
34310Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: start\n"));
34320Sstevel@tonic-gate 
34330Sstevel@tonic-gate 	if (fdc->c_csb.csb_read == CSB_READ) {
34340Sstevel@tonic-gate 		flags = DDI_DMA_READ;
34350Sstevel@tonic-gate 	} else {
34360Sstevel@tonic-gate 		flags = DDI_DMA_WRITE;
34370Sstevel@tonic-gate 	}
34380Sstevel@tonic-gate 
34390Sstevel@tonic-gate 
34400Sstevel@tonic-gate 	/* allow partial mapping to maximize the portability of the driver */
34410Sstevel@tonic-gate 	flags = flags | DDI_DMA_PARTIAL;
34420Sstevel@tonic-gate 
34430Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: amt. asked for %d\n",
34447656SSherry.Moore@Sun.COM 	    len));
34450Sstevel@tonic-gate 
34460Sstevel@tonic-gate 	/*
34470Sstevel@tonic-gate 	 * Zero out the current cookie.  This is done to ensure that
34480Sstevel@tonic-gate 	 * the previous transfers cookie information can in no way be
34490Sstevel@tonic-gate 	 * used.
34500Sstevel@tonic-gate 	 */
34510Sstevel@tonic-gate 	bzero((char *)&fdc->c_csb.csb_dmacookie,
34527656SSherry.Moore@Sun.COM 	    sizeof (fdc->c_csb.csb_dmacookie));
34530Sstevel@tonic-gate 	fdc->c_csb.csb_nwin = 0;
34540Sstevel@tonic-gate 	fdc->c_csb.csb_windex = 0;
34550Sstevel@tonic-gate 	fdc->c_csb.csb_ccount = 0;
34560Sstevel@tonic-gate 
34570Sstevel@tonic-gate 	res = ddi_dma_addr_bind_handle(fdc->c_dmahandle, NULL, addr, len,
34587656SSherry.Moore@Sun.COM 	    flags, DDI_DMA_DONTWAIT, 0,  &fdc->c_csb.csb_dmacookie,
34597656SSherry.Moore@Sun.COM 	    &fdc->c_csb.csb_ccount);
34600Sstevel@tonic-gate 
34610Sstevel@tonic-gate 	switch (res) {
34620Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
34630Sstevel@tonic-gate 			/*
34640Sstevel@tonic-gate 			 * There is one window. csb_windex is the index
34650Sstevel@tonic-gate 			 * into the array of windows. If there are n
34660Sstevel@tonic-gate 			 * windows then, (0 <= windex <= n-1).  csb_windex
34670Sstevel@tonic-gate 			 * represents the index of the next window
34680Sstevel@tonic-gate 			 * to be processed.
34690Sstevel@tonic-gate 			 */
34700Sstevel@tonic-gate 			fdc->c_csb.csb_nwin = 1;
34710Sstevel@tonic-gate 			fdc->c_csb.csb_windex = 1;
34720Sstevel@tonic-gate 
34730Sstevel@tonic-gate 
34740Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
34757656SSherry.Moore@Sun.COM 			    (C, "fdstart_dma: DDI_DMA_MAPPED\n"));
34760Sstevel@tonic-gate 
34770Sstevel@tonic-gate 			break;
34780Sstevel@tonic-gate 		case DDI_DMA_PARTIAL_MAP:
34790Sstevel@tonic-gate 
34800Sstevel@tonic-gate 			/*
34810Sstevel@tonic-gate 			 * obtain the number of DMA windows
34820Sstevel@tonic-gate 			 */
34830Sstevel@tonic-gate 			if (ddi_dma_numwin(fdc->c_dmahandle,
34847656SSherry.Moore@Sun.COM 			    &fdc->c_csb.csb_nwin) != DDI_SUCCESS) {
34850Sstevel@tonic-gate 				return (-1);
34860Sstevel@tonic-gate 			}
34870Sstevel@tonic-gate 
34880Sstevel@tonic-gate 
34890Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
34907656SSherry.Moore@Sun.COM 			    (C, "fdstart_dma: partially mapped %d windows\n",
34917656SSherry.Moore@Sun.COM 			    fdc->c_csb.csb_nwin));
34920Sstevel@tonic-gate 
34930Sstevel@tonic-gate 			/*
34940Sstevel@tonic-gate 			 * The DMA window currently in use is window number
34950Sstevel@tonic-gate 			 * one.
34960Sstevel@tonic-gate 			 */
34970Sstevel@tonic-gate 			fdc->c_csb.csb_windex = 1;
34980Sstevel@tonic-gate 
34990Sstevel@tonic-gate 			break;
35000Sstevel@tonic-gate 		case DDI_DMA_NORESOURCES:
35010Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35027656SSherry.Moore@Sun.COM 			    (C, "fdstart_dma: no resources\n"));
35030Sstevel@tonic-gate 			return (-1);
35040Sstevel@tonic-gate 		case DDI_DMA_NOMAPPING:
35050Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35067656SSherry.Moore@Sun.COM 			    (C, "fdstart_dma: no mapping\n"));
35070Sstevel@tonic-gate 			return (-1);
35080Sstevel@tonic-gate 		case DDI_DMA_TOOBIG:
35090Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35107656SSherry.Moore@Sun.COM 			    (C, "fdstart_dma: too big\n"));
35110Sstevel@tonic-gate 			return (-1);
35120Sstevel@tonic-gate 
35130Sstevel@tonic-gate 		case DDI_DMA_INUSE:
35140Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35157656SSherry.Moore@Sun.COM 			    (C, "fdstart_dma: dma inuse\n"));
35160Sstevel@tonic-gate 			return (-1);
35170Sstevel@tonic-gate 		default:
35180Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35197656SSherry.Moore@Sun.COM 			    (C, "fdstart_dma: result is 0x%x\n", res));
35200Sstevel@tonic-gate 			return (-1);
35210Sstevel@tonic-gate 
35220Sstevel@tonic-gate 	};
35230Sstevel@tonic-gate 
35240Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA,
35257656SSherry.Moore@Sun.COM 	    (C, "fdstart_dma: bound the handle\n"));
35260Sstevel@tonic-gate 
35270Sstevel@tonic-gate 	ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
35280Sstevel@tonic-gate 
35290Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: done\n"));
35300Sstevel@tonic-gate 	return (0);
35310Sstevel@tonic-gate }
35320Sstevel@tonic-gate 
35330Sstevel@tonic-gate 
35340Sstevel@tonic-gate /*
35350Sstevel@tonic-gate  * fd_unbind_handle: unbind a dma handle if one exists
35360Sstevel@tonic-gate  *		return EIO if unbind failes
35370Sstevel@tonic-gate  */
35380Sstevel@tonic-gate static int
fd_unbind_handle(struct fdctlr * fdc)35390Sstevel@tonic-gate fd_unbind_handle(struct fdctlr *fdc)
35400Sstevel@tonic-gate {
35410Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_DMA) &&
35427656SSherry.Moore@Sun.COM 	    ((fdc->c_csb.csb_read == CSB_READ) ||
35437656SSherry.Moore@Sun.COM 	    (fdc->c_csb.csb_read == CSB_WRITE))) {
35440Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
35450Sstevel@tonic-gate 
35460Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB) {
35470Sstevel@tonic-gate 			if (fdc->sb_dma_lock) {
35480Sstevel@tonic-gate 				release_sb_dma(fdc);
35490Sstevel@tonic-gate 			}
35500Sstevel@tonic-gate 		}
35510Sstevel@tonic-gate 
35520Sstevel@tonic-gate 		/*
35530Sstevel@tonic-gate 		 * If the byte count isn't zero, then the DMA engine is
35540Sstevel@tonic-gate 		 * still doing a transfer.  If the byte count is nonzero,
35550Sstevel@tonic-gate 		 * reset the DMA engine to cause it to drain.
35560Sstevel@tonic-gate 		 */
35570Sstevel@tonic-gate 
35580Sstevel@tonic-gate 		if (get_data_count_register(fdc) != 0) {
35597656SSherry.Moore@Sun.COM 			FDERRPRINT(FDEP_L1, FDEM_EXEC,
35607656SSherry.Moore@Sun.COM 			    (C, "unbind & byte count isn't zero\n"));
35617656SSherry.Moore@Sun.COM 
35627656SSherry.Moore@Sun.COM 			reset_dma_controller(fdc);
35637656SSherry.Moore@Sun.COM 			set_dma_control_register(fdc, DCSR_INIT_BITS);
35640Sstevel@tonic-gate 		}
35650Sstevel@tonic-gate 
35660Sstevel@tonic-gate 		if (ddi_dma_unbind_handle(fdc->c_dmahandle) != DDI_SUCCESS) {
35670Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_EXEC,
35687656SSherry.Moore@Sun.COM 			    (C, "problem unbinding the handle\n"));
35690Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
35700Sstevel@tonic-gate 			return (EIO);
35710Sstevel@tonic-gate 		}
35720Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
35730Sstevel@tonic-gate 	}
35740Sstevel@tonic-gate 	return (0);
35750Sstevel@tonic-gate }
35760Sstevel@tonic-gate 
35770Sstevel@tonic-gate /*
35780Sstevel@tonic-gate  * fdexec
35790Sstevel@tonic-gate  *	all commands go through here.  Assumes the command block
35800Sstevel@tonic-gate  *	fdctlr.c_csb is filled in.  The bytes are sent to the
35810Sstevel@tonic-gate  *	controller and then we do whatever else the csb says -
35820Sstevel@tonic-gate  *	like wait for immediate results, etc.
35830Sstevel@tonic-gate  *
35840Sstevel@tonic-gate  *	All waiting for operations done is in here - to allow retrys
35850Sstevel@tonic-gate  *	and checking for disk changed - so we don't have to worry
35860Sstevel@tonic-gate  *	about sleeping at interrupt level.
35870Sstevel@tonic-gate  *
35880Sstevel@tonic-gate  * RETURNS: 0 if all ok,
35890Sstevel@tonic-gate  *	ENXIO - diskette not in drive
35900Sstevel@tonic-gate  *	EBUSY - if chip is locked or busy
35910Sstevel@tonic-gate  *	EIO - for timeout during sending cmds to chip
35920Sstevel@tonic-gate  *
35930Sstevel@tonic-gate  * to sleep: set FDXC_SLEEP, to check for disk
35940Sstevel@tonic-gate  * changed: set FDXC_CHECKCHG
35950Sstevel@tonic-gate  *
35960Sstevel@tonic-gate  *	- called with the lock held
35970Sstevel@tonic-gate  */
35980Sstevel@tonic-gate static int
fdexec(struct fdctlr * fdc,int flags)35990Sstevel@tonic-gate fdexec(struct fdctlr *fdc, int flags)
36000Sstevel@tonic-gate {
36010Sstevel@tonic-gate 	struct fdcsb *csb;
36020Sstevel@tonic-gate 	int	i;
36030Sstevel@tonic-gate 	int	to, unit;
36040Sstevel@tonic-gate 	uchar_t	tmp;
36050Sstevel@tonic-gate 	caddr_t a = (caddr_t)fdc;
36060Sstevel@tonic-gate 
36070Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: flags:%x\n", flags));
36080Sstevel@tonic-gate 
36090Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
36100Sstevel@tonic-gate 
36110Sstevel@tonic-gate 	csb = &fdc->c_csb;
36120Sstevel@tonic-gate 	unit = csb->csb_unit;
36130Sstevel@tonic-gate 
36140Sstevel@tonic-gate 
36150Sstevel@tonic-gate 	ASSERT(unit == fdc->c_un->un_unit_no);
36160Sstevel@tonic-gate 
36170Sstevel@tonic-gate retry:
36180Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: cmd is %s\n",
36197656SSherry.Moore@Sun.COM 	    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
36200Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: transfer rate = %d\n",
36210Sstevel@tonic-gate 	    fdc->c_un->un_chars->fdc_transfer_rate));
36220Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: sec size = %d\n",
36230Sstevel@tonic-gate 	    fdc->c_un->un_chars->fdc_sec_size));
36240Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: nblocks (512) = %d\n",
36250Sstevel@tonic-gate 	    fdc->c_un->un_label.dkl_map[2].dkl_nblk));
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
36280Sstevel@tonic-gate 		fdexec_turn_on_motor(fdc, flags, unit);
36290Sstevel@tonic-gate 	}
36300Sstevel@tonic-gate 
36310Sstevel@tonic-gate 
36320Sstevel@tonic-gate 	fdselect(fdc, unit, 1);	/* select drive */
36330Sstevel@tonic-gate 
36340Sstevel@tonic-gate 	/*
36350Sstevel@tonic-gate 	 * select data rate for this unit/command
36360Sstevel@tonic-gate 	 */
36370Sstevel@tonic-gate 	switch (fdc->c_un->un_chars->fdc_transfer_rate) {
36380Sstevel@tonic-gate 	case 500:
36390Sstevel@tonic-gate 		Dsr(fdc, 0);
36400Sstevel@tonic-gate 		break;
36410Sstevel@tonic-gate 	case 300:
36420Sstevel@tonic-gate 		Dsr(fdc, 1);
36430Sstevel@tonic-gate 		break;
36440Sstevel@tonic-gate 	case 250:
36450Sstevel@tonic-gate 		Dsr(fdc, 2);
36460Sstevel@tonic-gate 		break;
36470Sstevel@tonic-gate 	}
36480Sstevel@tonic-gate 	drv_usecwait(2);
36490Sstevel@tonic-gate 
36500Sstevel@tonic-gate 
36510Sstevel@tonic-gate 	/*
36520Sstevel@tonic-gate 	 * If checking for changed is enabled (i.e., not seeking in checkdisk),
36530Sstevel@tonic-gate 	 * we sample the DSKCHG line to see if the diskette has wandered away.
36540Sstevel@tonic-gate 	 */
36550Sstevel@tonic-gate 	if ((flags & FDXC_CHECKCHG) && fdsense_chng(fdc, unit)) {
36560Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "diskette changed\n"));
36570Sstevel@tonic-gate 		fdc->c_un->un_flags |= FDUNIT_CHANGED;
36580Sstevel@tonic-gate 
36590Sstevel@tonic-gate 		if (fdcheckdisk(fdc, unit)) {
36600Sstevel@tonic-gate 
36610Sstevel@tonic-gate 			(void) fd_unbind_handle(fdc);
36620Sstevel@tonic-gate 			return (ENXIO);
36630Sstevel@tonic-gate 
36640Sstevel@tonic-gate 		}
36650Sstevel@tonic-gate 	}
36660Sstevel@tonic-gate 
36670Sstevel@tonic-gate 	/*
36680Sstevel@tonic-gate 	 * gather some statistics
36690Sstevel@tonic-gate 	 */
36700Sstevel@tonic-gate 	switch (csb->csb_cmds[0] & 0x1f) {
36710Sstevel@tonic-gate 	case FDRAW_RDCMD:
36720Sstevel@tonic-gate 		fdc->fdstats.rd++;
36730Sstevel@tonic-gate 		break;
36740Sstevel@tonic-gate 	case FDRAW_WRCMD:
36750Sstevel@tonic-gate 		fdc->fdstats.wr++;
36760Sstevel@tonic-gate 		break;
36770Sstevel@tonic-gate 	case FDRAW_REZERO:
36780Sstevel@tonic-gate 		fdc->fdstats.recal++;
36790Sstevel@tonic-gate 		break;
36800Sstevel@tonic-gate 	case FDRAW_FORMAT:
36810Sstevel@tonic-gate 		fdc->fdstats.form++;
36820Sstevel@tonic-gate 		break;
36830Sstevel@tonic-gate 	default:
36840Sstevel@tonic-gate 		fdc->fdstats.other++;
36850Sstevel@tonic-gate 		break;
36860Sstevel@tonic-gate 	}
36870Sstevel@tonic-gate 
36880Sstevel@tonic-gate 	/*
36890Sstevel@tonic-gate 	 * Always set the opmode *prior* to poking the chip.
36900Sstevel@tonic-gate 	 * This way we don't have to do any locking at high level.
36910Sstevel@tonic-gate 	 */
36920Sstevel@tonic-gate 	csb->csb_raddr = 0;
36930Sstevel@tonic-gate 	csb->csb_rlen = 0;
36940Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFSEEKOPS) {
36950Sstevel@tonic-gate 		csb->csb_opmode = 2;
36960Sstevel@tonic-gate 	} else if (csb->csb_opflags & CSB_OFIMMEDIATE) {
36970Sstevel@tonic-gate 		csb->csb_opmode = 0;
36980Sstevel@tonic-gate 	} else {
36990Sstevel@tonic-gate 		csb->csb_opmode = 1;	/* normal data xfer commands */
37000Sstevel@tonic-gate 		csb->csb_raddr = csb->csb_addr;
37010Sstevel@tonic-gate 		csb->csb_rlen = csb->csb_len;
37020Sstevel@tonic-gate 	}
37030Sstevel@tonic-gate 
37040Sstevel@tonic-gate 	bzero((caddr_t)csb->csb_rslt, 10);
37050Sstevel@tonic-gate 	csb->csb_status = 0;
37060Sstevel@tonic-gate 	csb->csb_cmdstat = 0;
37070Sstevel@tonic-gate 
37080Sstevel@tonic-gate 
37090Sstevel@tonic-gate 	/*
37100Sstevel@tonic-gate 	 * Program the DMA engine with the length and address of the transfer
37110Sstevel@tonic-gate 	 * (DMA is only used on a read or a write)
37120Sstevel@tonic-gate 	 */
37130Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_DMA) &&
37147656SSherry.Moore@Sun.COM 	    ((fdc->c_csb.csb_read == CSB_READ) ||
37157656SSherry.Moore@Sun.COM 	    (fdc->c_csb.csb_read == CSB_WRITE)))  {
37160Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
37170Sstevel@tonic-gate 
37180Sstevel@tonic-gate 		/* Reset the dcsr to clear it of all errors */
37190Sstevel@tonic-gate 
37200Sstevel@tonic-gate 		reset_dma_controller(fdc);
37210Sstevel@tonic-gate 
37220Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie addr 0x%p\n",
37230Sstevel@tonic-gate 		    (void *)fdc->c_csb.csb_dmacookie.dmac_laddress));
37240Sstevel@tonic-gate 
37250Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie length %ld\n",
37267656SSherry.Moore@Sun.COM 		    fdc->c_csb.csb_dmacookie.dmac_size));
37270Sstevel@tonic-gate 		ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
37280Sstevel@tonic-gate 
37290Sstevel@tonic-gate 		set_data_count_register(fdc,
37307656SSherry.Moore@Sun.COM 		    fdc->c_csb.csb_dmacookie.dmac_size);
37310Sstevel@tonic-gate 		set_data_address_register(fdc,
37327656SSherry.Moore@Sun.COM 		    fdc->c_csb.csb_dmacookie.dmac_laddress);
37330Sstevel@tonic-gate 
37340Sstevel@tonic-gate 		/* Program the DCSR */
37350Sstevel@tonic-gate 
37360Sstevel@tonic-gate 		if (fdc->c_csb.csb_read == CSB_READ)
37370Sstevel@tonic-gate 			set_dma_mode(fdc, CSB_READ);
37380Sstevel@tonic-gate 		else
37390Sstevel@tonic-gate 			set_dma_mode(fdc, CSB_WRITE);
37400Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
37410Sstevel@tonic-gate 	}
37420Sstevel@tonic-gate 
37430Sstevel@tonic-gate 	/*
37440Sstevel@tonic-gate 	 * I saw this (chip unexpectedly busy) happen when i shoved the
37450Sstevel@tonic-gate 	 * floppy into the drive while
37460Sstevel@tonic-gate 	 * running a dd if= /dev/rfd0c.	so it *is* possible for this to happen.
37470Sstevel@tonic-gate 	 * we need to do a ctlr reset ...
37480Sstevel@tonic-gate 	 */
37490Sstevel@tonic-gate 
37500Sstevel@tonic-gate 	if (Msr(fdc) & CB) {
37510Sstevel@tonic-gate 		/* tried to give command to chip when it is busy! */
37520Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_EXEC,
37530Sstevel@tonic-gate 		    (C, "fdc: unexpectedly busy-stat 0x%x\n", Msr(fdc)));
37540Sstevel@tonic-gate 		csb->csb_cmdstat = 1;	/* XXX TBD ERRS NYD for now */
37550Sstevel@tonic-gate 
37560Sstevel@tonic-gate 		(void) fd_unbind_handle(fdc);
37570Sstevel@tonic-gate 		return (EBUSY);
37580Sstevel@tonic-gate 	}
37590Sstevel@tonic-gate 
37600Sstevel@tonic-gate 	/* Give command to the controller */
37610Sstevel@tonic-gate 	for (i = 0; i < (int)csb->csb_ncmds; i++) {
37620Sstevel@tonic-gate 
37630Sstevel@tonic-gate 		/* Test the readiness of the controller to receive the cmd */
37640Sstevel@tonic-gate 		for (to = FD_CRETRY; to; to--) {
37650Sstevel@tonic-gate 			if ((Msr(fdc) & (DIO|RQM)) == RQM)
37660Sstevel@tonic-gate 				break;
37670Sstevel@tonic-gate 		}
37680Sstevel@tonic-gate 		if (to == 0) {
37690Sstevel@tonic-gate 			FDERRPRINT(FDEP_L2, FDEM_EXEC,
37700Sstevel@tonic-gate 			    (C, "fdc: no RQM - stat 0x%x\n", Msr(fdc)));
37710Sstevel@tonic-gate 			csb->csb_cmdstat = 1;
37720Sstevel@tonic-gate 
37730Sstevel@tonic-gate 			(void) fd_unbind_handle(fdc);
37740Sstevel@tonic-gate 			return (EIO);
37750Sstevel@tonic-gate 		}
37760Sstevel@tonic-gate 
37770Sstevel@tonic-gate 		Set_Fifo(fdc, csb->csb_cmds[i]);
37780Sstevel@tonic-gate 
37790Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC,
37800Sstevel@tonic-gate 		    (C, "fdexec: sent 0x%x, Msr 0x%x\n", csb->csb_cmds[i],
37810Sstevel@tonic-gate 		    Msr(fdc)));
37820Sstevel@tonic-gate 
37830Sstevel@tonic-gate 	}
37840Sstevel@tonic-gate 
37850Sstevel@tonic-gate 
37860Sstevel@tonic-gate 	/*
37870Sstevel@tonic-gate 	 * Start watchdog timer on data transfer type commands - required
37880Sstevel@tonic-gate 	 * in case a diskette is not present or is unformatted
37890Sstevel@tonic-gate 	 */
37900Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFTIMEIT) {
37910Sstevel@tonic-gate 		fdc->c_timeid = timeout(fdwatch, a,
37920Sstevel@tonic-gate 		    tosec * drv_usectohz(1000000));
37930Sstevel@tonic-gate 	}
37940Sstevel@tonic-gate 
37950Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC,
37960Sstevel@tonic-gate 	    (C, "fdexec: cmd sent, Msr 0x%x\n", Msr(fdc)));
37970Sstevel@tonic-gate 
37980Sstevel@tonic-gate 	/* If the operation has no results - then just return */
37990Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFNORESULTS) {
38000Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_82077) {
38010Sstevel@tonic-gate 			if (fdc->c_mtimeid == 0) {
38020Sstevel@tonic-gate 				fdc->c_mtimeid = timeout(fdmotoff, a,
38037656SSherry.Moore@Sun.COM 				    Motoff_delay);
38040Sstevel@tonic-gate 			}
38050Sstevel@tonic-gate 		}
38060Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..\n"));
38070Sstevel@tonic-gate 
38080Sstevel@tonic-gate 		/*
38090Sstevel@tonic-gate 		 * Make sure the last byte is received well by the
38100Sstevel@tonic-gate 		 * controller. On faster CPU, it may still be busy
38110Sstevel@tonic-gate 		 * by the time another command comes here.
38120Sstevel@tonic-gate 		 */
38130Sstevel@tonic-gate 		for (to = FD_CRETRY; to; to--) {
38140Sstevel@tonic-gate 			if ((Msr(fdc) & (DIO|RQM)) == RQM)
38150Sstevel@tonic-gate 				break;
38160Sstevel@tonic-gate 			}
38170Sstevel@tonic-gate 		if (to == 0) {
38180Sstevel@tonic-gate 			csb->csb_cmdstat = 1;
38190Sstevel@tonic-gate 			return (EIO);
38200Sstevel@tonic-gate 		}
38210Sstevel@tonic-gate 
38220Sstevel@tonic-gate 		/*
38230Sstevel@tonic-gate 		 * An operation that has no results isn't doing DMA so,
38240Sstevel@tonic-gate 		 * there is no reason to try to unbind a handle
38250Sstevel@tonic-gate 		 */
38260Sstevel@tonic-gate 		return (0);
38270Sstevel@tonic-gate 	}
38280Sstevel@tonic-gate 
38290Sstevel@tonic-gate 	/*
38300Sstevel@tonic-gate 	 * If this operation has no interrupt AND an immediate result
38310Sstevel@tonic-gate 	 * then we just busy wait for the results and stuff them into
38320Sstevel@tonic-gate 	 * the csb
38330Sstevel@tonic-gate 	 */
38340Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFIMMEDIATE) {
38350Sstevel@tonic-gate 		to = FD_RRETRY;
38360Sstevel@tonic-gate 		csb->csb_nrslts = 0;
38370Sstevel@tonic-gate 		/*
38380Sstevel@tonic-gate 		 * Wait while this command is still going on.
38390Sstevel@tonic-gate 		 */
38400Sstevel@tonic-gate 		while ((tmp = Msr(fdc)) & CB) {
38410Sstevel@tonic-gate 			/*
38420Sstevel@tonic-gate 			 * If RQM + DIO, then a result byte is at hand.
38430Sstevel@tonic-gate 			 */
38440Sstevel@tonic-gate 			if ((tmp & (RQM|DIO|CB)) == (RQM|DIO|CB)) {
38450Sstevel@tonic-gate 				csb->csb_rslt[csb->csb_nrslts++] =
38467656SSherry.Moore@Sun.COM 				    Fifo(fdc);
38470Sstevel@tonic-gate 				/*
38480Sstevel@tonic-gate 				 * FDERRPRINT(FDEP_L4, FDEM_EXEC,
38490Sstevel@tonic-gate 				 *    (C, "fdexec: got result 0x%x\n",
38500Sstevel@tonic-gate 				 *    csb->csb_nrslts));
38510Sstevel@tonic-gate 				 */
38520Sstevel@tonic-gate 			} else if (--to == 0) {
38530Sstevel@tonic-gate 				FDERRPRINT(FDEP_L4, FDEM_EXEC,
38540Sstevel@tonic-gate 				    (C, "fdexec: timeout, Msr%x, nr%x\n",
38550Sstevel@tonic-gate 				    Msr(fdc), csb->csb_nrslts));
38560Sstevel@tonic-gate 
38570Sstevel@tonic-gate 				csb->csb_status = 2;
38580Sstevel@tonic-gate 				if (fdc->c_fdtype & FDCTYPE_82077) {
38590Sstevel@tonic-gate 					if (fdc->c_mtimeid == 0) {
38600Sstevel@tonic-gate 						fdc->c_mtimeid = timeout(
38617656SSherry.Moore@Sun.COM 						    fdmotoff, a, Motoff_delay);
38620Sstevel@tonic-gate 					}
38630Sstevel@tonic-gate 				}
38640Sstevel@tonic-gate 				/*
38650Sstevel@tonic-gate 				 * There is no DMA happening.  No need to
38660Sstevel@tonic-gate 				 * try freeing a handle.
38670Sstevel@tonic-gate 				 */
38680Sstevel@tonic-gate 
38690Sstevel@tonic-gate 				return (EIO);
38700Sstevel@tonic-gate 			}
38710Sstevel@tonic-gate 		}
38720Sstevel@tonic-gate 	}
38730Sstevel@tonic-gate 
38740Sstevel@tonic-gate 	/*
38750Sstevel@tonic-gate 	 * If told to sleep here, well then sleep!
38760Sstevel@tonic-gate 	 */
38770Sstevel@tonic-gate 
38780Sstevel@tonic-gate 	if (flags & FDXC_SLEEP) {
38790Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WAITING;
38800Sstevel@tonic-gate 		while (fdc->c_flags & FDCFLG_WAITING) {
38810Sstevel@tonic-gate 			cv_wait(&fdc->c_iocv, &fdc->c_lolock);
38820Sstevel@tonic-gate 		}
38830Sstevel@tonic-gate 	}
38840Sstevel@tonic-gate 
38850Sstevel@tonic-gate 	/*
38860Sstevel@tonic-gate 	 * kludge for end-of-cylinder error which must be ignored!!!
38870Sstevel@tonic-gate 	 */
38880Sstevel@tonic-gate 
38890Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
38900Sstevel@tonic-gate 	    ((csb->csb_rslt[0] & IC_SR0) == 0x40) &&
38910Sstevel@tonic-gate 	    (csb->csb_rslt[1] & EN_SR1))
38920Sstevel@tonic-gate 		csb->csb_rslt[0] &= ~IC_SR0;
38930Sstevel@tonic-gate 
38940Sstevel@tonic-gate 	/*
38950Sstevel@tonic-gate 	 * See if there was an error detected, if so, fdrecover()
38960Sstevel@tonic-gate 	 * will check it out and say what to do.
38970Sstevel@tonic-gate 	 *
38980Sstevel@tonic-gate 	 * Don't do this, though, if this was the Sense Drive Status
38990Sstevel@tonic-gate 	 * or the Dump Registers command.
39000Sstevel@tonic-gate 	 */
39010Sstevel@tonic-gate 	if (((csb->csb_rslt[0] & IC_SR0) || (fdc->c_csb.csb_dcsr_rslt) ||
39027656SSherry.Moore@Sun.COM 	    (csb->csb_status)) &&
39037656SSherry.Moore@Sun.COM 	    ((csb->csb_cmds[0] != FDRAW_SENSE_DRV) &&
39047656SSherry.Moore@Sun.COM 	    (csb->csb_cmds[0] != DUMPREG))) {
39050Sstevel@tonic-gate 		/* if it can restarted OK, then do so, else return error */
39060Sstevel@tonic-gate 		if (fdrecover(fdc) != 0) {
39070Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_82077) {
39080Sstevel@tonic-gate 				if (fdc->c_mtimeid == 0) {
39090Sstevel@tonic-gate 					fdc->c_mtimeid = timeout(fdmotoff,
39107656SSherry.Moore@Sun.COM 					    a, Motoff_delay);
39110Sstevel@tonic-gate 				}
39120Sstevel@tonic-gate 			}
39130Sstevel@tonic-gate 
39140Sstevel@tonic-gate 			/*
39150Sstevel@tonic-gate 			 * If this was a dma transfer, unbind the handle so
39160Sstevel@tonic-gate 			 * that other transfers may use it.
39170Sstevel@tonic-gate 			 */
39180Sstevel@tonic-gate 
39190Sstevel@tonic-gate 			(void) fd_unbind_handle(fdc);
39200Sstevel@tonic-gate 			return (EIO);
39210Sstevel@tonic-gate 		} else {
39220Sstevel@tonic-gate 			/* ASSUMES that cmd is still intact in csb */
39230Sstevel@tonic-gate 			goto retry;
39240Sstevel@tonic-gate 		}
39250Sstevel@tonic-gate 	}
39260Sstevel@tonic-gate 
39270Sstevel@tonic-gate 	/* things went ok */
39280Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_82077) {
39290Sstevel@tonic-gate 		if (fdc->c_mtimeid == 0) {
39300Sstevel@tonic-gate 			fdc->c_mtimeid = timeout(fdmotoff, a, Motoff_delay);
39310Sstevel@tonic-gate 		}
39320Sstevel@tonic-gate 	}
39330Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..........\n"));
39340Sstevel@tonic-gate 
39350Sstevel@tonic-gate 	if (fd_unbind_handle(fdc))
39360Sstevel@tonic-gate 		return (EIO);
39370Sstevel@tonic-gate 
39380Sstevel@tonic-gate 	return (0);
39390Sstevel@tonic-gate }
39400Sstevel@tonic-gate 
39410Sstevel@tonic-gate /*
39420Sstevel@tonic-gate  * Turn on the drive's motor
39430Sstevel@tonic-gate  *
39440Sstevel@tonic-gate  *	- called with the low level lock held
39450Sstevel@tonic-gate  */
39460Sstevel@tonic-gate static void
fdexec_turn_on_motor(struct fdctlr * fdc,int flags,uint_t unit)39470Sstevel@tonic-gate fdexec_turn_on_motor(struct fdctlr *fdc, int flags,  uint_t unit)
39480Sstevel@tonic-gate {
39490Sstevel@tonic-gate 	clock_t local_lbolt;
39500Sstevel@tonic-gate 	timeout_id_t timeid;
39510Sstevel@tonic-gate 
39520Sstevel@tonic-gate 	/*
39530Sstevel@tonic-gate 	 * The low level mutex may not be held over the call to
39540Sstevel@tonic-gate 	 * untimeout().  See the manpage for details.
39550Sstevel@tonic-gate 	 */
39560Sstevel@tonic-gate 	timeid = fdc->c_mtimeid;
39570Sstevel@tonic-gate 	fdc->c_mtimeid = 0;
39580Sstevel@tonic-gate 	if (timeid) {
39590Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
39600Sstevel@tonic-gate 		(void) untimeout(timeid);
39610Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
39620Sstevel@tonic-gate 	}
39630Sstevel@tonic-gate 
39640Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
39650Sstevel@tonic-gate 
39660Sstevel@tonic-gate 
39670Sstevel@tonic-gate 	set_rotational_speed(fdc, unit);
39680Sstevel@tonic-gate 
39690Sstevel@tonic-gate 	if (!(Dor(fdc) & (MOTEN(unit)))) {
39700Sstevel@tonic-gate 		/*
39710Sstevel@tonic-gate 		 * Turn on the motor
39720Sstevel@tonic-gate 		 */
39730Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC,
39747656SSherry.Moore@Sun.COM 		    (C, "fdexec: turning on motor\n"));
39750Sstevel@tonic-gate 
39760Sstevel@tonic-gate 		/* LINTED */
39770Sstevel@tonic-gate 		Set_dor(fdc, (MOTEN(unit)), 1);
39780Sstevel@tonic-gate 
39790Sstevel@tonic-gate 		if (flags & FDXC_SLEEP) {
39800Sstevel@tonic-gate 			local_lbolt = ddi_get_lbolt();
39810Sstevel@tonic-gate 			(void) cv_timedwait(&fdc->c_motoncv,
39820Sstevel@tonic-gate 			    &fdc->c_lolock, local_lbolt + Moton_delay);
39830Sstevel@tonic-gate 		} else {
39840Sstevel@tonic-gate 			drv_usecwait(1000000);
39850Sstevel@tonic-gate 		}
39860Sstevel@tonic-gate 	}
39870Sstevel@tonic-gate 
39880Sstevel@tonic-gate }
39890Sstevel@tonic-gate 
39900Sstevel@tonic-gate /*
39910Sstevel@tonic-gate  * fdrecover
39920Sstevel@tonic-gate  *	see if possible to retry an operation.
39930Sstevel@tonic-gate  *	All we can do is restart the operation.	 If we are out of allowed
39940Sstevel@tonic-gate  *	retries - return non-zero so that the higher levels will be notified.
39950Sstevel@tonic-gate  *
39960Sstevel@tonic-gate  * RETURNS: 0 if ok to restart, !0 if can't or out of retries
39970Sstevel@tonic-gate  *	- called with the low level lock held
39980Sstevel@tonic-gate  */
39990Sstevel@tonic-gate static int
fdrecover(struct fdctlr * fdc)40000Sstevel@tonic-gate fdrecover(struct fdctlr *fdc)
40010Sstevel@tonic-gate {
40020Sstevel@tonic-gate 	struct fdcsb *csb;
40030Sstevel@tonic-gate 
40040Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdrecover\n"));
40050Sstevel@tonic-gate 	csb = &fdc->c_csb;
40060Sstevel@tonic-gate 
40070Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_TIMEDOUT) {
40080Sstevel@tonic-gate 		struct fdcsb savecsb;
40090Sstevel@tonic-gate 
40100Sstevel@tonic-gate 		fdc->c_flags ^= FDCFLG_TIMEDOUT;
40110Sstevel@tonic-gate 		csb->csb_rslt[1] |= TO_SR1;
40120Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RECO,
40130Sstevel@tonic-gate 		    (C, "fd%d: %s timed out\n", csb->csb_unit,
40140Sstevel@tonic-gate 		    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
40150Sstevel@tonic-gate 
40160Sstevel@tonic-gate 		/* use private csb */
40170Sstevel@tonic-gate 		savecsb = fdc->c_csb;
40180Sstevel@tonic-gate 		bzero(&fdc->c_csb, sizeof (struct fdcsb));
40190Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdc: resetting\n"));
40200Sstevel@tonic-gate 
40210Sstevel@tonic-gate 		(void) fdreset(fdc);
40220Sstevel@tonic-gate 
40230Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA) {
40240Sstevel@tonic-gate 			mutex_enter(&fdc->c_hilock);
40250Sstevel@tonic-gate 			/* Reset the DMA engine as well */
40260Sstevel@tonic-gate 			reset_dma_controller(fdc);
40270Sstevel@tonic-gate 			set_dma_control_register(fdc, DCSR_INIT_BITS);
40280Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
40290Sstevel@tonic-gate 		}
40300Sstevel@tonic-gate 
40310Sstevel@tonic-gate 
40320Sstevel@tonic-gate 		/* check change first?? */
40330Sstevel@tonic-gate 		/* don't ckchg in fdexec, too convoluted */
40340Sstevel@tonic-gate 		(void) fdrecalseek(fdc, savecsb.csb_unit, -1, 0);
40350Sstevel@tonic-gate 		fdc->c_csb = savecsb; /* restore original csb */
40360Sstevel@tonic-gate 	}
40370Sstevel@tonic-gate 
40380Sstevel@tonic-gate 	/*
40390Sstevel@tonic-gate 	 * gather statistics on errors
40400Sstevel@tonic-gate 	 */
40410Sstevel@tonic-gate 	if (csb->csb_rslt[1] & DE_SR1) {
40420Sstevel@tonic-gate 		fdc->fdstats.de++;
40430Sstevel@tonic-gate 	}
40440Sstevel@tonic-gate 	if (csb->csb_rslt[1] & OR_SR1) {
40450Sstevel@tonic-gate 		fdc->fdstats.run++;
40460Sstevel@tonic-gate 	}
40470Sstevel@tonic-gate 	if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
40480Sstevel@tonic-gate 		fdc->fdstats.bfmt++;
40490Sstevel@tonic-gate 	}
40500Sstevel@tonic-gate 	if (csb->csb_rslt[1] & TO_SR1) {
40510Sstevel@tonic-gate 		fdc->fdstats.to++;
40520Sstevel@tonic-gate 	}
40530Sstevel@tonic-gate 
40540Sstevel@tonic-gate 	/*
40550Sstevel@tonic-gate 	 * If raw ioctl don't examine results just pass status
40560Sstevel@tonic-gate 	 * back via fdraw. Raw commands are timed too, so put this
40570Sstevel@tonic-gate 	 * after the above check.
40580Sstevel@tonic-gate 	 */
40590Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFRAWIOCTL) {
40600Sstevel@tonic-gate 		return (1);
40610Sstevel@tonic-gate 	}
40620Sstevel@tonic-gate 
40630Sstevel@tonic-gate 
40640Sstevel@tonic-gate 	/*
40650Sstevel@tonic-gate 	 * if there was a pci bus error, do not retry
40660Sstevel@tonic-gate 	 */
40670Sstevel@tonic-gate 
40687656SSherry.Moore@Sun.COM 		if (csb->csb_dcsr_rslt == 1) {
40690Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
40700Sstevel@tonic-gate 			    (C, "fd%d: host bus error\n", 0));
40710Sstevel@tonic-gate 		return (1);
40727656SSherry.Moore@Sun.COM 		}
40730Sstevel@tonic-gate 
40740Sstevel@tonic-gate 	/*
40750Sstevel@tonic-gate 	 * If there was an error with the DMA functions, do not retry
40760Sstevel@tonic-gate 	 */
40770Sstevel@tonic-gate 	if (csb->csb_dma_rslt == 1) {
40780Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RECO,
40790Sstevel@tonic-gate 			    (C, "fd%d: DMA interface error\n", csb->csb_unit));
40800Sstevel@tonic-gate 		return (1);
40810Sstevel@tonic-gate 	}
40820Sstevel@tonic-gate 
40830Sstevel@tonic-gate 
40840Sstevel@tonic-gate 	/*
40850Sstevel@tonic-gate 	 * if we have run out of retries, return an error
40860Sstevel@tonic-gate 	 * XXX need better status interp
40870Sstevel@tonic-gate 	 */
40880Sstevel@tonic-gate 
40890Sstevel@tonic-gate 	csb->csb_retrys++;
40900Sstevel@tonic-gate 	if (csb->csb_retrys > csb->csb_maxretry) {
40910Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_RECO,
40920Sstevel@tonic-gate 		    (C, "fd%d: %s failed (%x %x %x)\n",
40930Sstevel@tonic-gate 		    0, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
40940Sstevel@tonic-gate 		    csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
40950Sstevel@tonic-gate 		if (csb->csb_rslt[1] & NW_SR1) {
40960Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
40970Sstevel@tonic-gate 			    (C, "fd%d: not writable\n", 0));
40980Sstevel@tonic-gate 		}
40990Sstevel@tonic-gate 		if (csb->csb_rslt[1] & DE_SR1) {
41000Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41010Sstevel@tonic-gate 			    (C, "fd%d: crc error blk %d\n", 0,
41020Sstevel@tonic-gate 			    (int)fdc->c_current->b_blkno));
41030Sstevel@tonic-gate 		}
41040Sstevel@tonic-gate 		if (csb->csb_rslt[1] & OR_SR1) {
41050Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB) {
41060Sstevel@tonic-gate 				/*
41070Sstevel@tonic-gate 				 * When using southbridge chip we need to
41080Sstevel@tonic-gate 				 * retry atleast 10 times to shake off the
41090Sstevel@tonic-gate 				 * underrun err.
41100Sstevel@tonic-gate 				 */
41110Sstevel@tonic-gate 				if (csb->csb_retrys <= rwretry)
41120Sstevel@tonic-gate 					return (0);
41130Sstevel@tonic-gate 			}
41140Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41150Sstevel@tonic-gate 			    (C, "fd%d: over/underrun\n", 0));
41160Sstevel@tonic-gate 		}
41170Sstevel@tonic-gate 
41180Sstevel@tonic-gate 		if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
41190Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41200Sstevel@tonic-gate 			    (C, "fd%d: bad format\n", 0));
41210Sstevel@tonic-gate 		}
41220Sstevel@tonic-gate 
41230Sstevel@tonic-gate 		if (csb->csb_rslt[1] & TO_SR1) {
41240Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41250Sstevel@tonic-gate 			    (C, "fd%d: timeout\n", 0));
41260Sstevel@tonic-gate 		}
41270Sstevel@tonic-gate 
41280Sstevel@tonic-gate 		csb->csb_cmdstat = 1; /* failed - give up */
41290Sstevel@tonic-gate 		return (1);
41300Sstevel@tonic-gate 	}
41310Sstevel@tonic-gate 
41320Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFSEEKOPS) {
41330Sstevel@tonic-gate 		/* seek, recal type commands - just look at st0 */
41340Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_RECO,
41350Sstevel@tonic-gate 		    (C, "fd%d: %s error : st0 0x%x\n", csb->csb_unit,
41360Sstevel@tonic-gate 		    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
41370Sstevel@tonic-gate 		    csb->csb_rslt[0]));
41380Sstevel@tonic-gate 	}
41390Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFXFEROPS) {
41400Sstevel@tonic-gate 		/* rd, wr, fmt type commands - look at st0, st1, st2 */
41410Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_RECO,
41420Sstevel@tonic-gate 		    (C, "fd%d: %s error : st0=0x%x st1=0x%x st2=0x%x\n",
41430Sstevel@tonic-gate 		    csb->csb_unit, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
41440Sstevel@tonic-gate 		    csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
41450Sstevel@tonic-gate 	}
41460Sstevel@tonic-gate 
41470Sstevel@tonic-gate 	return (0);	/* tell fdexec to retry */
41480Sstevel@tonic-gate }
41490Sstevel@tonic-gate 
41500Sstevel@tonic-gate /*
41510Sstevel@tonic-gate  * Interrupt handle for DMA
41520Sstevel@tonic-gate  */
41530Sstevel@tonic-gate 
41540Sstevel@tonic-gate static uint_t
fdintr_dma()41550Sstevel@tonic-gate fdintr_dma()
41560Sstevel@tonic-gate {
41570Sstevel@tonic-gate 	struct fdctlr   *fdc;
41580Sstevel@tonic-gate 	off_t		off;
41590Sstevel@tonic-gate 	size_t		len;
41600Sstevel@tonic-gate 	uint_t		ccount;
41610Sstevel@tonic-gate 	uint_t		windex;
41620Sstevel@tonic-gate 	uint_t		done = 0;
41630Sstevel@tonic-gate 	int		tmp_dcsr;
41640Sstevel@tonic-gate 	int		to;
41650Sstevel@tonic-gate 	uchar_t		tmp;
41660Sstevel@tonic-gate 	int		i = 0;
41670Sstevel@tonic-gate 	int		res = DDI_INTR_UNCLAIMED;
41680Sstevel@tonic-gate 	int		not_cheerio = 1;
41690Sstevel@tonic-gate 
41700Sstevel@tonic-gate 	/* search for a controller that's expecting an interrupt */
41710Sstevel@tonic-gate 	fdc = fdctlrs;
41720Sstevel@tonic-gate 
41730Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
41740Sstevel@tonic-gate 		tmp_dcsr = get_dma_control_register(fdc);
41750Sstevel@tonic-gate 		if (!(tmp_dcsr & DCSR_INT_PEND) && !(DCSR_ERR_PEND & tmp_dcsr))
41760Sstevel@tonic-gate 			return (res);
41770Sstevel@tonic-gate 		not_cheerio = 0;
41780Sstevel@tonic-gate 	}
41790Sstevel@tonic-gate 
41800Sstevel@tonic-gate 	mutex_enter(&fdc->c_hilock);
41810Sstevel@tonic-gate 
41820Sstevel@tonic-gate 	if (fdc->c_csb.csb_opmode == 0x0) {
41830Sstevel@tonic-gate 		fdc->c_csb.csb_opmode = 2;
41840Sstevel@tonic-gate 	}
41850Sstevel@tonic-gate 	if (fdc->sb_dma_lock) {
41860Sstevel@tonic-gate 		release_sb_dma(fdc);
41870Sstevel@tonic-gate 	}
41880Sstevel@tonic-gate 
41890Sstevel@tonic-gate 	/*
41900Sstevel@tonic-gate 	 * An interrupt can come from either the floppy controller or
41910Sstevel@tonic-gate 	 * or the DMA engine.  The DMA engine will only issue an
41920Sstevel@tonic-gate 	 * interrupt if there was an error.
41930Sstevel@tonic-gate 	 */
41940Sstevel@tonic-gate 
41950Sstevel@tonic-gate 	switch (fdc->c_csb.csb_opmode) {
41960Sstevel@tonic-gate 		case 0x1:
41970Sstevel@tonic-gate 			/* read/write/format data-xfer case */
41980Sstevel@tonic-gate 
41990Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
42007656SSherry.Moore@Sun.COM 			    (C, "fdintr_dma: opmode 1\n"));
42010Sstevel@tonic-gate 
42020Sstevel@tonic-gate 			/*
42030Sstevel@tonic-gate 			 * See if the interrupt is from the floppy
42040Sstevel@tonic-gate 			 * controller.  If there is, take out the status bytes.
42050Sstevel@tonic-gate 			 */
42060Sstevel@tonic-gate 
42070Sstevel@tonic-gate 			if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
42080Sstevel@tonic-gate 
42090Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
42107656SSherry.Moore@Sun.COM 				    (C, "fdintr_dma: INT_PEND \n"));
42110Sstevel@tonic-gate 
42120Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
42130Sstevel@tonic-gate 
42140Sstevel@tonic-gate 				to = FD_RRETRY;
42150Sstevel@tonic-gate 				fdc->c_csb.csb_nrslts = 0;
42160Sstevel@tonic-gate 
42170Sstevel@tonic-gate 				/* check status */
42180Sstevel@tonic-gate 				i = 0;
42190Sstevel@tonic-gate 
42200Sstevel@tonic-gate 				/*
42210Sstevel@tonic-gate 				 * CB turns off once all the result bytes are
42220Sstevel@tonic-gate 				 *  read.
42230Sstevel@tonic-gate 				 *
42240Sstevel@tonic-gate 				 * NOTE: the counters are there so that the
42250Sstevel@tonic-gate 				 * handler will never get stuck in a loop.
42260Sstevel@tonic-gate 				 * If the counters do reach their maximum
42270Sstevel@tonic-gate 				 * values, then a catastrophic error has
42280Sstevel@tonic-gate 				 * occurred.  This should never be the case.
42290Sstevel@tonic-gate 				 * The counters only came into play during
42300Sstevel@tonic-gate 				 * development.
42310Sstevel@tonic-gate 				 */
42320Sstevel@tonic-gate 				while (((tmp = Msr(fdc)) & CB) &&
42337656SSherry.Moore@Sun.COM 				    (i < 1000001)) {
42340Sstevel@tonic-gate 
42350Sstevel@tonic-gate 					/*
42360Sstevel@tonic-gate 					 * If RQM + DIO, then a result byte
42370Sstevel@tonic-gate 					 * is at hand.
42380Sstevel@tonic-gate 					 */
42390Sstevel@tonic-gate 					if ((tmp & (RQM|DIO|CB)) ==
42407656SSherry.Moore@Sun.COM 					    (RQM|DIO|CB)) {
42410Sstevel@tonic-gate 						fdc->c_csb.csb_rslt
42427656SSherry.Moore@Sun.COM 						    [fdc->c_csb.csb_nrslts++]
42437656SSherry.Moore@Sun.COM 						    = Fifo(fdc);
42440Sstevel@tonic-gate 
42450Sstevel@tonic-gate 						FDERRPRINT(FDEP_L1, FDEM_INTR,
42467656SSherry.Moore@Sun.COM 						    (C,
42477656SSherry.Moore@Sun.COM 						    "fdintr_dma: res 0x%x\n",
42487656SSherry.Moore@Sun.COM 						    fdc->c_csb.csb_rslt
42497656SSherry.Moore@Sun.COM 						    [fdc->c_csb.csb_nrslts
42507656SSherry.Moore@Sun.COM 						    - 1]));
42510Sstevel@tonic-gate 
42520Sstevel@tonic-gate 					} else if (--to == 0) {
42530Sstevel@tonic-gate 						/*
42540Sstevel@tonic-gate 						 * controller was never
42550Sstevel@tonic-gate 						 * ready to give results
42560Sstevel@tonic-gate 						 */
42570Sstevel@tonic-gate 						fdc->c_csb.csb_status = 2;
42580Sstevel@tonic-gate 						break;
42590Sstevel@tonic-gate 					}
42607656SSherry.Moore@Sun.COM 					i++;
42610Sstevel@tonic-gate 				}
42620Sstevel@tonic-gate 				if (i == 10000) {
42630Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
42647656SSherry.Moore@Sun.COM 					    (C, "First loop overran\n"));
42650Sstevel@tonic-gate 				}
42660Sstevel@tonic-gate 			}
42670Sstevel@tonic-gate 
42680Sstevel@tonic-gate 			/*
42690Sstevel@tonic-gate 			 * See if the interrupt is from the DMA engine,
42700Sstevel@tonic-gate 			 * which will only interrupt on an error
42710Sstevel@tonic-gate 			 */
42720Sstevel@tonic-gate 			if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
42730Sstevel@tonic-gate 
42740Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
42750Sstevel@tonic-gate 
42760Sstevel@tonic-gate 				done = 1;
42770Sstevel@tonic-gate 				fdc->c_csb.csb_dcsr_rslt = 1;
42780Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
42797656SSherry.Moore@Sun.COM 				    (C, "fdintr_dma: Error pending\n"));
42800Sstevel@tonic-gate 				reset_dma_controller(fdc);
42810Sstevel@tonic-gate 				set_dma_control_register(fdc, DCSR_INIT_BITS);
42820Sstevel@tonic-gate 				break;
42830Sstevel@tonic-gate 			}
42840Sstevel@tonic-gate 
42850Sstevel@tonic-gate 			/* TCBUG kludge */
42860Sstevel@tonic-gate 			if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
42877656SSherry.Moore@Sun.COM 			    ((fdc->c_csb.csb_rslt[0] & IC_SR0) == 0x40) &&
42887656SSherry.Moore@Sun.COM 			    (fdc->c_csb.csb_rslt[1] & EN_SR1)) {
42890Sstevel@tonic-gate 
42900Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[0] &= ~IC_SR0;
42910Sstevel@tonic-gate 
42920Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[1] &= ~EN_SR1;
42930Sstevel@tonic-gate 
42940Sstevel@tonic-gate 
42950Sstevel@tonic-gate 			}
42960Sstevel@tonic-gate 
42970Sstevel@tonic-gate 
42980Sstevel@tonic-gate 			/* Exit if there were errors in the DMA */
42990Sstevel@tonic-gate 			if (((fdc->c_csb.csb_rslt[0] & IC_SR0) != 0) ||
43000Sstevel@tonic-gate 			    (fdc->c_csb.csb_rslt[1] != 0) ||
43010Sstevel@tonic-gate 			    (fdc->c_csb.csb_rslt[2] != 0)) {
43020Sstevel@tonic-gate 				done = 1;
43030Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43047656SSherry.Moore@Sun.COM 				    (C, "fdintr_dma: errors in command\n"));
43050Sstevel@tonic-gate 
43060Sstevel@tonic-gate 
43070Sstevel@tonic-gate 				break;
43080Sstevel@tonic-gate 			}
43090Sstevel@tonic-gate 
43100Sstevel@tonic-gate 
43110Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
43127656SSherry.Moore@Sun.COM 			    (C, "fdintr_dma: dbcr 0x%x\n",
43137656SSherry.Moore@Sun.COM 			    get_data_count_register(fdc)));
43140Sstevel@tonic-gate 			/*
43150Sstevel@tonic-gate 			 * The csb_ccount is the number of cookies that still
43160Sstevel@tonic-gate 			 * need to be processed.  A cookie was just processed
43170Sstevel@tonic-gate 			 * so decrement the cookie counter.
43180Sstevel@tonic-gate 			 */
43190Sstevel@tonic-gate 			if (fdc->c_csb.csb_ccount == 0) {
43200Sstevel@tonic-gate 				done = 1;
43210Sstevel@tonic-gate 				break;
43220Sstevel@tonic-gate 			}
43230Sstevel@tonic-gate 			fdc->c_csb.csb_ccount--;
43240Sstevel@tonic-gate 			ccount = fdc->c_csb.csb_ccount;
43250Sstevel@tonic-gate 
43260Sstevel@tonic-gate 			windex = fdc->c_csb.csb_windex;
43270Sstevel@tonic-gate 
43280Sstevel@tonic-gate 			/*
43290Sstevel@tonic-gate 			 * If there are no more cookies and all the windows
43300Sstevel@tonic-gate 			 * have been DMA'd, then DMA is done.
43310Sstevel@tonic-gate 			 *
43320Sstevel@tonic-gate 			 */
43330Sstevel@tonic-gate 			if ((ccount == 0) && (windex == fdc->c_csb.csb_nwin)) {
43340Sstevel@tonic-gate 
43350Sstevel@tonic-gate 				done = 1;
43360Sstevel@tonic-gate 
43370Sstevel@tonic-gate 				/*
43380Sstevel@tonic-gate 				 * The handle is unbound in fdexec
43390Sstevel@tonic-gate 				 */
43400Sstevel@tonic-gate 
43410Sstevel@tonic-gate 				break;
43420Sstevel@tonic-gate 			}
43430Sstevel@tonic-gate 
43440Sstevel@tonic-gate 			if (ccount != 0) {
43450Sstevel@tonic-gate 				/* process the next cookie */
43460Sstevel@tonic-gate 				ddi_dma_nextcookie(fdc->c_dmahandle,
43470Sstevel@tonic-gate 				    &fdc->c_csb.csb_dmacookie);
43480Sstevel@tonic-gate 
43490Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43500Sstevel@tonic-gate 				    (C, "cookie addr 0x%" PRIx64 "\n",
43510Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_laddress));
43520Sstevel@tonic-gate 
43530Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43540Sstevel@tonic-gate 				    (C, "cookie length %lu\n",
43550Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_size));
43560Sstevel@tonic-gate 
43570Sstevel@tonic-gate 			} else {
43580Sstevel@tonic-gate 
43590Sstevel@tonic-gate 				(void) ddi_dma_getwin(fdc->c_dmahandle,
43600Sstevel@tonic-gate 				    fdc->c_csb.csb_windex,
43610Sstevel@tonic-gate 				    &off, &len,
43620Sstevel@tonic-gate 				    &fdc->c_csb.csb_dmacookie,
43630Sstevel@tonic-gate 				    &fdc->c_csb.csb_ccount);
43640Sstevel@tonic-gate 				fdc->c_csb.csb_windex++;
43650Sstevel@tonic-gate 
43660Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43670Sstevel@tonic-gate 				    (C, "fdintr_dma: process %d window\n",
43680Sstevel@tonic-gate 				    fdc->c_csb.csb_windex));
43690Sstevel@tonic-gate 
43700Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43710Sstevel@tonic-gate 				    (C, "fdintr_dma: process no. cookies %d\n",
43720Sstevel@tonic-gate 				    fdc->c_csb.csb_ccount));
43730Sstevel@tonic-gate 
43740Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43750Sstevel@tonic-gate 				    (C, "cookie addr 0x%" PRIx64 "\n",
43760Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_laddress));
43770Sstevel@tonic-gate 
43780Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43790Sstevel@tonic-gate 				    (C, "cookie length %lu\n",
43800Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_size));
43810Sstevel@tonic-gate 			}
43820Sstevel@tonic-gate 
43830Sstevel@tonic-gate 			/*
43840Sstevel@tonic-gate 			 * Program the DMA engine with the length and
43850Sstevel@tonic-gate 			 * the address of the transfer
43860Sstevel@tonic-gate 			 */
43870Sstevel@tonic-gate 
43880Sstevel@tonic-gate 			ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
43890Sstevel@tonic-gate 
43900Sstevel@tonic-gate 			set_data_count_register(fdc,
43917656SSherry.Moore@Sun.COM 			    fdc->c_csb.csb_dmacookie.dmac_size);
43920Sstevel@tonic-gate 			set_data_address_register(fdc,
43937656SSherry.Moore@Sun.COM 			    fdc->c_csb.csb_dmacookie.dmac_laddress);
43940Sstevel@tonic-gate 
43950Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR, (C,
43960Sstevel@tonic-gate 			    "fdintr_dma: size 0x%lx\n",
43970Sstevel@tonic-gate 			    fdc->c_csb.csb_dmacookie.dmac_size));
43980Sstevel@tonic-gate 
43990Sstevel@tonic-gate 
44000Sstevel@tonic-gate 			/* reprogram the controller */
44010Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[2] = fdc->c_csb.csb_rslt[3];
44020Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[3] = fdc->c_csb.csb_rslt[4];
44030Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[4] = fdc->c_csb.csb_rslt[5];
44040Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[1] = (fdc->c_csb.csb_cmds[1]
44057656SSherry.Moore@Sun.COM 			    & ~0x04) | (fdc->c_csb.csb_rslt[4] << 2);
44060Sstevel@tonic-gate 
44070Sstevel@tonic-gate 			for (i = 0; i < (int)fdc->c_csb.csb_ncmds; i++) {
44080Sstevel@tonic-gate 
44090Sstevel@tonic-gate 				/*
44100Sstevel@tonic-gate 				 * Test the readiness of the controller
44110Sstevel@tonic-gate 				 * to receive the cmd
44120Sstevel@tonic-gate 				 */
44130Sstevel@tonic-gate 				for (to = FD_CRETRY; to; to--) {
44140Sstevel@tonic-gate 					if ((Msr(fdc) & (DIO|RQM)) == RQM)
44150Sstevel@tonic-gate 						break;
44160Sstevel@tonic-gate 				}
44170Sstevel@tonic-gate 				if (to == 0) {
44180Sstevel@tonic-gate 					FDERRPRINT(FDEP_L2, FDEM_EXEC,
44197656SSherry.Moore@Sun.COM 					    (C,
44207656SSherry.Moore@Sun.COM 					    "fdc: no RQM - stat 0x%x\n",
44217656SSherry.Moore@Sun.COM 					    Msr(fdc)));
44220Sstevel@tonic-gate 					/* stop the DMA from happening */
44230Sstevel@tonic-gate 					fdc->c_csb.csb_status = 2;
44240Sstevel@tonic-gate 					done = 1;
44250Sstevel@tonic-gate 					break;
44260Sstevel@tonic-gate 				}
44270Sstevel@tonic-gate 
44280Sstevel@tonic-gate 				Set_Fifo(fdc, fdc->c_csb.csb_cmds[i]);
44290Sstevel@tonic-gate 
44300Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
44317656SSherry.Moore@Sun.COM 				    (C,
44327656SSherry.Moore@Sun.COM 				    "fdintr_dma: sent 0x%x, Msr 0x%x\n",
44337656SSherry.Moore@Sun.COM 				    fdc->c_csb.csb_cmds[i], Msr(fdc)));
44340Sstevel@tonic-gate 			}
44350Sstevel@tonic-gate 
44360Sstevel@tonic-gate 			/* reenable DMA */
44370Sstevel@tonic-gate 			if ((!not_cheerio) && (!done))
44380Sstevel@tonic-gate 				set_dma_control_register(fdc, tmp_dcsr |
44397656SSherry.Moore@Sun.COM 				    DCSR_EN_DMA);
44400Sstevel@tonic-gate 			break;
44410Sstevel@tonic-gate 
44420Sstevel@tonic-gate 		case 0x2:
44430Sstevel@tonic-gate 		/* seek/recal type cmd */
44440Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
44457656SSherry.Moore@Sun.COM 			    (C, "fintr_dma: opmode 2\n"));
44460Sstevel@tonic-gate 
44470Sstevel@tonic-gate 			/*
44480Sstevel@tonic-gate 			 *  See if the interrupt is from the DMA engine,
44490Sstevel@tonic-gate 			 *  which will only interrupt if there was an error.
44500Sstevel@tonic-gate 			 */
44510Sstevel@tonic-gate 			if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
44520Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
44530Sstevel@tonic-gate 				done = 1;
44540Sstevel@tonic-gate 				fdc->c_csb.csb_dcsr_rslt = 1;
44550Sstevel@tonic-gate 				reset_dma_controller(fdc);
44560Sstevel@tonic-gate 				set_dma_control_register(fdc, DCSR_INIT_BITS);
44570Sstevel@tonic-gate 
44580Sstevel@tonic-gate 				break;
44590Sstevel@tonic-gate 			}
44600Sstevel@tonic-gate 
44610Sstevel@tonic-gate 
44620Sstevel@tonic-gate 			/* See if the interrupt is from the floppy controller */
44630Sstevel@tonic-gate 			if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
44640Sstevel@tonic-gate 
44650Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
44660Sstevel@tonic-gate 
44670Sstevel@tonic-gate 
44680Sstevel@tonic-gate 				/*
44690Sstevel@tonic-gate 				 * Wait until there's no longer a command
44700Sstevel@tonic-gate 				 * in progress
44710Sstevel@tonic-gate 				 */
44720Sstevel@tonic-gate 
44730Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
44747656SSherry.Moore@Sun.COM 				    (C, "fdintr_dma: interrupt pending\n"));
44750Sstevel@tonic-gate 				i = 0;
44760Sstevel@tonic-gate 				while (((Msr(fdc) & CB)) && (i < 10000)) {
44770Sstevel@tonic-gate 					i++;
44780Sstevel@tonic-gate 				}
44790Sstevel@tonic-gate 
44800Sstevel@tonic-gate 				if (i == 10000)
44810Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
44827656SSherry.Moore@Sun.COM 					    (C, "2nd loop overran !!!\n"));
44830Sstevel@tonic-gate 
44840Sstevel@tonic-gate 				/*
44850Sstevel@tonic-gate 				 * Check the RQM bit to see if the controller is
44860Sstevel@tonic-gate 				 * ready to transfer status of the command.
44870Sstevel@tonic-gate 				 */
44880Sstevel@tonic-gate 				i = 0;
44890Sstevel@tonic-gate 				while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
44900Sstevel@tonic-gate 					i++;
44910Sstevel@tonic-gate 				}
44920Sstevel@tonic-gate 
44930Sstevel@tonic-gate 				if (i == 10000)
44940Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
44950Sstevel@tonic-gate 					    (C, "3rd loop overran !!!\n"));
44960Sstevel@tonic-gate 
44970Sstevel@tonic-gate 				/*
44980Sstevel@tonic-gate 				 * Issue the Sense Interrupt Status Command
44990Sstevel@tonic-gate 				 */
45000Sstevel@tonic-gate 				Set_Fifo(fdc, SNSISTAT);
45010Sstevel@tonic-gate 
45020Sstevel@tonic-gate 				i = 0;
45030Sstevel@tonic-gate 				while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
45040Sstevel@tonic-gate 					i++;
45050Sstevel@tonic-gate 				}
45060Sstevel@tonic-gate 				if (i == 10000)
45070Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
45087656SSherry.Moore@Sun.COM 					    (C, "4th loop overran !!!\n"));
45090Sstevel@tonic-gate 
45100Sstevel@tonic-gate 				/* Store the first result byte */
45110Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[0] = Fifo(fdc);
45120Sstevel@tonic-gate 
45130Sstevel@tonic-gate 				i = 0;
45140Sstevel@tonic-gate 				while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
45150Sstevel@tonic-gate 					i++;
45160Sstevel@tonic-gate 				}
45170Sstevel@tonic-gate 				if (i == 10000)
45180Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
45197656SSherry.Moore@Sun.COM 					    (C, "5th loop overran !!!\n"));
45200Sstevel@tonic-gate 
45210Sstevel@tonic-gate 				/* Store the second  result byte */
45220Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[1] = Fifo(fdc);
45230Sstevel@tonic-gate 
45240Sstevel@tonic-gate 				done = 1;
45250Sstevel@tonic-gate 			}
45260Sstevel@tonic-gate 
45270Sstevel@tonic-gate 		}
45280Sstevel@tonic-gate 
45290Sstevel@tonic-gate 	/*
45300Sstevel@tonic-gate 	 * We are done with the actual interrupt handling here.
45310Sstevel@tonic-gate 	 * The portion below should be actually be done by fd_lointr().
45320Sstevel@tonic-gate 	 * We should be triggering the fd_lointr here and exiting.
45330Sstevel@tonic-gate 	 * However for want of time this will be done in the next FIX.
45340Sstevel@tonic-gate 	 *
45350Sstevel@tonic-gate 	 * Hence for now we will release hilock only and keep the remaining
45360Sstevel@tonic-gate 	 * code as it is.
45370Sstevel@tonic-gate 	 * Releasing of hilock ensures that we don't hold on to the
45380Sstevel@tonic-gate 	 * lolock and hilock at the same time.
45390Sstevel@tonic-gate 	 * hilock is acquired each time dma related  registers are accessed.
45400Sstevel@tonic-gate 	 */
45410Sstevel@tonic-gate 	mutex_exit(&fdc->c_hilock);
45420Sstevel@tonic-gate 	/* Make signal and get out of interrupt handler */
45430Sstevel@tonic-gate 	if (done) {
45440Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
45450Sstevel@tonic-gate 
45460Sstevel@tonic-gate 		fdc->c_csb.csb_opmode = 0;
45470Sstevel@tonic-gate 
45480Sstevel@tonic-gate 		/*  reset watchdog timer if armed and not already triggered */
45490Sstevel@tonic-gate 
45500Sstevel@tonic-gate 
45510Sstevel@tonic-gate 		if (fdc->c_timeid) {
45520Sstevel@tonic-gate 			timeout_id_t timeid = fdc->c_timeid;
45530Sstevel@tonic-gate 			fdc->c_timeid = 0;
45540Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
45550Sstevel@tonic-gate 			(void) untimeout(timeid);
45560Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
45570Sstevel@tonic-gate 		}
45580Sstevel@tonic-gate 
45590Sstevel@tonic-gate 
45600Sstevel@tonic-gate 		if (fdc->c_flags & FDCFLG_WAITING) {
45610Sstevel@tonic-gate 			/*
45620Sstevel@tonic-gate 			 * somebody's waiting on finish of fdctlr/csb,
45630Sstevel@tonic-gate 			 * wake them
45640Sstevel@tonic-gate 			 */
45650Sstevel@tonic-gate 
45660Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
45677656SSherry.Moore@Sun.COM 			    (C, "fdintr_dma: signal the waiter\n"));
45680Sstevel@tonic-gate 
45690Sstevel@tonic-gate 			fdc->c_flags ^= FDCFLG_WAITING;
45700Sstevel@tonic-gate 			cv_signal(&fdc->c_iocv);
45710Sstevel@tonic-gate 
45720Sstevel@tonic-gate 			/*
45730Sstevel@tonic-gate 			 * FDCFLG_BUSY is NOT cleared, NOR is the csb given
45740Sstevel@tonic-gate 			 * back; the operation just finished can look at the csb
45750Sstevel@tonic-gate 			 */
45760Sstevel@tonic-gate 		} else {
45770Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
45787656SSherry.Moore@Sun.COM 			    (C, "fdintr_dma: nobody sleeping (%x %x %x)\n",
45797656SSherry.Moore@Sun.COM 			    fdc->c_csb.csb_rslt[0], fdc->c_csb.csb_rslt[1],
45807656SSherry.Moore@Sun.COM 			    fdc->c_csb.csb_rslt[2]));
45810Sstevel@tonic-gate 		}
45820Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
45830Sstevel@tonic-gate 	}
45840Sstevel@tonic-gate 	/* update high level interrupt counter */
45850Sstevel@tonic-gate 	if (fdc->c_intrstat)
45867656SSherry.Moore@Sun.COM 		KIOIP->intrs[KSTAT_INTR_HARD]++;
45870Sstevel@tonic-gate 
45880Sstevel@tonic-gate 
45890Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr_dma: done\n"));
45900Sstevel@tonic-gate 	return (res);
45910Sstevel@tonic-gate }
45920Sstevel@tonic-gate 
45930Sstevel@tonic-gate /*
45940Sstevel@tonic-gate  * fd_lointr
45950Sstevel@tonic-gate  *	This is the low level SW interrupt handler triggered by the high
45960Sstevel@tonic-gate  *	level interrupt handler (or by fdwatch).
45970Sstevel@tonic-gate  */
45980Sstevel@tonic-gate static uint_t
fd_lointr(caddr_t arg)45990Sstevel@tonic-gate fd_lointr(caddr_t arg)
46000Sstevel@tonic-gate {
46010Sstevel@tonic-gate 	struct fdctlr *fdc = (struct fdctlr *)arg;
46020Sstevel@tonic-gate 	struct fdcsb *csb;
46030Sstevel@tonic-gate 
46040Sstevel@tonic-gate 	csb = &fdc->c_csb;
46050Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr: opmode %d\n",
46060Sstevel@tonic-gate 	    csb->csb_opmode));
46070Sstevel@tonic-gate 	/*
46080Sstevel@tonic-gate 	 * Check that lowlevel interrupt really meant to trigger us.
46090Sstevel@tonic-gate 	 */
46100Sstevel@tonic-gate 	if (csb->csb_opmode != 4) {
46110Sstevel@tonic-gate 		/*
46120Sstevel@tonic-gate 		 * This should probably be protected, but, what the
46130Sstevel@tonic-gate 		 * heck...the cost isn't worth the accuracy for this
46140Sstevel@tonic-gate 		 * statistic.
46150Sstevel@tonic-gate 		 */
46160Sstevel@tonic-gate 		if (fdc->c_intrstat)
46170Sstevel@tonic-gate 			KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
46180Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
46190Sstevel@tonic-gate 	}
46200Sstevel@tonic-gate 
46210Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
46220Sstevel@tonic-gate 	csb->csb_opmode = 0;
46230Sstevel@tonic-gate 
46240Sstevel@tonic-gate 	/*  reset watchdog timer if armed and not already triggered */
46250Sstevel@tonic-gate 	if (fdc->c_timeid) {
46260Sstevel@tonic-gate 		timeout_id_t timeid = fdc->c_timeid;
46270Sstevel@tonic-gate 		fdc->c_timeid = 0;
46280Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
46290Sstevel@tonic-gate 		(void) untimeout(timeid);
46300Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
46310Sstevel@tonic-gate 
46320Sstevel@tonic-gate 	}
46330Sstevel@tonic-gate 
46340Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_WAITING) {
46350Sstevel@tonic-gate 		/*
46360Sstevel@tonic-gate 		 * somebody's waiting on finish of fdctlr/csb, wake them
46370Sstevel@tonic-gate 		 */
46380Sstevel@tonic-gate 		fdc->c_flags ^= FDCFLG_WAITING;
46390Sstevel@tonic-gate 		cv_signal(&fdc->c_iocv);
46400Sstevel@tonic-gate 
46410Sstevel@tonic-gate 		/*
46420Sstevel@tonic-gate 		 * FDCFLG_BUSY is NOT cleared, NOR is the csb given back; so
46430Sstevel@tonic-gate 		 * the operation just finished can look at the csb
46440Sstevel@tonic-gate 		 */
46450Sstevel@tonic-gate 	} else {
46460Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_INTR,
46470Sstevel@tonic-gate 		    (C, "fdintr: nobody sleeping (%x %x %x)\n",
46480Sstevel@tonic-gate 		    csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
46490Sstevel@tonic-gate 	}
46500Sstevel@tonic-gate 	if (fdc->c_intrstat)
46510Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_SOFT]++;
46520Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
46530Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
46540Sstevel@tonic-gate }
46550Sstevel@tonic-gate 
46560Sstevel@tonic-gate /*
46570Sstevel@tonic-gate  * fdwatch
46580Sstevel@tonic-gate  *	is called from timein() when a floppy operation has expired.
46590Sstevel@tonic-gate  */
46600Sstevel@tonic-gate static void
fdwatch(void * arg)46610Sstevel@tonic-gate fdwatch(void *arg)
46620Sstevel@tonic-gate {
46630Sstevel@tonic-gate 	struct fdctlr *fdc = arg;
46640Sstevel@tonic-gate 	int old_opmode;
46650Sstevel@tonic-gate 	struct fdcsb *csb;
46660Sstevel@tonic-gate 
46670Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch\n"));
46680Sstevel@tonic-gate 
46690Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
46700Sstevel@tonic-gate 	if (fdc->c_timeid == 0) {
46710Sstevel@tonic-gate 		/*
46720Sstevel@tonic-gate 		 * fdintr got here first, ergo, no timeout condition..
46730Sstevel@tonic-gate 		 */
46740Sstevel@tonic-gate 
46750Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_WATC,
46767656SSherry.Moore@Sun.COM 		    (C, "fdwatch: no timeout\n"));
46770Sstevel@tonic-gate 
46780Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
46790Sstevel@tonic-gate 		return;
46800Sstevel@tonic-gate 	}
46810Sstevel@tonic-gate 	fdc->c_timeid = 0;
46820Sstevel@tonic-gate 	csb = &fdc->c_csb;
46830Sstevel@tonic-gate 
46840Sstevel@tonic-gate 	mutex_enter(&fdc->c_hilock);
46850Sstevel@tonic-gate 	/*
46860Sstevel@tonic-gate 	 * XXXX: We should probably reset the bloody chip
46870Sstevel@tonic-gate 	 */
46880Sstevel@tonic-gate 	old_opmode = csb->csb_opmode;
46890Sstevel@tonic-gate 
46900Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_WATC,
46910Sstevel@tonic-gate 	    (C, "fd%d: timeout, opmode:%d\n", csb->csb_unit, old_opmode));
46920Sstevel@tonic-gate 
46930Sstevel@tonic-gate 	csb->csb_opmode = 4;
46940Sstevel@tonic-gate 	mutex_exit(&fdc->c_hilock);
46950Sstevel@tonic-gate 
46960Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch: cmd %s timed out\n",
46977656SSherry.Moore@Sun.COM 	    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
46980Sstevel@tonic-gate 	fdc->c_flags |= FDCFLG_TIMEDOUT;
46990Sstevel@tonic-gate 	csb->csb_status = CSB_CMDTO;
47000Sstevel@tonic-gate 
47010Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_DMA) == 0) {
47020Sstevel@tonic-gate 		ddi_trigger_softintr(fdc->c_softid);
47030Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_WATCHDOG]++;
47040Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
47050Sstevel@tonic-gate 	} else {
47060Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
47070Sstevel@tonic-gate 		(void) fd_lointr((caddr_t)fdctlrs);
47080Sstevel@tonic-gate 	}
47090Sstevel@tonic-gate }
47100Sstevel@tonic-gate 
47110Sstevel@tonic-gate /*
47120Sstevel@tonic-gate  * fdgetcsb
47130Sstevel@tonic-gate  *	wait until the csb is free
47140Sstevel@tonic-gate  */
47150Sstevel@tonic-gate static void
fdgetcsb(struct fdctlr * fdc)47160Sstevel@tonic-gate fdgetcsb(struct fdctlr *fdc)
47170Sstevel@tonic-gate {
47180Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETC, (C, "fdgetcsb\n"));
47190Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
47200Sstevel@tonic-gate 	while (fdc->c_flags & FDCFLG_BUSY) {
47210Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WANT;
47220Sstevel@tonic-gate 		cv_wait(&fdc->c_csbcv, &fdc->c_lolock);
47230Sstevel@tonic-gate 	}
47240Sstevel@tonic-gate 	fdc->c_flags |= FDCFLG_BUSY; /* got it! */
47250Sstevel@tonic-gate }
47260Sstevel@tonic-gate 
47270Sstevel@tonic-gate /*
47280Sstevel@tonic-gate  * fdretcsb
47290Sstevel@tonic-gate  *	return csb
47300Sstevel@tonic-gate  */
47310Sstevel@tonic-gate static void
fdretcsb(struct fdctlr * fdc)47320Sstevel@tonic-gate fdretcsb(struct fdctlr *fdc)
47330Sstevel@tonic-gate {
47340Sstevel@tonic-gate 
47350Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
47360Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RETC, (C, "fdretcsb\n"));
47370Sstevel@tonic-gate 	fdc->c_flags &= ~FDCFLG_BUSY; /* let go */
47380Sstevel@tonic-gate 
47390Sstevel@tonic-gate 	fdc->c_csb.csb_read = 0;
47400Sstevel@tonic-gate 
47410Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_WANT) {
47420Sstevel@tonic-gate 		fdc->c_flags ^= FDCFLG_WANT;
47430Sstevel@tonic-gate 		/*
47440Sstevel@tonic-gate 		 * broadcast the signal.  One thread will wake up and
47450Sstevel@tonic-gate 		 * set the flags to FDCFLG_BUSY.  If more than one thread is
47460Sstevel@tonic-gate 		 * waiting then each thread will wake up in turn.  The first
47470Sstevel@tonic-gate 		 * thread to wake-up will set the FDCFLG_BUSY flag and the
47480Sstevel@tonic-gate 		 * subsequent threads will will wake-up, but reset the
47490Sstevel@tonic-gate 		 * flag to FDCFLG_WANT because the FDCFLG_BUSY bit is set.
47500Sstevel@tonic-gate 		 */
47510Sstevel@tonic-gate 		cv_broadcast(&fdc->c_csbcv);
47520Sstevel@tonic-gate 	}
47530Sstevel@tonic-gate }
47540Sstevel@tonic-gate 
47550Sstevel@tonic-gate 
47560Sstevel@tonic-gate /*
47570Sstevel@tonic-gate  * fdreset
47580Sstevel@tonic-gate  *	reset THE controller, and configure it to be
47590Sstevel@tonic-gate  *	the way it ought to be
47600Sstevel@tonic-gate  * ASSUMES: that it already owns the csb/fdctlr!
47610Sstevel@tonic-gate  *
47620Sstevel@tonic-gate  *	- called with the low level lock held
47630Sstevel@tonic-gate  */
47640Sstevel@tonic-gate static int
fdreset(struct fdctlr * fdc)47650Sstevel@tonic-gate fdreset(struct fdctlr *fdc)
47660Sstevel@tonic-gate {
47670Sstevel@tonic-gate 	struct fdcsb *csb;
47680Sstevel@tonic-gate 	clock_t local_lbolt = 0;
47690Sstevel@tonic-gate 	timeout_id_t timeid;
47700Sstevel@tonic-gate 
47710Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset\n"));
47720Sstevel@tonic-gate 
47730Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
47740Sstevel@tonic-gate 
47750Sstevel@tonic-gate 	/* count resets */
47760Sstevel@tonic-gate 	fdc->fdstats.reset++;
47770Sstevel@tonic-gate 
47780Sstevel@tonic-gate 	/*
47790Sstevel@tonic-gate 	 * On the 82077, the DSR will clear itself after a reset.  Upon exiting
47800Sstevel@tonic-gate 	 * the reset, a polling interrupt will be generated.  If the floppy
47810Sstevel@tonic-gate 	 * interrupt is enabled, it's possible for cv_signal() to be called
47820Sstevel@tonic-gate 	 * before cv_wait().  This will cause the system to hang.  Turn off
47830Sstevel@tonic-gate 	 * the floppy interrupt to avoid this race condition
47840Sstevel@tonic-gate 	 */
47850Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
47860Sstevel@tonic-gate 		/*
47870Sstevel@tonic-gate 		 * We need to perform any timeouts before we Reset the
47880Sstevel@tonic-gate 		 * controller. We cannot afford to drop the c_lolock mutex after
47890Sstevel@tonic-gate 		 * Resetting the controller. The reason is that we get a spate
47900Sstevel@tonic-gate 		 * of interrupts until we take the controller out of reset.
47910Sstevel@tonic-gate 		 * The way we avoid this spate of continuous interrupts is by
47920Sstevel@tonic-gate 		 * holding on to the c_lolock and forcing the fdintr_dma routine
47930Sstevel@tonic-gate 		 * to go to sleep waiting for this mutex.
47940Sstevel@tonic-gate 		 */
47950Sstevel@tonic-gate 		/* Do not hold the mutex across the untimeout call */
47960Sstevel@tonic-gate 		timeid = fdc->c_mtimeid;
47970Sstevel@tonic-gate 		fdc->c_mtimeid = 0;
47980Sstevel@tonic-gate 		if (timeid) {
47990Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
48000Sstevel@tonic-gate 			(void) untimeout(timeid);
48010Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
48020Sstevel@tonic-gate 		}
48030Sstevel@tonic-gate 		/* LINTED */
48040Sstevel@tonic-gate 		Set_dor(fdc, DMAGATE, 0);
48050Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset: set dor\n"));
48060Sstevel@tonic-gate 	}
48070Sstevel@tonic-gate 
48080Sstevel@tonic-gate 	/* toggle software reset */
48090Sstevel@tonic-gate 	Dsr(fdc, SWR);
48100Sstevel@tonic-gate 
48110Sstevel@tonic-gate 	drv_usecwait(5);
48120Sstevel@tonic-gate 
48130Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RESE,
48147656SSherry.Moore@Sun.COM 	    (C, "fdreset: toggled software reset\n"));
48150Sstevel@tonic-gate 
48160Sstevel@tonic-gate 	/*
48170Sstevel@tonic-gate 	 * This sets the data rate to 500Kbps (for high density)
48180Sstevel@tonic-gate 	 * XXX should use current characteristics instead XXX
48190Sstevel@tonic-gate 	 */
48200Sstevel@tonic-gate 	Dsr(fdc, 0);
48210Sstevel@tonic-gate 	drv_usecwait(5);
48220Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
48230Sstevel@tonic-gate 	case FDCTYPE_82077:
48240Sstevel@tonic-gate 		/*
48250Sstevel@tonic-gate 		 * when we bring the controller out of reset it will generate
48260Sstevel@tonic-gate 		 * a polling interrupt. fdintr() will field it and schedule
48270Sstevel@tonic-gate 		 * fd_lointr(). There will be no one sleeping but we are
48280Sstevel@tonic-gate 		 * expecting an interrupt so....
48290Sstevel@tonic-gate 		 */
48300Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WAITING;
48310Sstevel@tonic-gate 
48320Sstevel@tonic-gate 		/*
48330Sstevel@tonic-gate 		 * The reset bit must be cleared to take the 077 out of
48340Sstevel@tonic-gate 		 * reset state and the DMAGATE bit must be high to enable
48350Sstevel@tonic-gate 		 * interrupts.
48360Sstevel@tonic-gate 		 */
48370Sstevel@tonic-gate 		/* LINTED */
48380Sstevel@tonic-gate 		Set_dor(fdc, DMAGATE|RESET, 1);
48390Sstevel@tonic-gate 
48400Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
48417656SSherry.Moore@Sun.COM 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
48420Sstevel@tonic-gate 
48430Sstevel@tonic-gate 		local_lbolt = ddi_get_lbolt();
48440Sstevel@tonic-gate 		if (cv_timedwait(&fdc->c_iocv, &fdc->c_lolock,
48457656SSherry.Moore@Sun.COM 		    local_lbolt + drv_usectohz(1000000)) == -1) {
48460Sstevel@tonic-gate 			return (-1);
48470Sstevel@tonic-gate 		}
48480Sstevel@tonic-gate 		break;
48490Sstevel@tonic-gate 
48500Sstevel@tonic-gate 	default:
48510Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WAITING;
48520Sstevel@tonic-gate 
48530Sstevel@tonic-gate 		/*
48540Sstevel@tonic-gate 		 * A timed wait is not used because it's possible for the timer
48550Sstevel@tonic-gate 		 * to go off before the controller has a chance to interrupt.
48560Sstevel@tonic-gate 		 */
48570Sstevel@tonic-gate 		cv_wait(&fdc->c_iocv, &fdc->c_lolock);
48580Sstevel@tonic-gate 		break;
48590Sstevel@tonic-gate 	}
48600Sstevel@tonic-gate 	csb = &fdc->c_csb;
48610Sstevel@tonic-gate 
48620Sstevel@tonic-gate 	/* setup common things in csb */
48630Sstevel@tonic-gate 	csb->csb_unit = fdc->c_un->un_unit_no;
48640Sstevel@tonic-gate 	csb->csb_nrslts = 0;
48650Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFNORESULTS;
48660Sstevel@tonic-gate 	csb->csb_maxretry = 0;
48670Sstevel@tonic-gate 	csb->csb_retrys = 0;
48680Sstevel@tonic-gate 
48690Sstevel@tonic-gate 	csb->csb_read = CSB_NULL;
48700Sstevel@tonic-gate 
48710Sstevel@tonic-gate 	/* send SPECIFY command to fdc */
48720Sstevel@tonic-gate 	/* csb->unit is don't care */
48730Sstevel@tonic-gate 	csb->csb_cmds[0] = FDRAW_SPECIFY;
48740Sstevel@tonic-gate 	csb->csb_cmds[1] = fdspec[0]; /* step rate, head unload time */
48750Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA)
48760Sstevel@tonic-gate 		csb->csb_cmds[2] =  SPEC_DMA_MODE;
48770Sstevel@tonic-gate 	else
48780Sstevel@tonic-gate 		csb->csb_cmds[2] = fdspec[1];  /* head load time, DMA mode */
48790Sstevel@tonic-gate 
48800Sstevel@tonic-gate 	csb->csb_ncmds = 3;
48810Sstevel@tonic-gate 
48820Sstevel@tonic-gate 	/* XXX for now ignore errors, they "CAN'T HAPPEN" */
48830Sstevel@tonic-gate 	(void) fdexec(fdc, 0);	/* no FDXC_CHECKCHG, ... */
48840Sstevel@tonic-gate 	/* no results */
48850Sstevel@tonic-gate 
48860Sstevel@tonic-gate 	/* send CONFIGURE command to fdc */
48870Sstevel@tonic-gate 	/* csb->unit is don't care */
48880Sstevel@tonic-gate 	csb->csb_cmds[0] = CONFIGURE;
48890Sstevel@tonic-gate 	csb->csb_cmds[1] = fdconf[0]; /* motor info, motor delays */
48900Sstevel@tonic-gate 	csb->csb_cmds[2] = fdconf[1]; /* enaimplsk, disapoll, fifothru */
48910Sstevel@tonic-gate 	csb->csb_cmds[3] = fdconf[2]; /* track precomp */
48920Sstevel@tonic-gate 	csb->csb_ncmds = 4;
48930Sstevel@tonic-gate 
48940Sstevel@tonic-gate 	csb->csb_read = CSB_NULL;
48950Sstevel@tonic-gate 
48960Sstevel@tonic-gate 	csb->csb_retrys = 0;
48970Sstevel@tonic-gate 
48980Sstevel@tonic-gate 	/* XXX for now ignore errors, they "CAN'T HAPPEN" */
48990Sstevel@tonic-gate 	(void) fdexec(fdc, 0); /* no FDXC_CHECKCHG, ... */
49000Sstevel@tonic-gate 	return (0);
49010Sstevel@tonic-gate }
49020Sstevel@tonic-gate 
49030Sstevel@tonic-gate /*
49040Sstevel@tonic-gate  * fdrecalseek
49050Sstevel@tonic-gate  *	performs recalibrates or seeks if the "arg" is -1 does a
49060Sstevel@tonic-gate  *	recalibrate on a drive, else it seeks to the cylinder of
49070Sstevel@tonic-gate  *	the drive.  The recalibrate is also used to find a drive,
49080Sstevel@tonic-gate  *	ie if the drive is not there, the controller says "error"
49090Sstevel@tonic-gate  *	on the operation
49100Sstevel@tonic-gate  * NOTE: that there is special handling of this operation in the hardware
49110Sstevel@tonic-gate  * interrupt routine - it causes the operation to appear to have results;
49120Sstevel@tonic-gate  * ie the results of the SENSE INTERRUPT STATUS that the hardware interrupt
49130Sstevel@tonic-gate  * function did for us.
49140Sstevel@tonic-gate  * NOTE: because it uses sleep/wakeup it must be protected in a critical
49150Sstevel@tonic-gate  * section so create one before calling it!
49160Sstevel@tonic-gate  *
49170Sstevel@tonic-gate  * RETURNS: 0 for ok,
49180Sstevel@tonic-gate  *	else	errno from fdexec,
49190Sstevel@tonic-gate  *	or	ENODEV if error (infers hardware type error)
49200Sstevel@tonic-gate  *
49210Sstevel@tonic-gate  *	- called with the low level lock held
49220Sstevel@tonic-gate  */
49230Sstevel@tonic-gate static int
fdrecalseek(struct fdctlr * fdc,int unit,int arg,int execflg)49240Sstevel@tonic-gate fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg)
49250Sstevel@tonic-gate {
49260Sstevel@tonic-gate 	struct fdcsb *csb;
49270Sstevel@tonic-gate 	int result;
49280Sstevel@tonic-gate 
49290Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
49300Sstevel@tonic-gate 
49310Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RECA, (C, "fdrecalseek to %d\n", arg));
49320Sstevel@tonic-gate 
49330Sstevel@tonic-gate 	/* XXX TODO: check see argument for <= num cyls OR < 256 */
49340Sstevel@tonic-gate 
49350Sstevel@tonic-gate 	csb = &fdc->c_csb;
49360Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
49370Sstevel@tonic-gate 	csb->csb_cmds[1] = unit & 0x03;
49380Sstevel@tonic-gate 
49390Sstevel@tonic-gate 	if (arg == -1) {			/* is recal... */
49400Sstevel@tonic-gate 		csb->csb_cmds[0] = FDRAW_REZERO;
49410Sstevel@tonic-gate 		csb->csb_ncmds = 2;
49420Sstevel@tonic-gate 	} else {
49430Sstevel@tonic-gate 		csb->csb_cmds[0] = FDRAW_SEEK;
49440Sstevel@tonic-gate 		csb->csb_cmds[2] = (uchar_t)arg;
49450Sstevel@tonic-gate 		csb->csb_ncmds = 3;
49460Sstevel@tonic-gate 	}
49470Sstevel@tonic-gate 	csb->csb_nrslts = 2;	/* 2 for SENSE INTERRUPTS */
49480Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFSEEKOPS | CSB_OFTIMEIT;
49490Sstevel@tonic-gate 	/*
49500Sstevel@tonic-gate 	 * MAYBE NYD need to set retries to different values? - depending on
49510Sstevel@tonic-gate 	 * drive characteristics - if we get to high capacity drives
49520Sstevel@tonic-gate 	 */
49530Sstevel@tonic-gate 	csb->csb_maxretry = skretry;
49540Sstevel@tonic-gate 	csb->csb_retrys = 0;
49550Sstevel@tonic-gate 
49560Sstevel@tonic-gate 	/* send cmd off to fdexec */
49570Sstevel@tonic-gate 	if (result = fdexec(fdc, FDXC_SLEEP | execflg)) {
49580Sstevel@tonic-gate 		goto out;
49590Sstevel@tonic-gate 	}
49600Sstevel@tonic-gate 
49610Sstevel@tonic-gate 	/*
49620Sstevel@tonic-gate 	 * if recal, test for equipment check error
49630Sstevel@tonic-gate 	 * ASSUMES result = 0 from above call
49640Sstevel@tonic-gate 	 */
49650Sstevel@tonic-gate 	if (arg == -1) {
49660Sstevel@tonic-gate 		result = 0;
49670Sstevel@tonic-gate 	} else {
49680Sstevel@tonic-gate 		/* for seeks, any old error will do */
49690Sstevel@tonic-gate 		if ((csb->csb_rslt[0] & IC_SR0) || csb->csb_cmdstat)
49700Sstevel@tonic-gate 			result = ENODEV;
49710Sstevel@tonic-gate 	}
49720Sstevel@tonic-gate 
49730Sstevel@tonic-gate out:
49740Sstevel@tonic-gate 	return (result);
49750Sstevel@tonic-gate }
49760Sstevel@tonic-gate 
49770Sstevel@tonic-gate /*
49780Sstevel@tonic-gate  * fdsensedrv
49790Sstevel@tonic-gate  *	do a sense_drive command.  used by fdopen and fdcheckdisk.
49800Sstevel@tonic-gate  *
49810Sstevel@tonic-gate  *	- called with the lock held
49820Sstevel@tonic-gate  */
49830Sstevel@tonic-gate static int
fdsensedrv(struct fdctlr * fdc,int unit)49840Sstevel@tonic-gate fdsensedrv(struct fdctlr *fdc, int unit)
49850Sstevel@tonic-gate {
49860Sstevel@tonic-gate 	struct fdcsb *csb;
49870Sstevel@tonic-gate 
49880Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
49890Sstevel@tonic-gate 
49900Sstevel@tonic-gate 	csb = &fdc->c_csb;
49910Sstevel@tonic-gate 
49920Sstevel@tonic-gate 	/* setup common things in csb */
49930Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
49940Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFIMMEDIATE;
49950Sstevel@tonic-gate 	csb->csb_cmds[0] = FDRAW_SENSE_DRV;
49960Sstevel@tonic-gate 	/* MOT bit set means don't delay */
49970Sstevel@tonic-gate 	csb->csb_cmds[1] = MOT | (unit & 0x03);
49980Sstevel@tonic-gate 	csb->csb_ncmds = 2;
49990Sstevel@tonic-gate 	csb->csb_nrslts = 1;
50000Sstevel@tonic-gate 	csb->csb_maxretry = skretry;
50010Sstevel@tonic-gate 	csb->csb_retrys = 0;
50020Sstevel@tonic-gate 
50030Sstevel@tonic-gate 	/* XXX for now ignore errors, they "CAN'T HAPPEN" */
50040Sstevel@tonic-gate 	(void) fdexec(fdc, 0);	/* DON't check changed!, no sleep */
50050Sstevel@tonic-gate 
50060Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CHEK,
50077656SSherry.Moore@Sun.COM 	    (C, "fdsensedrv: result 0x%x", csb->csb_rslt[0]));
50080Sstevel@tonic-gate 
50090Sstevel@tonic-gate 	return (csb->csb_rslt[0]); /* return status byte 3 */
50100Sstevel@tonic-gate }
50110Sstevel@tonic-gate 
50120Sstevel@tonic-gate /*
50130Sstevel@tonic-gate  * fdcheckdisk
50140Sstevel@tonic-gate  *	check to see if the disk is still there - do a recalibrate,
50150Sstevel@tonic-gate  *	then see if DSKCHG line went away, if so, diskette is in; else
50160Sstevel@tonic-gate  *	it's (still) out.
50170Sstevel@tonic-gate  */
50180Sstevel@tonic-gate 
50190Sstevel@tonic-gate static int
fdcheckdisk(struct fdctlr * fdc,int unit)50200Sstevel@tonic-gate fdcheckdisk(struct fdctlr *fdc, int unit)
50210Sstevel@tonic-gate {
50220Sstevel@tonic-gate 	auto struct fdcsb savecsb;
50230Sstevel@tonic-gate 	struct fdcsb *csb;
50240Sstevel@tonic-gate 	int	err, st3;
50250Sstevel@tonic-gate 	int	seekto;			/* where to seek for reset of DSKCHG */
50260Sstevel@tonic-gate 
50270Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CHEK,
50280Sstevel@tonic-gate 	    (C, "fdcheckdisk, unit %d\n", unit));
50290Sstevel@tonic-gate 
50300Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
50310Sstevel@tonic-gate 
50320Sstevel@tonic-gate 	/*
50330Sstevel@tonic-gate 	 * save old csb
50340Sstevel@tonic-gate 	 */
50350Sstevel@tonic-gate 
50360Sstevel@tonic-gate 	csb = &fdc->c_csb;
50370Sstevel@tonic-gate 	savecsb = fdc->c_csb;
50380Sstevel@tonic-gate 	bzero((caddr_t)csb, sizeof (*csb));
50390Sstevel@tonic-gate 
50400Sstevel@tonic-gate 	/*
50410Sstevel@tonic-gate 	 * Read drive status to see if at TRK0, if so, seek to cyl 1,
50420Sstevel@tonic-gate 	 * else seek to cyl 0.	We do this because the controller is
50430Sstevel@tonic-gate 	 * "smart" enough to not send any step pulses (which are how
50440Sstevel@tonic-gate 	 * the DSKCHG line gets reset) if it sees TRK0 'cause it
50450Sstevel@tonic-gate 	 * knows the drive is already recalibrated.
50460Sstevel@tonic-gate 	 */
50470Sstevel@tonic-gate 	st3 = fdsensedrv(fdc, unit);
50480Sstevel@tonic-gate 
50490Sstevel@tonic-gate 	/* check TRK0 bit in status */
50500Sstevel@tonic-gate 	if (st3 & T0_SR3)
50510Sstevel@tonic-gate 		seekto = 1;	/* at TRK0, seek out */
50520Sstevel@tonic-gate 	else
50530Sstevel@tonic-gate 		seekto = 0;
50540Sstevel@tonic-gate 
50550Sstevel@tonic-gate 	/*
50560Sstevel@tonic-gate 	 * DON'T recurse check changed
50570Sstevel@tonic-gate 	 */
50580Sstevel@tonic-gate 	err = fdrecalseek(fdc, unit, seekto, 0);
50590Sstevel@tonic-gate 
50600Sstevel@tonic-gate 	/* "restore" old csb, check change state */
50610Sstevel@tonic-gate 	fdc->c_csb = savecsb;
50620Sstevel@tonic-gate 
50630Sstevel@tonic-gate 	/* any recal/seek errors are too serious to attend to */
50640Sstevel@tonic-gate 	if (err) {
50650Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_CHEK,
50660Sstevel@tonic-gate 		    (C, "fdcheckdisk err %d\n", err));
50670Sstevel@tonic-gate 		return (err);
50680Sstevel@tonic-gate 	}
50690Sstevel@tonic-gate 
50700Sstevel@tonic-gate 	/*
50710Sstevel@tonic-gate 	 * if disk change still asserted, no diskette in drive!
50720Sstevel@tonic-gate 	 */
50730Sstevel@tonic-gate 	if (fdsense_chng(fdc, csb->csb_unit)) {
50740Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_CHEK,
50750Sstevel@tonic-gate 		    (C, "fdcheckdisk no disk\n"));
50760Sstevel@tonic-gate 		return (1);
50770Sstevel@tonic-gate 	}
50780Sstevel@tonic-gate 	return (0);
50790Sstevel@tonic-gate }
50800Sstevel@tonic-gate 
50810Sstevel@tonic-gate /*
50820Sstevel@tonic-gate  *	fdselect() - select drive, needed for external to chip select logic
50830Sstevel@tonic-gate  *	fdeject() - ejects drive, must be previously selected
50840Sstevel@tonic-gate  *	fdsense_chng() - sense disk changed line from previously selected drive
50850Sstevel@tonic-gate  *		return s 1 is signal asserted, else 0
50860Sstevel@tonic-gate  */
50870Sstevel@tonic-gate /* ARGSUSED */
50880Sstevel@tonic-gate static void
fdselect(struct fdctlr * fdc,int unit,int on)50890Sstevel@tonic-gate fdselect(struct fdctlr *fdc, int unit, int on)
50900Sstevel@tonic-gate {
50910Sstevel@tonic-gate 
50920Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
50930Sstevel@tonic-gate 
50940Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_DSEL,
50950Sstevel@tonic-gate 	    (C, "fdselect, unit %d, on = %d\n", unit, on));
50960Sstevel@tonic-gate 
50970Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
50980Sstevel@tonic-gate 	case FDCTYPE_MACHIO:
50990Sstevel@tonic-gate 		set_auxioreg(AUX_DRVSELECT, on);
51000Sstevel@tonic-gate 		break;
51010Sstevel@tonic-gate 
51020Sstevel@tonic-gate 	case FDCTYPE_SLAVIO:
51030Sstevel@tonic-gate 	case FDCTYPE_CHEERIO:
51040Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
51057656SSherry.Moore@Sun.COM 		    (C, "fdselect: (before) Dor 0x%x\n", Dor(fdc)));
51060Sstevel@tonic-gate 
51070Sstevel@tonic-gate 		if (unit == 0) {
51080Sstevel@tonic-gate 			Set_dor(fdc, DRVSEL, !on);
51090Sstevel@tonic-gate 		} else {
51100Sstevel@tonic-gate 			Set_dor(fdc, DRVSEL, on);
51110Sstevel@tonic-gate 		}
51120Sstevel@tonic-gate 
51130Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
51147656SSherry.Moore@Sun.COM 		    (C, "fdselect: Dor 0x%x\n", Dor(fdc)));
51150Sstevel@tonic-gate 
51160Sstevel@tonic-gate 		break;
51170Sstevel@tonic-gate 
51180Sstevel@tonic-gate 	default:
51190Sstevel@tonic-gate 		break;
51200Sstevel@tonic-gate 	}
51210Sstevel@tonic-gate }
51220Sstevel@tonic-gate 
51230Sstevel@tonic-gate /* ARGSUSED */
51240Sstevel@tonic-gate static void
fdeject(struct fdctlr * fdc,int unit)51250Sstevel@tonic-gate fdeject(struct fdctlr *fdc, int unit)
51260Sstevel@tonic-gate {
51270Sstevel@tonic-gate 	struct fdunit *un;
51280Sstevel@tonic-gate 
51290Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
51300Sstevel@tonic-gate 
51310Sstevel@tonic-gate 	un = fdc->c_un;
51320Sstevel@tonic-gate 
51330Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EJEC, (C, "fdeject\n"));
51340Sstevel@tonic-gate 	/*
51350Sstevel@tonic-gate 	 * assume delay of function calling sufficient settling time
51360Sstevel@tonic-gate 	 * eject line is NOT driven by inverter so it is true low
51370Sstevel@tonic-gate 	 */
51380Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
51390Sstevel@tonic-gate 	case FDCTYPE_MACHIO:
51400Sstevel@tonic-gate 		set_auxioreg(AUX_EJECT, 0);
51410Sstevel@tonic-gate 		drv_usecwait(2);
51420Sstevel@tonic-gate 		set_auxioreg(AUX_EJECT, 1);
51430Sstevel@tonic-gate 		break;
51440Sstevel@tonic-gate 
51450Sstevel@tonic-gate 	case FDCTYPE_SLAVIO:
51460Sstevel@tonic-gate 		if (!(Dor(fdc) & MOTEN(unit))) {
51470Sstevel@tonic-gate 			/* LINTED */
51480Sstevel@tonic-gate 			Set_dor(fdc, MOTEN(unit), 1);
51490Sstevel@tonic-gate 		}
51500Sstevel@tonic-gate 		drv_usecwait(2);	/* just to settle */
51510Sstevel@tonic-gate 		/* LINTED */
51520Sstevel@tonic-gate 		Set_dor(fdc, EJECT, 1);
51530Sstevel@tonic-gate 		drv_usecwait(2);
51540Sstevel@tonic-gate 		/* LINTED */
51550Sstevel@tonic-gate 		Set_dor(fdc, EJECT, 0);
51560Sstevel@tonic-gate 		break;
51570Sstevel@tonic-gate 	case FDCTYPE_CHEERIO:
51580Sstevel@tonic-gate 		if (!(Dor(fdc) & MOTEN(unit))) {
51590Sstevel@tonic-gate 			/* LINTED */
51600Sstevel@tonic-gate 			Set_dor(fdc, MOTEN(unit), 1);
51610Sstevel@tonic-gate 		}
51620Sstevel@tonic-gate 		drv_usecwait(2);	/* just to settle */
51630Sstevel@tonic-gate 		/* LINTED */
51640Sstevel@tonic-gate 		Set_dor(fdc, EJECT_DMA, 1);
51650Sstevel@tonic-gate 		drv_usecwait(2);
51660Sstevel@tonic-gate 		/* LINTED */
51670Sstevel@tonic-gate 		Set_dor(fdc, EJECT_DMA, 0);
51680Sstevel@tonic-gate 		break;
51690Sstevel@tonic-gate 	}
51700Sstevel@tonic-gate 	/*
51710Sstevel@tonic-gate 	 * XXX set ejected state?
51720Sstevel@tonic-gate 	 */
51730Sstevel@tonic-gate 	un->un_ejected = 1;
51740Sstevel@tonic-gate }
51750Sstevel@tonic-gate 
51760Sstevel@tonic-gate /* ARGSUSED */
51770Sstevel@tonic-gate static int
fdsense_chng(struct fdctlr * fdc,int unit)51780Sstevel@tonic-gate fdsense_chng(struct fdctlr *fdc, int unit)
51790Sstevel@tonic-gate {
51800Sstevel@tonic-gate 	int changed = 0;
51810Sstevel@tonic-gate 
51820Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:start\n"));
51830Sstevel@tonic-gate 
51840Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
51850Sstevel@tonic-gate 
51860Sstevel@tonic-gate 	/*
51870Sstevel@tonic-gate 	 * Do not turn on the motor of a pollable drive
51880Sstevel@tonic-gate 	 */
51890Sstevel@tonic-gate 	if (fd_pollable) {
51900Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "pollable: don't turn on motor\n"));
51910Sstevel@tonic-gate 		/*
51920Sstevel@tonic-gate 		 * Invert the sense of the DSKCHG for pollable drives
51930Sstevel@tonic-gate 		 */
51940Sstevel@tonic-gate 		if (Dir(fdc) & DSKCHG)
51950Sstevel@tonic-gate 			changed = 0;
51960Sstevel@tonic-gate 		else
51970Sstevel@tonic-gate 			changed = 1;
51980Sstevel@tonic-gate 
51990Sstevel@tonic-gate 		return (changed);
52000Sstevel@tonic-gate 	}
52010Sstevel@tonic-gate 
52020Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
52030Sstevel@tonic-gate 	case FDCTYPE_MACHIO:
52040Sstevel@tonic-gate 		if (*fdc->c_auxiova & AUX_DISKCHG)
52050Sstevel@tonic-gate 			changed = 1;
52060Sstevel@tonic-gate 		break;
52070Sstevel@tonic-gate 
52080Sstevel@tonic-gate 	case FDCTYPE_SB:
52090Sstevel@tonic-gate 	case FDCTYPE_SLAVIO:
52100Sstevel@tonic-gate 	case FDCTYPE_CHEERIO:
52110Sstevel@tonic-gate 		if (!(Dor(fdc) & MOTEN(unit))) {
52120Sstevel@tonic-gate 			/* LINTED */
52130Sstevel@tonic-gate 			Set_dor(fdc, MOTEN(unit), 1);
52140Sstevel@tonic-gate 		}
52150Sstevel@tonic-gate 		drv_usecwait(2);	/* just to settle */
52160Sstevel@tonic-gate 		if (Dir(fdc) & DSKCHG)
52170Sstevel@tonic-gate 			changed = 1;
52180Sstevel@tonic-gate 		break;
52190Sstevel@tonic-gate 	}
52200Sstevel@tonic-gate 
52210Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:end\n"));
52220Sstevel@tonic-gate 
52230Sstevel@tonic-gate 	return (changed);
52240Sstevel@tonic-gate }
52250Sstevel@tonic-gate 
52260Sstevel@tonic-gate /*
52270Sstevel@tonic-gate  *	if it can read a valid label it does so, else it will use a
52280Sstevel@tonic-gate  *	default.  If it can`t read the diskette - that is an error.
52290Sstevel@tonic-gate  *
52300Sstevel@tonic-gate  * RETURNS: 0 for ok - meaning that it could at least read the device,
52310Sstevel@tonic-gate  *	!0 for error XXX TBD NYD error codes
52320Sstevel@tonic-gate  *
52330Sstevel@tonic-gate  *	- called with the low level lock held
52340Sstevel@tonic-gate  */
52350Sstevel@tonic-gate static int
fdgetlabel(struct fdctlr * fdc,int unit)52360Sstevel@tonic-gate fdgetlabel(struct fdctlr *fdc, int unit)
52370Sstevel@tonic-gate {
52380Sstevel@tonic-gate 	struct dk_label *label = NULL;
52390Sstevel@tonic-gate 	struct fdunit *un;
52400Sstevel@tonic-gate 	short *sp;
52410Sstevel@tonic-gate 	short count;
52420Sstevel@tonic-gate 	short xsum;			/* checksum */
52430Sstevel@tonic-gate 	int	i, tries;
52440Sstevel@tonic-gate 	int	err = 0;
52450Sstevel@tonic-gate 	short	oldlvl;
52460Sstevel@tonic-gate 
52470Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
52480Sstevel@tonic-gate 	    (C, "fdgetlabel: unit %d\n", unit));
52490Sstevel@tonic-gate 
52500Sstevel@tonic-gate 	un = fdc->c_un;
52510Sstevel@tonic-gate 	un->un_flags &= ~(FDUNIT_UNLABELED);
52520Sstevel@tonic-gate 
52530Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
52540Sstevel@tonic-gate 
52550Sstevel@tonic-gate 	/* Do not print errors since this is a private cmd */
52560Sstevel@tonic-gate 
52570Sstevel@tonic-gate 	oldlvl = fderrlevel;
52580Sstevel@tonic-gate 
52590Sstevel@tonic-gate 
52600Sstevel@tonic-gate 	fderrlevel = FDEP_L4;
52610Sstevel@tonic-gate 
52620Sstevel@tonic-gate 	label = (struct dk_label *)
52637656SSherry.Moore@Sun.COM 	    kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
52640Sstevel@tonic-gate 
52650Sstevel@tonic-gate 	/*
52660Sstevel@tonic-gate 	 * try different characteristics (ie densities) by attempting to read
52670Sstevel@tonic-gate 	 * from the diskette.  The diskette may not be present or
52680Sstevel@tonic-gate 	 * is unformatted.
52690Sstevel@tonic-gate 	 *
52700Sstevel@tonic-gate 	 * First, the last sector of the first track is read.  If this
52710Sstevel@tonic-gate 	 * passes, attempt to read the last sector + 1 of the first track.
52720Sstevel@tonic-gate 	 * For example, for a high density diskette, sector 18 is read.  If
52730Sstevel@tonic-gate 	 * the diskette is high density, this will pass.  Next, try to
52740Sstevel@tonic-gate 	 * read sector 19 of the first track.  This should fail.  If it
52750Sstevel@tonic-gate 	 * passes, this is not a high density diskette.  Finally, read
52760Sstevel@tonic-gate 	 * the first sector which should contain a label.
52770Sstevel@tonic-gate 	 *
52780Sstevel@tonic-gate 	 * if un->un_curfdtype is -1 then the current characteristics
52790Sstevel@tonic-gate 	 * were set by FDIOSCHAR and need to try it as well as everything
52800Sstevel@tonic-gate 	 * in the table
52810Sstevel@tonic-gate 	 */
52820Sstevel@tonic-gate 	if (un->un_curfdtype == -1) {
52830Sstevel@tonic-gate 		tries = nfdtypes+1;
52840Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
52850Sstevel@tonic-gate 		    (C, "fdgetl: un_curfdtype is -1\n"));
52860Sstevel@tonic-gate 
52877656SSherry.Moore@Sun.COM 	} else {
52880Sstevel@tonic-gate 		tries = nfdtypes;
52890Sstevel@tonic-gate 
52900Sstevel@tonic-gate 		/* Always start with the highest density (1.7MB) */
52910Sstevel@tonic-gate 		un->un_curfdtype = 0;
52920Sstevel@tonic-gate 		*(un->un_chars) = fdtypes[un->un_curfdtype];
52930Sstevel@tonic-gate 	}
52940Sstevel@tonic-gate 
52950Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
52967656SSherry.Moore@Sun.COM 	    (C, "fdgetl: no. of tries %d\n", tries));
52970Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
52987656SSherry.Moore@Sun.COM 	    (C, "fdgetl: no. of curfdtype %d\n", un->un_curfdtype));
52990Sstevel@tonic-gate 
53000Sstevel@tonic-gate 	for (i = 0; i < tries; i++) {
53010Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53020Sstevel@tonic-gate 		    (C, "fdgetl: trying %d\n", i));
53030Sstevel@tonic-gate 
53040Sstevel@tonic-gate 		if (!(err = fdrw(fdc, unit, FDREAD, 0, 0,
53057656SSherry.Moore@Sun.COM 		    un->un_chars->fdc_secptrack, (caddr_t)label,
53067656SSherry.Moore@Sun.COM 		    sizeof (struct dk_label))) &&
53070Sstevel@tonic-gate 
53080Sstevel@tonic-gate 		    fdrw(fdc, unit, FDREAD, 0, 0,
53097656SSherry.Moore@Sun.COM 		    un->un_chars->fdc_secptrack + 1,
53107656SSherry.Moore@Sun.COM 		    (caddr_t)label, sizeof (struct dk_label)) &&
53110Sstevel@tonic-gate 
53120Sstevel@tonic-gate 		    !(err = fdrw(fdc, unit, FDREAD, 0, 0, 1, (caddr_t)label,
53137656SSherry.Moore@Sun.COM 		    sizeof (struct dk_label)))) {
53140Sstevel@tonic-gate 
53150Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_GETL,
53160Sstevel@tonic-gate 				(C, "fdgetl: succeeded\n"));
53170Sstevel@tonic-gate 
53180Sstevel@tonic-gate 			break;
53190Sstevel@tonic-gate 		}
53200Sstevel@tonic-gate 
53210Sstevel@tonic-gate 		/*
53220Sstevel@tonic-gate 		 * try the next entry in the characteristics tbl
53230Sstevel@tonic-gate 		 * If curfdtype is -1, the nxt entry in tbl is 0 (the first).
53240Sstevel@tonic-gate 		 */
53250Sstevel@tonic-gate 
53260Sstevel@tonic-gate 		un->un_curfdtype = (un->un_curfdtype + 1) % nfdtypes;
53270Sstevel@tonic-gate 		*(un->un_chars) = fdtypes[un->un_curfdtype];
53280Sstevel@tonic-gate 
53290Sstevel@tonic-gate 
53300Sstevel@tonic-gate 	}
53310Sstevel@tonic-gate 
53320Sstevel@tonic-gate 	/* print errors again */
53330Sstevel@tonic-gate 	fderrlevel = oldlvl;
53340Sstevel@tonic-gate 
53350Sstevel@tonic-gate 	/* Couldn't read anything */
53360Sstevel@tonic-gate 	if (err) {
53370Sstevel@tonic-gate 
53380Sstevel@tonic-gate 		/* The default characteristics are high density (1.4MB) */
53390Sstevel@tonic-gate 		un->un_curfdtype = 1;
53400Sstevel@tonic-gate 		*(un->un_chars) = fdtypes[un->un_curfdtype];
53410Sstevel@tonic-gate 
53420Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_80, &un->un_label);
53430Sstevel@tonic-gate 
53440Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53457656SSherry.Moore@Sun.COM 		    (C, "fdgetl: Can't autosense diskette\n"));
53460Sstevel@tonic-gate 
53470Sstevel@tonic-gate 		goto out;
53480Sstevel@tonic-gate 	}
53490Sstevel@tonic-gate 
53500Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
53510Sstevel@tonic-gate 	    (C, "fdgetl: fdtype=%d !!!\n", un->un_curfdtype));
53520Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
53530Sstevel@tonic-gate 	    (C, "fdgetl: rate=%d ssize=%d !!!\n",
53540Sstevel@tonic-gate 	    un->un_chars->fdc_transfer_rate, un->un_chars->fdc_sec_size));
53550Sstevel@tonic-gate 
53560Sstevel@tonic-gate 	/*
53570Sstevel@tonic-gate 	 * _something_ was read	 -  look for unixtype label
53580Sstevel@tonic-gate 	 */
53590Sstevel@tonic-gate 	if (label->dkl_magic != DKL_MAGIC) {
53600Sstevel@tonic-gate 
53610Sstevel@tonic-gate 		/*
53620Sstevel@tonic-gate 		 * The label isn't a unix label.  However, the diskette
53630Sstevel@tonic-gate 		 * is formatted because we were able to read the first
53640Sstevel@tonic-gate 		 * cylinder.
53650Sstevel@tonic-gate 		 */
53660Sstevel@tonic-gate 
53670Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53680Sstevel@tonic-gate 		    (C, "fdgetl: not unix label\n"));
53690Sstevel@tonic-gate 
53700Sstevel@tonic-gate 		goto nolabel;
53710Sstevel@tonic-gate 	}
53720Sstevel@tonic-gate 
53730Sstevel@tonic-gate 	/*
53740Sstevel@tonic-gate 	 * Checksum the label
53750Sstevel@tonic-gate 	 */
53760Sstevel@tonic-gate 	count = sizeof (struct dk_label)/sizeof (short);
53770Sstevel@tonic-gate 	sp = (short *)label;
53780Sstevel@tonic-gate 	xsum = 0;
53790Sstevel@tonic-gate 	while (count--)
53800Sstevel@tonic-gate 		xsum ^= *sp++;	/* should add up to 0 */
53810Sstevel@tonic-gate 	if (xsum) {
53820Sstevel@tonic-gate 
53830Sstevel@tonic-gate 		/*
53840Sstevel@tonic-gate 		 * The checksum fails.  However, the diskette is formatted
53850Sstevel@tonic-gate 		 * because we were able to read the first cylinder
53860Sstevel@tonic-gate 		 */
53870Sstevel@tonic-gate 
53880Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53890Sstevel@tonic-gate 		    (C, "fdgetl: bad cksum\n"));
53900Sstevel@tonic-gate 
53910Sstevel@tonic-gate 		goto nolabel;
53920Sstevel@tonic-gate 	}
53930Sstevel@tonic-gate 
53940Sstevel@tonic-gate 	/*
53950Sstevel@tonic-gate 	 * The diskette has a unix label with a correct checksum.
53960Sstevel@tonic-gate 	 * Copy the label into the unit structure
53970Sstevel@tonic-gate 	 */
53980Sstevel@tonic-gate 	un->un_label = *label;
53990Sstevel@tonic-gate 
54000Sstevel@tonic-gate 	goto out;
54010Sstevel@tonic-gate 
54020Sstevel@tonic-gate nolabel:
54030Sstevel@tonic-gate 	/*
54040Sstevel@tonic-gate 	 * The diskette doesn't have a correct unix label, but it is formatted.
54050Sstevel@tonic-gate 	 * Use a default label according to the diskette's density
54060Sstevel@tonic-gate 	 * (mark default used)
54070Sstevel@tonic-gate 	 */
54080Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
54090Sstevel@tonic-gate 	    (C, "fdgetlabel: unit %d\n", unit));
54100Sstevel@tonic-gate 	un->un_flags |= FDUNIT_UNLABELED;
54110Sstevel@tonic-gate 	switch (un->un_chars->fdc_secptrack) {
54120Sstevel@tonic-gate 	case 9:
54130Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_low_80, &un->un_label);
54140Sstevel@tonic-gate 		break;
54150Sstevel@tonic-gate 	case 8:
54160Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_medium_80, &un->un_label);
54170Sstevel@tonic-gate 		break;
54180Sstevel@tonic-gate 	case 18:
54190Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_80, &un->un_label);
54200Sstevel@tonic-gate 		break;
54210Sstevel@tonic-gate 	case 21:
54220Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_21, &un->un_label);
54230Sstevel@tonic-gate 		break;
54240Sstevel@tonic-gate 	default:
54250Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_80, &un->un_label);
54260Sstevel@tonic-gate 		break;
54270Sstevel@tonic-gate 	}
54280Sstevel@tonic-gate 
54290Sstevel@tonic-gate out:
54300Sstevel@tonic-gate 	if (label != NULL)
54310Sstevel@tonic-gate 		kmem_free((caddr_t)label, sizeof (struct dk_label));
54320Sstevel@tonic-gate 	return (err);
54330Sstevel@tonic-gate }
54340Sstevel@tonic-gate 
54350Sstevel@tonic-gate /*
54360Sstevel@tonic-gate  * fdrw- used only for reading labels  and for DKIOCSVTOC ioctl
54370Sstevel@tonic-gate  *	 which reads the 1 sector.
54380Sstevel@tonic-gate  */
54390Sstevel@tonic-gate static int
fdrw(struct fdctlr * fdc,int unit,int rw,int cyl,int head,int sector,caddr_t bufp,uint_t len)54400Sstevel@tonic-gate fdrw(struct fdctlr *fdc, int unit, int rw, int cyl, int head,
54410Sstevel@tonic-gate     int sector, caddr_t bufp, uint_t len)
54420Sstevel@tonic-gate {
54430Sstevel@tonic-gate 	struct fdcsb *csb;
54440Sstevel@tonic-gate 	struct	fd_char *ch;
54450Sstevel@tonic-gate 	int	cmdresult = 0;
54460Sstevel@tonic-gate 	caddr_t dma_addr;
54470Sstevel@tonic-gate 	size_t	real_length;
54480Sstevel@tonic-gate 	int	res;
54490Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
54500Sstevel@tonic-gate 	ddi_acc_handle_t	mem_handle = NULL;
54510Sstevel@tonic-gate 
54520Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw\n"));
54530Sstevel@tonic-gate 
54540Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
54550Sstevel@tonic-gate 
54560Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
54570Sstevel@tonic-gate 
54580Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
54590Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
54600Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
54617656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
54620Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
54637656SSherry.Moore@Sun.COM 			    failed. \n"));
54640Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
54650Sstevel@tonic-gate 			return (EIO);
54660Sstevel@tonic-gate 		}
54670Sstevel@tonic-gate 
54680Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
54690Sstevel@tonic-gate 	}
54700Sstevel@tonic-gate 
54710Sstevel@tonic-gate 	fdgetcsb(fdc);
54720Sstevel@tonic-gate 	csb = &fdc->c_csb;
54730Sstevel@tonic-gate 	ch = fdc->c_un->un_chars;
54740Sstevel@tonic-gate 	if (rw == FDREAD) {
54750Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_TCBUG) {
54760Sstevel@tonic-gate 			/*
54770Sstevel@tonic-gate 			 * kludge for lack of Multitrack functionality
54780Sstevel@tonic-gate 			 */
54790Sstevel@tonic-gate 			csb->csb_cmds[0] = SK + FDRAW_RDCMD;
54800Sstevel@tonic-gate 		} else
54810Sstevel@tonic-gate 			csb->csb_cmds[0] = MT + SK + FDRAW_RDCMD;
54820Sstevel@tonic-gate 	} else { /* write */
54830Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_TCBUG) {
54840Sstevel@tonic-gate 			/*
54850Sstevel@tonic-gate 			 * kludge for lack of Multitrack functionality
54860Sstevel@tonic-gate 			 */
54870Sstevel@tonic-gate 			csb->csb_cmds[0] = FDRAW_WRCMD;
54880Sstevel@tonic-gate 		} else
54890Sstevel@tonic-gate 			csb->csb_cmds[0] = MT + FDRAW_WRCMD;
54900Sstevel@tonic-gate 	}
54910Sstevel@tonic-gate 
54920Sstevel@tonic-gate 	if (rw == FDREAD)
54930Sstevel@tonic-gate 		fdc->c_csb.csb_read = CSB_READ;
54940Sstevel@tonic-gate 	else
54950Sstevel@tonic-gate 		fdc->c_csb.csb_read = CSB_WRITE;
54960Sstevel@tonic-gate 
54970Sstevel@tonic-gate 	/* always or in MFM bit */
54980Sstevel@tonic-gate 	csb->csb_cmds[0] |= MFM;
54990Sstevel@tonic-gate 	csb->csb_cmds[1] = (uchar_t)(unit | ((head & 0x1) << 2));
55000Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB)
55010Sstevel@tonic-gate 		csb->csb_cmds[1] |= IPS;
55020Sstevel@tonic-gate 	csb->csb_cmds[2] = (uchar_t)cyl;
55030Sstevel@tonic-gate 	csb->csb_cmds[3] = (uchar_t)head;
55040Sstevel@tonic-gate 	csb->csb_cmds[4] = (uchar_t)sector;
55050Sstevel@tonic-gate 	csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size code */
55060Sstevel@tonic-gate 	/*
55070Sstevel@tonic-gate 	 * kludge for end-of-cylinder error.
55080Sstevel@tonic-gate 	 */
55090Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_TCBUG)
55100Sstevel@tonic-gate 		csb->csb_cmds[6] = sector + (len / ch->fdc_sec_size) - 1;
55110Sstevel@tonic-gate 	else
55120Sstevel@tonic-gate 		csb->csb_cmds[6] =
55130Sstevel@tonic-gate 		    (uchar_t)max(fdc->c_un->un_chars->fdc_secptrack, sector);
55140Sstevel@tonic-gate 	csb->csb_len = len;
55150Sstevel@tonic-gate 	csb->csb_cmds[7] = GPLN;
55160Sstevel@tonic-gate 	csb->csb_cmds[8] = SSSDTL;
55170Sstevel@tonic-gate 	csb->csb_ncmds = NCBRW;
55180Sstevel@tonic-gate 	csb->csb_len = len;
55190Sstevel@tonic-gate 	csb->csb_maxretry = 2;
55200Sstevel@tonic-gate 	csb->csb_retrys = 0;
55210Sstevel@tonic-gate 	bzero(csb->csb_rslt, NRBRW);
55220Sstevel@tonic-gate 	csb->csb_nrslts = NRBRW;
55230Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
55240Sstevel@tonic-gate 
55250Sstevel@tonic-gate 	/* If platform supports DMA, set up DMA resources */
55260Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
55270Sstevel@tonic-gate 
55280Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
55290Sstevel@tonic-gate 
55300Sstevel@tonic-gate 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
55310Sstevel@tonic-gate 		attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
55320Sstevel@tonic-gate 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
55330Sstevel@tonic-gate 
55340Sstevel@tonic-gate 		res = ddi_dma_mem_alloc(fdc->c_dmahandle, len,
55357656SSherry.Moore@Sun.COM 		    &attr, DDI_DMA_STREAMING,
55367656SSherry.Moore@Sun.COM 		    DDI_DMA_DONTWAIT, 0, &dma_addr, &real_length,
55377656SSherry.Moore@Sun.COM 		    &mem_handle);
55380Sstevel@tonic-gate 
55390Sstevel@tonic-gate 		if (res != DDI_SUCCESS) {
55400Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RW,
55417656SSherry.Moore@Sun.COM 			    (C, "fdrw: dma mem alloc failed\n"));
55420Sstevel@tonic-gate 
55430Sstevel@tonic-gate 			fdretcsb(fdc);
55440Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
55450Sstevel@tonic-gate 			return (EIO);
55460Sstevel@tonic-gate 		}
55470Sstevel@tonic-gate 
55480Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: allocated memory"));
55490Sstevel@tonic-gate 
55500Sstevel@tonic-gate 		if (fdstart_dma(fdc, dma_addr, len) != 0) {
55510Sstevel@tonic-gate 			fdretcsb(fdc);
55520Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
55530Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
55540Sstevel@tonic-gate 			return (-1);
55550Sstevel@tonic-gate 
55560Sstevel@tonic-gate 		}
55570Sstevel@tonic-gate 
55580Sstevel@tonic-gate 		/*
55590Sstevel@tonic-gate 		 * If the command is a write, copy the data to be written to
55600Sstevel@tonic-gate 		 * dma_addr.
55610Sstevel@tonic-gate 		 */
55620Sstevel@tonic-gate 
55630Sstevel@tonic-gate 		if (fdc->c_csb.csb_read == CSB_WRITE) {
55640Sstevel@tonic-gate 			bcopy((char *)bufp, (char *)dma_addr, len);
55650Sstevel@tonic-gate 		}
55660Sstevel@tonic-gate 
55670Sstevel@tonic-gate 		csb->csb_addr = dma_addr;
55680Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
55690Sstevel@tonic-gate 	} else {
55700Sstevel@tonic-gate 		csb->csb_addr = bufp;
55710Sstevel@tonic-gate 	}
55720Sstevel@tonic-gate 
55730Sstevel@tonic-gate 
55740Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: call fdexec\n"));
55750Sstevel@tonic-gate 
55760Sstevel@tonic-gate 	if (fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG) != 0) {
55770Sstevel@tonic-gate 		fdretcsb(fdc);
55780Sstevel@tonic-gate 
55790Sstevel@tonic-gate 		if (mem_handle)
55800Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
55810Sstevel@tonic-gate 
55820Sstevel@tonic-gate 		return (EIO);
55830Sstevel@tonic-gate 
55840Sstevel@tonic-gate 	}
55850Sstevel@tonic-gate 
55860Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: fdexec returned\n"));
55870Sstevel@tonic-gate 
55880Sstevel@tonic-gate 	/*
55890Sstevel@tonic-gate 	 * if DMA was used and the command was a read
55900Sstevel@tonic-gate 	 * copy the results into bufp
55910Sstevel@tonic-gate 	 */
55920Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
55930Sstevel@tonic-gate 		if (fdc->c_csb.csb_read == CSB_READ) {
55940Sstevel@tonic-gate 			bcopy((char *)dma_addr, (char *)bufp, len);
55950Sstevel@tonic-gate 		}
55960Sstevel@tonic-gate 		ddi_dma_mem_free(&mem_handle);
55970Sstevel@tonic-gate 	}
55980Sstevel@tonic-gate 
55990Sstevel@tonic-gate 	if (csb->csb_cmdstat)
56000Sstevel@tonic-gate 		cmdresult = EIO;	/* XXX TBD NYD for now */
56010Sstevel@tonic-gate 
56020Sstevel@tonic-gate 	fdretcsb(fdc);
56030Sstevel@tonic-gate 	return (cmdresult);
56040Sstevel@tonic-gate }
56050Sstevel@tonic-gate 
56060Sstevel@tonic-gate /*
56070Sstevel@tonic-gate  * fdunpacklabel
56080Sstevel@tonic-gate  *	this unpacks a (packed) struct dk_label into a standard dk_label.
56090Sstevel@tonic-gate  */
56100Sstevel@tonic-gate static void
fdunpacklabel(struct packed_label * from,struct dk_label * to)56110Sstevel@tonic-gate fdunpacklabel(struct packed_label *from, struct dk_label *to)
56120Sstevel@tonic-gate {
56130Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PACK, (C, "fdpacklabel\n"));
56140Sstevel@tonic-gate 	bzero((caddr_t)to, sizeof (*to));
56150Sstevel@tonic-gate 	bcopy((caddr_t)&from->dkl_vname, (caddr_t)to->dkl_asciilabel,
56160Sstevel@tonic-gate 	    sizeof (to->dkl_asciilabel));
56170Sstevel@tonic-gate 	to->dkl_rpm = from->dkl_rpm;	/* rotations per minute */
56180Sstevel@tonic-gate 	to->dkl_pcyl = from->dkl_pcyl;	/* # physical cylinders */
56190Sstevel@tonic-gate 	to->dkl_apc = from->dkl_apc;	/* alternates per cylinder */
56200Sstevel@tonic-gate 	to->dkl_intrlv = from->dkl_intrlv;	/* interleave factor */
56210Sstevel@tonic-gate 	to->dkl_ncyl = from->dkl_ncyl;	/* # of data cylinders */
56220Sstevel@tonic-gate 	to->dkl_acyl = from->dkl_acyl;	/* # of alternate cylinders */
56230Sstevel@tonic-gate 	to->dkl_nhead = from->dkl_nhead; /* # of heads in this partition */
56240Sstevel@tonic-gate 	to->dkl_nsect = from->dkl_nsect; /* # of 512 byte sectors per track */
56250Sstevel@tonic-gate 	/* logical partitions */
56260Sstevel@tonic-gate 	bcopy((caddr_t)from->dkl_map, (caddr_t)to->dkl_map,
56270Sstevel@tonic-gate 	    sizeof (struct dk_map32) * NDKMAP);
56280Sstevel@tonic-gate 	to->dkl_vtoc = from->dkl_vtoc;
56290Sstevel@tonic-gate }
56300Sstevel@tonic-gate 
56310Sstevel@tonic-gate static struct fdctlr *
fd_getctlr(dev_t dev)56320Sstevel@tonic-gate fd_getctlr(dev_t dev)
56330Sstevel@tonic-gate {
56340Sstevel@tonic-gate 
56350Sstevel@tonic-gate 	struct fdctlr *fdc = fdctlrs;
56360Sstevel@tonic-gate 	int ctlr = FDCTLR(dev);
56370Sstevel@tonic-gate 
56380Sstevel@tonic-gate 	while (fdc) {
56390Sstevel@tonic-gate 		if (ddi_get_instance(fdc->c_dip) == ctlr)
56400Sstevel@tonic-gate 			return (fdc);
56410Sstevel@tonic-gate 		fdc = fdc->c_next;
56420Sstevel@tonic-gate 	}
56430Sstevel@tonic-gate 	return (fdc);
56440Sstevel@tonic-gate }
56450Sstevel@tonic-gate 
56460Sstevel@tonic-gate static int
fd_unit_is_open(struct fdunit * un)56470Sstevel@tonic-gate fd_unit_is_open(struct fdunit *un)
56480Sstevel@tonic-gate {
56490Sstevel@tonic-gate 	int i;
56500Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++)
56510Sstevel@tonic-gate 		if (un->un_lyropen[i])
56520Sstevel@tonic-gate 			return (1);
56530Sstevel@tonic-gate 	for (i = 0; i < OTYPCNT - 1; i++)
56540Sstevel@tonic-gate 		if (un->un_regopen[i])
56550Sstevel@tonic-gate 			return (1);
56560Sstevel@tonic-gate 	return (0);
56570Sstevel@tonic-gate }
56580Sstevel@tonic-gate 
56590Sstevel@tonic-gate /*
56600Sstevel@tonic-gate  * Return the a vtoc structure in *vtoc.
56610Sstevel@tonic-gate  * The vtoc is built from information in
56620Sstevel@tonic-gate  * the diskette's label.
56630Sstevel@tonic-gate  */
56640Sstevel@tonic-gate static void
fd_build_user_vtoc(struct fdunit * un,struct vtoc * vtoc)56650Sstevel@tonic-gate fd_build_user_vtoc(struct fdunit *un, struct vtoc *vtoc)
56660Sstevel@tonic-gate {
56670Sstevel@tonic-gate 	int i;
56680Sstevel@tonic-gate 	int nblks;			/* DEV_BSIZE sectors per cylinder */
56690Sstevel@tonic-gate 	struct dk_map2 *lpart;
56700Sstevel@tonic-gate 	struct dk_map32	*lmap;
56710Sstevel@tonic-gate 	struct partition *vpart;
56720Sstevel@tonic-gate 
56730Sstevel@tonic-gate 	bzero(vtoc, sizeof (struct vtoc));
56740Sstevel@tonic-gate 
56750Sstevel@tonic-gate 	/* Initialize info. needed by mboot.  (unsupported) */
56760Sstevel@tonic-gate 	vtoc->v_bootinfo[0] = un->un_label.dkl_vtoc.v_bootinfo[0];
56770Sstevel@tonic-gate 	vtoc->v_bootinfo[1] = un->un_label.dkl_vtoc.v_bootinfo[1];
56780Sstevel@tonic-gate 	vtoc->v_bootinfo[2] = un->un_label.dkl_vtoc.v_bootinfo[2];
56790Sstevel@tonic-gate 
56800Sstevel@tonic-gate 	/* Fill in vtoc sanity and version information */
56810Sstevel@tonic-gate 	vtoc->v_sanity		= un->un_label.dkl_vtoc.v_sanity;
56820Sstevel@tonic-gate 	vtoc->v_version		= un->un_label.dkl_vtoc.v_version;
56830Sstevel@tonic-gate 
56840Sstevel@tonic-gate 	/* Copy the volume name */
56850Sstevel@tonic-gate 	bcopy(un->un_label.dkl_vtoc.v_volume,
56860Sstevel@tonic-gate 	    vtoc->v_volume, LEN_DKL_VVOL);
56870Sstevel@tonic-gate 
56880Sstevel@tonic-gate 	/*
56890Sstevel@tonic-gate 	 * The dk_map32 structure is based on DEV_BSIZE byte blocks.
56900Sstevel@tonic-gate 	 * However, medium density diskettes have 1024 byte blocks.
56910Sstevel@tonic-gate 	 * The number of sectors per partition listed in the dk_map32 structure
56920Sstevel@tonic-gate 	 * accounts for this by multiplying the number of 1024 byte
56930Sstevel@tonic-gate 	 * blocks by 2.  (See the packed_label initializations.)  The
56940Sstevel@tonic-gate 	 * 1024 byte block size can not be listed for medium density
56950Sstevel@tonic-gate 	 * diskettes because the kernel is hard coded for DEV_BSIZE
56960Sstevel@tonic-gate 	 * blocks.
56970Sstevel@tonic-gate 	 */
56980Sstevel@tonic-gate 	vtoc->v_sectorsz = DEV_BSIZE;
56990Sstevel@tonic-gate 	vtoc->v_nparts = un->un_label.dkl_vtoc.v_nparts;
57000Sstevel@tonic-gate 
57010Sstevel@tonic-gate 	/* Copy the reserved space */
57020Sstevel@tonic-gate 	bcopy(un->un_label.dkl_vtoc.v_reserved,
57030Sstevel@tonic-gate 	    vtoc->v_reserved, sizeof (un->un_label.dkl_vtoc.v_reserved));
57040Sstevel@tonic-gate 	/*
57050Sstevel@tonic-gate 	 * Convert partitioning information.
57060Sstevel@tonic-gate 	 *
57070Sstevel@tonic-gate 	 * Note the conversion from starting cylinder number
57080Sstevel@tonic-gate 	 * to starting sector number.
57090Sstevel@tonic-gate 	 */
57100Sstevel@tonic-gate 	lmap = un->un_label.dkl_map;
57110Sstevel@tonic-gate 	lpart = un->un_label.dkl_vtoc.v_part;
57120Sstevel@tonic-gate 	vpart = vtoc->v_part;
57130Sstevel@tonic-gate 
57140Sstevel@tonic-gate 	nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
57157656SSherry.Moore@Sun.COM 	    un->un_chars->fdc_sec_size) / DEV_BSIZE;
57160Sstevel@tonic-gate 
57170Sstevel@tonic-gate 	for (i = 0; i < V_NUMPAR; i++) {
57180Sstevel@tonic-gate 		vpart->p_tag	= lpart->p_tag;
57190Sstevel@tonic-gate 		vpart->p_flag	= lpart->p_flag;
57200Sstevel@tonic-gate 		vpart->p_start	= lmap->dkl_cylno * nblks;
57210Sstevel@tonic-gate 		vpart->p_size	= lmap->dkl_nblk;
57220Sstevel@tonic-gate 
57230Sstevel@tonic-gate 		lmap++;
57240Sstevel@tonic-gate 		lpart++;
57250Sstevel@tonic-gate 		vpart++;
57260Sstevel@tonic-gate 	}
57270Sstevel@tonic-gate 
57280Sstevel@tonic-gate 	/* Initialize timestamp and label */
57290Sstevel@tonic-gate 	bcopy(un->un_label.dkl_vtoc.v_timestamp,
57300Sstevel@tonic-gate 	    vtoc->timestamp, sizeof (vtoc->timestamp));
57310Sstevel@tonic-gate 
57320Sstevel@tonic-gate 	bcopy(un->un_label.dkl_asciilabel,
57330Sstevel@tonic-gate 	    vtoc->v_asciilabel, LEN_DKL_ASCII);
57340Sstevel@tonic-gate }
57350Sstevel@tonic-gate 
57360Sstevel@tonic-gate /*
57370Sstevel@tonic-gate  * Build a label out of a vtoc structure.
57380Sstevel@tonic-gate  */
57390Sstevel@tonic-gate static int
fd_build_label_vtoc(struct fdunit * un,struct vtoc * vtoc)57400Sstevel@tonic-gate fd_build_label_vtoc(struct fdunit *un, struct vtoc *vtoc)
57410Sstevel@tonic-gate {
57420Sstevel@tonic-gate 	struct dk_map32		*lmap;
57430Sstevel@tonic-gate 	struct dk_map2		*lpart;
57440Sstevel@tonic-gate 	struct partition	*vpart;
57450Sstevel@tonic-gate 	int			nblks;	/* no. blocks per cylinder */
57460Sstevel@tonic-gate 	int			ncyl;
57470Sstevel@tonic-gate 	int			i;
57480Sstevel@tonic-gate 	short	 sum, *sp;
57490Sstevel@tonic-gate 
57500Sstevel@tonic-gate 	/* Sanity-check the vtoc */
57510Sstevel@tonic-gate 	if ((vtoc->v_sanity != VTOC_SANE) ||
57527656SSherry.Moore@Sun.COM 	    (vtoc->v_nparts > NDKMAP) || (vtoc->v_nparts <= 0)) {
57530Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_IOCT,
57540Sstevel@tonic-gate 		    (C, "fd_build_label:  sanity check on vtoc failed\n"));
57550Sstevel@tonic-gate 		return (EINVAL);
57560Sstevel@tonic-gate 	}
57570Sstevel@tonic-gate 
57580Sstevel@tonic-gate 	nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
57597656SSherry.Moore@Sun.COM 	    un->un_chars->fdc_sec_size) / DEV_BSIZE;
57600Sstevel@tonic-gate 
57610Sstevel@tonic-gate 	vpart = vtoc->v_part;
57620Sstevel@tonic-gate 
57630Sstevel@tonic-gate 	/*
57640Sstevel@tonic-gate 	 * Check the partition information in the vtoc.  The starting sectors
57650Sstevel@tonic-gate 	 * must lie along partition boundaries. (NDKMAP entries are checked
57660Sstevel@tonic-gate 	 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
57670Sstevel@tonic-gate 	 * is less than NDKMAP)
57680Sstevel@tonic-gate 	 */
57690Sstevel@tonic-gate 
57700Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
57710Sstevel@tonic-gate 		if ((vpart->p_start % nblks) != 0) {
57720Sstevel@tonic-gate 			return (EINVAL);
57730Sstevel@tonic-gate 		}
57740Sstevel@tonic-gate 		ncyl = vpart->p_start % nblks;
57750Sstevel@tonic-gate 		ncyl += vpart->p_size % nblks;
57760Sstevel@tonic-gate 		if ((vpart->p_size % nblks) != 0)
57770Sstevel@tonic-gate 			ncyl++;
57780Sstevel@tonic-gate 		if (ncyl > un->un_chars->fdc_ncyl) {
57790Sstevel@tonic-gate 			return (EINVAL);
57800Sstevel@tonic-gate 		}
57810Sstevel@tonic-gate 		vpart++;
57820Sstevel@tonic-gate 	}
57830Sstevel@tonic-gate 
57840Sstevel@tonic-gate 	/*
57850Sstevel@tonic-gate 	 * reinitialize the existing label
57860Sstevel@tonic-gate 	 */
57870Sstevel@tonic-gate 	bzero(&un->un_label, sizeof (un->un_label));
57880Sstevel@tonic-gate 
57890Sstevel@tonic-gate 	/* Put appropriate vtoc structure fields into the disk label */
57900Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_bootinfo[0] = (uint32_t)vtoc->v_bootinfo[0];
57910Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_bootinfo[1] = (uint32_t)vtoc->v_bootinfo[1];
57920Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_bootinfo[2] = (uint32_t)vtoc->v_bootinfo[2];
57930Sstevel@tonic-gate 
57940Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_sanity = vtoc->v_sanity;
57950Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_version = vtoc->v_version;
57960Sstevel@tonic-gate 
57970Sstevel@tonic-gate 	bcopy(vtoc->v_volume, un->un_label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
57980Sstevel@tonic-gate 
57990Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_nparts = vtoc->v_nparts;
58000Sstevel@tonic-gate 
58010Sstevel@tonic-gate 	bcopy(vtoc->v_reserved, un->un_label.dkl_vtoc.v_reserved,
58020Sstevel@tonic-gate 	    sizeof (un->un_label.dkl_vtoc.v_reserved));
58030Sstevel@tonic-gate 
58040Sstevel@tonic-gate 	/*
58050Sstevel@tonic-gate 	 * Initialize cylinder information in the label.
58060Sstevel@tonic-gate 	 * Note the conversion from starting sector number
58070Sstevel@tonic-gate 	 * to starting cylinder number.
58080Sstevel@tonic-gate 	 * Return error if division results in a remainder.
58090Sstevel@tonic-gate 	 */
58100Sstevel@tonic-gate 	lmap = un->un_label.dkl_map;
58110Sstevel@tonic-gate 	lpart = un->un_label.dkl_vtoc.v_part;
58120Sstevel@tonic-gate 	vpart = vtoc->v_part;
58130Sstevel@tonic-gate 
58140Sstevel@tonic-gate 	for (i = 0; i < (int)vtoc->v_nparts; i++) {
58150Sstevel@tonic-gate 		lpart->p_tag  = vtoc->v_part[i].p_tag;
58160Sstevel@tonic-gate 		lpart->p_flag = vtoc->v_part[i].p_flag;
58170Sstevel@tonic-gate 		lmap->dkl_cylno = vpart->p_start / nblks;
58180Sstevel@tonic-gate 		lmap->dkl_nblk = vpart->p_size;
58190Sstevel@tonic-gate 
58200Sstevel@tonic-gate 		lmap++;
58210Sstevel@tonic-gate 		lpart++;
58220Sstevel@tonic-gate 		vpart++;
58230Sstevel@tonic-gate 	}
58240Sstevel@tonic-gate 
58250Sstevel@tonic-gate 	/* Copy the timestamp and ascii label */
58260Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
58270Sstevel@tonic-gate 		un->un_label.dkl_vtoc.v_timestamp[i] = vtoc->timestamp[i];
58280Sstevel@tonic-gate 	}
58290Sstevel@tonic-gate 
58300Sstevel@tonic-gate 
58310Sstevel@tonic-gate 	bcopy(vtoc->v_asciilabel, un->un_label.dkl_asciilabel, LEN_DKL_ASCII);
58320Sstevel@tonic-gate 
58330Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
58347656SSherry.Moore@Sun.COM 	    (C, "fd_build_label: asciilabel %s\n",
58357656SSherry.Moore@Sun.COM 	    un->un_label.dkl_asciilabel));
58360Sstevel@tonic-gate 
58370Sstevel@tonic-gate 	/* Initialize the magic number */
58380Sstevel@tonic-gate 	un->un_label.dkl_magic = DKL_MAGIC;
58390Sstevel@tonic-gate 
58400Sstevel@tonic-gate 	un->un_label.dkl_pcyl = un->un_chars->fdc_ncyl;
58410Sstevel@tonic-gate 
58420Sstevel@tonic-gate 	/*
58430Sstevel@tonic-gate 	 * The fdc_secptrack filed of the fd_char structure is the number
58440Sstevel@tonic-gate 	 * of sectors per track where the sectors are fdc_sec_size.  The
58450Sstevel@tonic-gate 	 * dkl_nsect field of the dk_label structure is the number of
58460Sstevel@tonic-gate 	 * 512 (DEVBSIZE) byte sectors per track.
58470Sstevel@tonic-gate 	 */
58480Sstevel@tonic-gate 	un->un_label.dkl_nsect = (un->un_chars->fdc_secptrack *
58497656SSherry.Moore@Sun.COM 	    un->un_chars->fdc_sec_size) / DEV_BSIZE;
58500Sstevel@tonic-gate 
58510Sstevel@tonic-gate 
58520Sstevel@tonic-gate 	un->un_label.dkl_ncyl = un->un_label.dkl_pcyl;
58530Sstevel@tonic-gate 	un->un_label.dkl_nhead = un->un_chars->fdc_nhead;
58540Sstevel@tonic-gate 	un->un_label.dkl_rpm = un->un_chars->fdc_medium ? 360 : 300;
58550Sstevel@tonic-gate 	un->un_label.dkl_intrlv = 1;
58560Sstevel@tonic-gate 
58570Sstevel@tonic-gate 	/* Create the checksum */
58580Sstevel@tonic-gate 	sum = 0;
58590Sstevel@tonic-gate 	un->un_label.dkl_cksum = 0;
58600Sstevel@tonic-gate 	sp = (short *)&un->un_label;
58610Sstevel@tonic-gate 	i = sizeof (struct dk_label)/sizeof (short);
58620Sstevel@tonic-gate 	while (i--) {
58630Sstevel@tonic-gate 		sum ^= *sp++;
58640Sstevel@tonic-gate 	}
58650Sstevel@tonic-gate 	un->un_label.dkl_cksum = sum;
58660Sstevel@tonic-gate 
58670Sstevel@tonic-gate 	return (0);
58680Sstevel@tonic-gate }
58690Sstevel@tonic-gate 
58700Sstevel@tonic-gate /*
58710Sstevel@tonic-gate  * Check for auxio register node
58720Sstevel@tonic-gate  */
58730Sstevel@tonic-gate 
58740Sstevel@tonic-gate int
fd_isauxiodip(dev_info_t * dip)58750Sstevel@tonic-gate fd_isauxiodip(dev_info_t *dip)
58760Sstevel@tonic-gate {
58770Sstevel@tonic-gate 	if (strcmp(ddi_get_name(dip), "auxio") == 0 ||
58780Sstevel@tonic-gate 	    strcmp(ddi_get_name(dip), "auxiliary-io") == 0) {
58790Sstevel@tonic-gate 		return (1);
58800Sstevel@tonic-gate 	}
58810Sstevel@tonic-gate 	return (0);
58820Sstevel@tonic-gate }
58830Sstevel@tonic-gate 
58840Sstevel@tonic-gate /*
58850Sstevel@tonic-gate  * Search for auxio register node, then for address property
58860Sstevel@tonic-gate  */
58870Sstevel@tonic-gate 
58880Sstevel@tonic-gate caddr_t
fd_getauxiova(dev_info_t * dip)58890Sstevel@tonic-gate fd_getauxiova(dev_info_t *dip)
58900Sstevel@tonic-gate {
58910Sstevel@tonic-gate 	dev_info_t *auxdip;
58920Sstevel@tonic-gate 	caddr_t addr;
58930Sstevel@tonic-gate 
58940Sstevel@tonic-gate 	/*
58950Sstevel@tonic-gate 	 * Search sibling list, which happens to be safe inside attach
58960Sstevel@tonic-gate 	 */
58970Sstevel@tonic-gate 	auxdip = ddi_get_child(ddi_get_parent(dip));
58980Sstevel@tonic-gate 	while (auxdip) {
58990Sstevel@tonic-gate 		if (fd_isauxiodip(auxdip))
59000Sstevel@tonic-gate 			break;
59010Sstevel@tonic-gate 		auxdip = ddi_get_next_sibling(auxdip);
59020Sstevel@tonic-gate 	}
59030Sstevel@tonic-gate 
59040Sstevel@tonic-gate 	if (auxdip == NULL)
59050Sstevel@tonic-gate 		return (NULL);
59060Sstevel@tonic-gate 
5907483Spc157239 	addr = (caddr_t)(uintptr_t)(caddr32_t)ddi_getprop(DDI_DEV_T_ANY,
59087656SSherry.Moore@Sun.COM 	    auxdip, DDI_PROP_DONTPASS, "address", 0);
59090Sstevel@tonic-gate 
59100Sstevel@tonic-gate 	return (addr);
59110Sstevel@tonic-gate }
59120Sstevel@tonic-gate 
59130Sstevel@tonic-gate 
59140Sstevel@tonic-gate /*
59150Sstevel@tonic-gate  * set_rotational speed
59160Sstevel@tonic-gate  * 300 rpm for high and low density.
59170Sstevel@tonic-gate  * 360 rpm for medium density.
59180Sstevel@tonic-gate  * for now, we assume that 3rd density is supported only for Sun4M,
59190Sstevel@tonic-gate  * not for Clones. (else we would have to check for 82077, and do
59200Sstevel@tonic-gate  * specific things for the MEDIUM_DENSITY BIT for clones.
59210Sstevel@tonic-gate  * this code should not break CLONES.
59220Sstevel@tonic-gate  *
59230Sstevel@tonic-gate  * REMARK: there is a SOny requirement, to deselect the drive then
59240Sstevel@tonic-gate  * select it again after the medium density change, since the
59250Sstevel@tonic-gate  * leading edge of the select line latches the rotational Speed.
59260Sstevel@tonic-gate  * then after that, we have to wait 500 ms for the rotation to
59270Sstevel@tonic-gate  * stabilize.
59280Sstevel@tonic-gate  *
59290Sstevel@tonic-gate  */
59300Sstevel@tonic-gate static void
set_rotational_speed(struct fdctlr * fdc,int unit)59310Sstevel@tonic-gate set_rotational_speed(struct fdctlr *fdc, int unit)
59320Sstevel@tonic-gate {
59330Sstevel@tonic-gate 	int check;
59340Sstevel@tonic-gate 	int is_medium;
59350Sstevel@tonic-gate 
59360Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
59370Sstevel@tonic-gate 
59380Sstevel@tonic-gate 	/*
59390Sstevel@tonic-gate 	 * if we do not have a Sun4m, medium density is not supported.
59400Sstevel@tonic-gate 	 */
59410Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_MACHIO)
59420Sstevel@tonic-gate 		return;
59430Sstevel@tonic-gate 
59440Sstevel@tonic-gate 	/*
59450Sstevel@tonic-gate 	 * if FDUNIT_SET_SPEED is set, set the speed.
59460Sstevel@tonic-gate 	 * else,
59470Sstevel@tonic-gate 	 *	if there is a change, do it, if not leave it alone.
59480Sstevel@tonic-gate 	 *	there is a change if un->un_chars->fdc_medium does not match
59490Sstevel@tonic-gate 	 *	un->un_flags & FDUNIT_MEDIUM
59500Sstevel@tonic-gate 	 *	un->un_flags & FDUNIT_MEDIUM specifies the last setting.
59510Sstevel@tonic-gate 	 *	un->un_chars->fdc_medium specifies next setting.
59520Sstevel@tonic-gate 	 *	if there is a change, wait 500ms according to Sony spec.
59530Sstevel@tonic-gate 	 */
59540Sstevel@tonic-gate 
59550Sstevel@tonic-gate 	is_medium = fdc->c_un->un_chars->fdc_medium;
59560Sstevel@tonic-gate 
59570Sstevel@tonic-gate 	if (fdc->c_un->un_flags & FDUNIT_SET_SPEED) {
59580Sstevel@tonic-gate 		check = 1;
59590Sstevel@tonic-gate 	} else {
59600Sstevel@tonic-gate 		check = is_medium ^
59617656SSherry.Moore@Sun.COM 		    ((fdc->c_un->un_flags & FDUNIT_MEDIUM) ? 1 : 0);
59620Sstevel@tonic-gate 
59630Sstevel@tonic-gate 		/* Set the un_flags if necessary */
59640Sstevel@tonic-gate 
59650Sstevel@tonic-gate 		if (check)
59660Sstevel@tonic-gate 			fdc->c_un->un_flags ^= FDUNIT_MEDIUM;
59670Sstevel@tonic-gate 	}
59680Sstevel@tonic-gate 
59690Sstevel@tonic-gate 	fdc->c_un->un_flags &= ~FDUNIT_SET_SPEED;
59700Sstevel@tonic-gate 
59710Sstevel@tonic-gate 
59720Sstevel@tonic-gate 	if (check) {
59730Sstevel@tonic-gate 
59740Sstevel@tonic-gate 		fdselect(fdc, unit, 0);
59750Sstevel@tonic-gate 		drv_usecwait(5);
59760Sstevel@tonic-gate 
59770Sstevel@tonic-gate 		if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_SLAVIO) {
59780Sstevel@tonic-gate 			Set_dor(fdc, MEDIUM_DENSITY, is_medium);
59790Sstevel@tonic-gate 		}
59800Sstevel@tonic-gate 
59810Sstevel@tonic-gate 		if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_CHEERIO) {
59820Sstevel@tonic-gate 			if (is_medium) {
59830Sstevel@tonic-gate 				Set_auxio(fdc, AUX_MEDIUM_DENSITY);
59840Sstevel@tonic-gate 			} else {
59850Sstevel@tonic-gate 				Set_auxio(fdc, AUX_HIGH_DENSITY);
59860Sstevel@tonic-gate 			}
59870Sstevel@tonic-gate 
59880Sstevel@tonic-gate 		}
59890Sstevel@tonic-gate 
59900Sstevel@tonic-gate 		if (is_medium) {
59910Sstevel@tonic-gate 			drv_usecwait(5);
59920Sstevel@tonic-gate 		}
59930Sstevel@tonic-gate 
59940Sstevel@tonic-gate 		fdselect(fdc, unit, 1);	/* Sony requirement */
59950Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "rotation:medium\n"));
59960Sstevel@tonic-gate 		drv_usecwait(500000);
59970Sstevel@tonic-gate 	}
59980Sstevel@tonic-gate }
59990Sstevel@tonic-gate 
60000Sstevel@tonic-gate static void
fd_media_watch(void * arg)60010Sstevel@tonic-gate fd_media_watch(void *arg)
60020Sstevel@tonic-gate {
60030Sstevel@tonic-gate 	dev_t		dev;
60040Sstevel@tonic-gate 	struct fdunit *un;
60050Sstevel@tonic-gate 	struct fdctlr *fdc;
60060Sstevel@tonic-gate 	int		unit;
60070Sstevel@tonic-gate 
60080Sstevel@tonic-gate 	dev = (dev_t)arg;
60090Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
60100Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
60110Sstevel@tonic-gate 	un = fdc->c_un;
60120Sstevel@tonic-gate 
60130Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
60140Sstevel@tonic-gate 
60150Sstevel@tonic-gate 	if (un->un_media_timeout_id == 0) {
60160Sstevel@tonic-gate 		/*
60170Sstevel@tonic-gate 		 * Untimeout is about to be called.
60180Sstevel@tonic-gate 		 * Don't call fd_get_media_state again
60190Sstevel@tonic-gate 		 */
60200Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
60210Sstevel@tonic-gate 		return;
60220Sstevel@tonic-gate 	}
60230Sstevel@tonic-gate 
60240Sstevel@tonic-gate 
60250Sstevel@tonic-gate 	un->un_media_state = fd_get_media_state(fdc, unit);
60260Sstevel@tonic-gate 	cv_broadcast(&fdc->c_statecv);
60270Sstevel@tonic-gate 
60280Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
60290Sstevel@tonic-gate 
60300Sstevel@tonic-gate 	if (un->un_media_timeout) {
60310Sstevel@tonic-gate 		un->un_media_timeout_id = timeout(fd_media_watch,
60327656SSherry.Moore@Sun.COM 		    (void *)(ulong_t)dev, un->un_media_timeout);
60330Sstevel@tonic-gate 	}
60340Sstevel@tonic-gate }
60350Sstevel@tonic-gate 
60360Sstevel@tonic-gate enum dkio_state
fd_get_media_state(struct fdctlr * fdc,int unit)60370Sstevel@tonic-gate fd_get_media_state(struct fdctlr *fdc, int unit)
60380Sstevel@tonic-gate {
60390Sstevel@tonic-gate 	enum dkio_state state;
60400Sstevel@tonic-gate 
60410Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
60420Sstevel@tonic-gate 
60430Sstevel@tonic-gate 	if (fdsense_chng(fdc, unit)) {
60440Sstevel@tonic-gate 		/* check disk only if DSKCHG "high" */
60450Sstevel@tonic-gate 		if (fdcheckdisk(fdc, unit)) {
60460Sstevel@tonic-gate 			state = DKIO_EJECTED;
60470Sstevel@tonic-gate 		} else {
60480Sstevel@tonic-gate 			state = DKIO_INSERTED;
60490Sstevel@tonic-gate 		}
60500Sstevel@tonic-gate 	} else {
60510Sstevel@tonic-gate 		state = DKIO_INSERTED;
60520Sstevel@tonic-gate 	}
60530Sstevel@tonic-gate 	return (state);
60540Sstevel@tonic-gate }
60550Sstevel@tonic-gate 
60560Sstevel@tonic-gate static int
fd_check_media(dev_t dev,enum dkio_state state)60570Sstevel@tonic-gate fd_check_media(dev_t dev, enum dkio_state state)
60580Sstevel@tonic-gate {
60590Sstevel@tonic-gate 	struct fdunit *un;
60600Sstevel@tonic-gate 	struct fdctlr *fdc;
60610Sstevel@tonic-gate 	int		unit;
60620Sstevel@tonic-gate 
60630Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: start\n"));
60640Sstevel@tonic-gate 
60650Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
60660Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
60670Sstevel@tonic-gate 	un = fdc->c_un;
60680Sstevel@tonic-gate 
60690Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
60700Sstevel@tonic-gate 
60710Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
60720Sstevel@tonic-gate 
60730Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
60740Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
60750Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
60767656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
60770Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
60787656SSherry.Moore@Sun.COM 			    failed. \n"));
60790Sstevel@tonic-gate 
60800Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
60810Sstevel@tonic-gate 			return (EIO);
60820Sstevel@tonic-gate 		}
60830Sstevel@tonic-gate 
60840Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
60850Sstevel@tonic-gate 	}
60860Sstevel@tonic-gate 
60870Sstevel@tonic-gate 	un->un_media_state = fd_get_media_state(fdc, unit);
60880Sstevel@tonic-gate 
60890Sstevel@tonic-gate 	/* turn on timeout */
60900Sstevel@tonic-gate 	un->un_media_timeout = drv_usectohz(fd_check_media_time);
60910Sstevel@tonic-gate 	un->un_media_timeout_id = timeout(fd_media_watch,
60927656SSherry.Moore@Sun.COM 	    (void *)(ulong_t)dev, un->un_media_timeout);
60930Sstevel@tonic-gate 
60940Sstevel@tonic-gate 	while (un->un_media_state == state) {
60950Sstevel@tonic-gate 		if (cv_wait_sig(&fdc->c_statecv, &fdc->c_lolock) == 0) {
60960Sstevel@tonic-gate 			un->un_media_timeout = 0;
60970Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
60980Sstevel@tonic-gate 			return (EINTR);
60990Sstevel@tonic-gate 		}
61000Sstevel@tonic-gate 	}
61010Sstevel@tonic-gate 
61020Sstevel@tonic-gate 	if (un->un_media_timeout_id) {
61030Sstevel@tonic-gate 		timeout_id_t timeid = un->un_media_timeout_id;
61040Sstevel@tonic-gate 		un->un_media_timeout_id = 0;
61050Sstevel@tonic-gate 
61060Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
61070Sstevel@tonic-gate 		(void) untimeout(timeid);
61080Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
61090Sstevel@tonic-gate 	}
61100Sstevel@tonic-gate 
61110Sstevel@tonic-gate 	if (un->un_media_state == DKIO_INSERTED) {
61120Sstevel@tonic-gate 		if (fdgetlabel(fdc, unit)) {
61130Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
61140Sstevel@tonic-gate 			return (EIO);
61150Sstevel@tonic-gate 		}
61160Sstevel@tonic-gate 	}
61170Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
61180Sstevel@tonic-gate 
61190Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: end\n"));
61200Sstevel@tonic-gate 	return (0);
61210Sstevel@tonic-gate }
61220Sstevel@tonic-gate 
61230Sstevel@tonic-gate /*
61240Sstevel@tonic-gate  * fd_get_media_info :
61250Sstevel@tonic-gate  * 	Collects medium information for
61260Sstevel@tonic-gate  *	DKIOCGMEDIAINFO ioctl.
61270Sstevel@tonic-gate  */
61280Sstevel@tonic-gate 
61290Sstevel@tonic-gate static int
fd_get_media_info(struct fdunit * un,caddr_t buf,int flag)61300Sstevel@tonic-gate fd_get_media_info(struct fdunit *un, caddr_t buf, int flag)
61310Sstevel@tonic-gate {
61320Sstevel@tonic-gate 	struct dk_minfo media_info;
61330Sstevel@tonic-gate 	int err = 0;
61340Sstevel@tonic-gate 
61350Sstevel@tonic-gate 	media_info.dki_media_type = DK_FLOPPY;
61360Sstevel@tonic-gate 	media_info.dki_lbsize = un->un_chars->fdc_sec_size;
61370Sstevel@tonic-gate 	media_info.dki_capacity = un->un_chars->fdc_ncyl *
61387656SSherry.Moore@Sun.COM 	    un->un_chars->fdc_secptrack * un->un_chars->fdc_nhead;
61390Sstevel@tonic-gate 
61400Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)&media_info, buf,
61417656SSherry.Moore@Sun.COM 	    sizeof (struct dk_minfo), flag))
61427656SSherry.Moore@Sun.COM 		err = EFAULT;
61430Sstevel@tonic-gate 	return (err);
61440Sstevel@tonic-gate }
61450Sstevel@tonic-gate 
61460Sstevel@tonic-gate /*
61470Sstevel@tonic-gate  * fd_power :
61480Sstevel@tonic-gate  *	Power entry point of fd driver.
61490Sstevel@tonic-gate  */
61500Sstevel@tonic-gate 
61510Sstevel@tonic-gate static int
fd_power(dev_info_t * dip,int component,int level)61520Sstevel@tonic-gate fd_power(dev_info_t *dip, int component, int level)
61530Sstevel@tonic-gate {
61540Sstevel@tonic-gate 
61550Sstevel@tonic-gate 	struct fdctlr *fdc;
61560Sstevel@tonic-gate 	int instance;
61570Sstevel@tonic-gate 	int rval;
61580Sstevel@tonic-gate 
61590Sstevel@tonic-gate 	if ((level < PM_LEVEL_OFF) || (level > PM_LEVEL_ON) ||
61607656SSherry.Moore@Sun.COM 	    (component != 0)) {
61610Sstevel@tonic-gate 		return (DDI_FAILURE);
61620Sstevel@tonic-gate 	}
61630Sstevel@tonic-gate 
61640Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
61650Sstevel@tonic-gate 	fdc = fd_getctlr(instance << FDINSTSHIFT);
61660Sstevel@tonic-gate 	if (fdc->c_un == NULL)
61670Sstevel@tonic-gate 		return (DDI_FAILURE);
61680Sstevel@tonic-gate 
61690Sstevel@tonic-gate 	if (level == PM_LEVEL_OFF) {
61700Sstevel@tonic-gate 		rval = fd_pm_lower_power(fdc);
61710Sstevel@tonic-gate 	}
61720Sstevel@tonic-gate 	if (level == PM_LEVEL_ON) {
61730Sstevel@tonic-gate 		rval = fd_pm_raise_power(fdc);
61740Sstevel@tonic-gate 	}
61750Sstevel@tonic-gate 	return (rval);
61760Sstevel@tonic-gate }
61770Sstevel@tonic-gate 
61780Sstevel@tonic-gate /*
61790Sstevel@tonic-gate  * fd_pm_lower_power :
61800Sstevel@tonic-gate  *	This function is called only during pm suspend. At this point,
61810Sstevel@tonic-gate  *	the power management framework thinks the device is idle for
61820Sstevel@tonic-gate  *	long enough to go to a low power mode. If the device is busy,
61830Sstevel@tonic-gate  *	then this function returns DDI_FAILURE.
61840Sstevel@tonic-gate  */
61850Sstevel@tonic-gate 
61860Sstevel@tonic-gate static int
fd_pm_lower_power(struct fdctlr * fdc)61870Sstevel@tonic-gate fd_pm_lower_power(struct fdctlr *fdc)
61880Sstevel@tonic-gate {
61890Sstevel@tonic-gate 
61900Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
61910Sstevel@tonic-gate 
61920Sstevel@tonic-gate 	if ((fdc->c_un->un_state == FD_STATE_SUSPENDED) ||
61937656SSherry.Moore@Sun.COM 	    (fdc->c_un->un_state == FD_STATE_STOPPED)) {
61940Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
61950Sstevel@tonic-gate 		return (DDI_SUCCESS);
61960Sstevel@tonic-gate 	}
61970Sstevel@tonic-gate 
61980Sstevel@tonic-gate 
61990Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_lower_power called\n"));
62000Sstevel@tonic-gate 
62010Sstevel@tonic-gate 	/* if the device is busy then we fail the lower power request */
62020Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_BUSY) {
62030Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_PWR, (C, "fd_pm_lower_power : \
62040Sstevel@tonic-gate controller is busy.\n"));
62050Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
62060Sstevel@tonic-gate 		return (DDI_FAILURE);
62070Sstevel@tonic-gate 	}
62080Sstevel@tonic-gate 
62090Sstevel@tonic-gate 	fdc->c_un->un_state = FD_STATE_STOPPED;
62100Sstevel@tonic-gate 
62110Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
62120Sstevel@tonic-gate 	return (DDI_SUCCESS);
62130Sstevel@tonic-gate }
62140Sstevel@tonic-gate 
62150Sstevel@tonic-gate /*
62160Sstevel@tonic-gate  * fd_pm_raise_power :
62170Sstevel@tonic-gate  *	This function performs the necessary steps for resuming a
62180Sstevel@tonic-gate  *	device, either from pm suspend or CPR. Here the controller
62190Sstevel@tonic-gate  *	is reset, initialized and the state is set to FD_STATE_NORMAL.
62200Sstevel@tonic-gate  */
62210Sstevel@tonic-gate 
62220Sstevel@tonic-gate static int
fd_pm_raise_power(struct fdctlr * fdc)62230Sstevel@tonic-gate fd_pm_raise_power(struct fdctlr *fdc)
62240Sstevel@tonic-gate {
62250Sstevel@tonic-gate 
62260Sstevel@tonic-gate 	struct fdunit *un = fdc->c_un;
62270Sstevel@tonic-gate 	int unit;
62280Sstevel@tonic-gate 
62290Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_raise_power called\n"));
62300Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
62310Sstevel@tonic-gate 	fdgetcsb(fdc);
62320Sstevel@tonic-gate 
62330Sstevel@tonic-gate 	/* Reset the dma engine */
62340Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
62350Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
62360Sstevel@tonic-gate 		reset_dma_controller(fdc);
62370Sstevel@tonic-gate 		set_dma_control_register(fdc, DCSR_INIT_BITS);
62380Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
62390Sstevel@tonic-gate 	}
62400Sstevel@tonic-gate 
62410Sstevel@tonic-gate 	/*
62420Sstevel@tonic-gate 	 * Force a rotational speed set in the next
62430Sstevel@tonic-gate 	 * call to set_rotational_speed().
62440Sstevel@tonic-gate 	 */
62450Sstevel@tonic-gate 
62460Sstevel@tonic-gate 	fdc->c_un->un_flags |= FDUNIT_SET_SPEED;
62470Sstevel@tonic-gate 
62480Sstevel@tonic-gate 	/* Reset and configure the controller */
62490Sstevel@tonic-gate 	(void) fdreset(fdc);
62500Sstevel@tonic-gate 
62510Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
62520Sstevel@tonic-gate 
62530Sstevel@tonic-gate 	/* Recalibrate the drive */
62540Sstevel@tonic-gate 	if (fdrecalseek(fdc, unit, -1, 0) != 0) {
62550Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "raise_power : recalibrate \
62560Sstevel@tonic-gate failed\n"));
62570Sstevel@tonic-gate 		fdretcsb(fdc);
62580Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
62590Sstevel@tonic-gate 		return (DDI_FAILURE);
62600Sstevel@tonic-gate 	}
62610Sstevel@tonic-gate 
62620Sstevel@tonic-gate 	/* Select the drive through the AUXIO registers */
62630Sstevel@tonic-gate 	fdselect(fdc, unit, 0);
62640Sstevel@tonic-gate 	un->un_state = FD_STATE_NORMAL;
62650Sstevel@tonic-gate 	fdretcsb(fdc);
62660Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
62670Sstevel@tonic-gate 	return (DDI_SUCCESS);
62680Sstevel@tonic-gate }
62690Sstevel@tonic-gate 
62700Sstevel@tonic-gate /*
62710Sstevel@tonic-gate  * create_pm_components :
62720Sstevel@tonic-gate  *	creates the power management components for auto pm framework.
62730Sstevel@tonic-gate  */
62740Sstevel@tonic-gate 
62750Sstevel@tonic-gate static void
create_pm_components(dev_info_t * dip)62760Sstevel@tonic-gate create_pm_components(dev_info_t *dip)
62770Sstevel@tonic-gate {
62780Sstevel@tonic-gate 	char	*un_pm_comp[] = { "NAME=spindle-motor", "0=off", "1=on"};
62790Sstevel@tonic-gate 
62800Sstevel@tonic-gate 	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
62817656SSherry.Moore@Sun.COM 	    "pm-components", un_pm_comp, 3) == DDI_PROP_SUCCESS) {
62820Sstevel@tonic-gate 
62830Sstevel@tonic-gate 		(void) pm_raise_power(dip, 0, PM_LEVEL_ON);
62840Sstevel@tonic-gate 	}
62850Sstevel@tonic-gate }
62860Sstevel@tonic-gate 
62870Sstevel@tonic-gate /*
62880Sstevel@tonic-gate  * set_data_count_register(struct fdctlr *fdc, uint32_t count)
62890Sstevel@tonic-gate  * 	Set the data count in appropriate dma register.
62900Sstevel@tonic-gate  */
62910Sstevel@tonic-gate 
62920Sstevel@tonic-gate static void
set_data_count_register(struct fdctlr * fdc,uint32_t count)62930Sstevel@tonic-gate set_data_count_register(struct fdctlr *fdc, uint32_t count)
62940Sstevel@tonic-gate {
62950Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
62960Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
62970Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
62980Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr, count);
62990Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
63000Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
63010Sstevel@tonic-gate 		count = count - 1; /* 8237 needs it */
63020Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
63030Sstevel@tonic-gate 		switch (fdc->sb_dma_channel) {
63047656SSherry.Moore@Sun.COM 		case 0 :
63057656SSherry.Moore@Sun.COM 			ddi_put16(fdc->c_handlep_dma,
63067656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT],
63077656SSherry.Moore@Sun.COM 			    count & 0xFFFF);
63087656SSherry.Moore@Sun.COM 			break;
63097656SSherry.Moore@Sun.COM 		case 1 :
63107656SSherry.Moore@Sun.COM 			ddi_put16(fdc->c_handlep_dma,
63117656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT],
63127656SSherry.Moore@Sun.COM 			    count & 0xFFFF);
63137656SSherry.Moore@Sun.COM 			break;
63147656SSherry.Moore@Sun.COM 		case 2 :
63157656SSherry.Moore@Sun.COM 			ddi_put16(fdc->c_handlep_dma,
63167656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT],
63177656SSherry.Moore@Sun.COM 			    count & 0xFFFF);
63187656SSherry.Moore@Sun.COM 			break;
63197656SSherry.Moore@Sun.COM 		case 3 :
63207656SSherry.Moore@Sun.COM 			ddi_put16(fdc->c_handlep_dma,
63217656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT],
63227656SSherry.Moore@Sun.COM 			    count & 0xFFFF);
63237656SSherry.Moore@Sun.COM 			break;
63247656SSherry.Moore@Sun.COM 		default :
63257656SSherry.Moore@Sun.COM 			FDERRPRINT(FDEP_L3, FDEM_SDMA,
63267656SSherry.Moore@Sun.COM 			    (C, "set_data_count: wrong channel %x\n",
63277656SSherry.Moore@Sun.COM 			    fdc->sb_dma_channel));
63287656SSherry.Moore@Sun.COM 			break;
63290Sstevel@tonic-gate 		}
63300Sstevel@tonic-gate 	}
63310Sstevel@tonic-gate }
63320Sstevel@tonic-gate 
63330Sstevel@tonic-gate /*
63340Sstevel@tonic-gate  * get_data_count_register(struct fdctlr *fdc)
63350Sstevel@tonic-gate  * 	Read the data count from appropriate dma register.
63360Sstevel@tonic-gate  */
63370Sstevel@tonic-gate 
63380Sstevel@tonic-gate static uint32_t
get_data_count_register(struct fdctlr * fdc)63390Sstevel@tonic-gate get_data_count_register(struct fdctlr *fdc)
63400Sstevel@tonic-gate {
63410Sstevel@tonic-gate 	uint32_t retval = 0;
63420Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
63430Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
63440Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
63450Sstevel@tonic-gate 		retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr);
63460Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
63470Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
63480Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
63490Sstevel@tonic-gate 		switch (fdc->sb_dma_channel) {
63507656SSherry.Moore@Sun.COM 		case 0 :
63517656SSherry.Moore@Sun.COM 			retval = ddi_get16(fdc->c_handlep_dma,
63527656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT]);
63537656SSherry.Moore@Sun.COM 			break;
63547656SSherry.Moore@Sun.COM 		case 1 :
63557656SSherry.Moore@Sun.COM 			retval = ddi_get16(fdc->c_handlep_dma,
63567656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT]);
63577656SSherry.Moore@Sun.COM 			break;
63587656SSherry.Moore@Sun.COM 		case 2 :
63597656SSherry.Moore@Sun.COM 			retval = ddi_get16(fdc->c_handlep_dma,
63607656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT]);
63617656SSherry.Moore@Sun.COM 			break;
63627656SSherry.Moore@Sun.COM 		case 3 :
63637656SSherry.Moore@Sun.COM 			retval = ddi_get16(fdc->c_handlep_dma,
63647656SSherry.Moore@Sun.COM 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT]);
63657656SSherry.Moore@Sun.COM 			break;
63667656SSherry.Moore@Sun.COM 		default :
63677656SSherry.Moore@Sun.COM 			FDERRPRINT(FDEP_L3, FDEM_SDMA,
63687656SSherry.Moore@Sun.COM 			    (C, "get_data_count: wrong channel %x\n",
63697656SSherry.Moore@Sun.COM 			    fdc->sb_dma_channel));
63707656SSherry.Moore@Sun.COM 			break;
63710Sstevel@tonic-gate 		}
63720Sstevel@tonic-gate 		retval = (uint32_t)((uint16_t)(retval +1));
63730Sstevel@tonic-gate 	}
63740Sstevel@tonic-gate 
63750Sstevel@tonic-gate 	return (retval);
63760Sstevel@tonic-gate 
63770Sstevel@tonic-gate }
63780Sstevel@tonic-gate 
63790Sstevel@tonic-gate /*
63800Sstevel@tonic-gate  * reset_dma_controller(struct fdctlr *fdc)
63810Sstevel@tonic-gate  * 	Reset and initialize the dma controller.
63820Sstevel@tonic-gate  */
63830Sstevel@tonic-gate 
63840Sstevel@tonic-gate static void
reset_dma_controller(struct fdctlr * fdc)63850Sstevel@tonic-gate reset_dma_controller(struct fdctlr *fdc)
63860Sstevel@tonic-gate {
63870Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
63880Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
63890Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
63900Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, DCSR_RESET);
63917656SSherry.Moore@Sun.COM 		while (get_dma_control_register(fdc) & DCSR_CYC_PEND)
63927656SSherry.Moore@Sun.COM 			;
63930Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, 0);
63940Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
63950Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
63960Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
63970Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MASK],
63980Sstevel@tonic-gate 		    (fdc->sb_dma_channel & 0x3));
63990Sstevel@tonic-gate 
64000Sstevel@tonic-gate 	}
64010Sstevel@tonic-gate }
64020Sstevel@tonic-gate 
64030Sstevel@tonic-gate /*
64040Sstevel@tonic-gate  * Get the DMA control register for CHEERIO.
64050Sstevel@tonic-gate  * For SouthBridge 8237 DMA controller, this register is not valid.
64060Sstevel@tonic-gate  * So, just return 0.
64070Sstevel@tonic-gate  */
64080Sstevel@tonic-gate static uint32_t
get_dma_control_register(struct fdctlr * fdc)64090Sstevel@tonic-gate get_dma_control_register(struct fdctlr *fdc)
64100Sstevel@tonic-gate {
64110Sstevel@tonic-gate 	uint32_t retval = 0;
64120Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
64130Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
64140Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
64150Sstevel@tonic-gate 		retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr);
64160Sstevel@tonic-gate 	}
64170Sstevel@tonic-gate 
64180Sstevel@tonic-gate 	return (retval);
64190Sstevel@tonic-gate }
64200Sstevel@tonic-gate 
64210Sstevel@tonic-gate 
64220Sstevel@tonic-gate /*
64230Sstevel@tonic-gate  * set_data_address_register(struct fdctlr *fdc)
64240Sstevel@tonic-gate  * 	Set the data address in appropriate dma register.
64250Sstevel@tonic-gate  */
64260Sstevel@tonic-gate static void
set_data_address_register(struct fdctlr * fdc,uint32_t address)64270Sstevel@tonic-gate set_data_address_register(struct fdctlr *fdc, uint32_t address)
64280Sstevel@tonic-gate {
64290Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
64300Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
64310Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
64320Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dacr, address);
64330Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
64340Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
64350Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
64360Sstevel@tonic-gate 		switch (fdc->sb_dma_channel) {
64370Sstevel@tonic-gate 			case 0 :
64380Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64390Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_0PAGE],
64400Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64410Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64420Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_0HPG],
64430Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64440Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64450Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_0ADR],
64460Sstevel@tonic-gate 				    address & 0xFFFF);
64470Sstevel@tonic-gate 				break;
64480Sstevel@tonic-gate 			case 1 :
64490Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64500Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_1PAGE],
64510Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64520Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64530Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_1HPG],
64540Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64550Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64560Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_1ADR],
64570Sstevel@tonic-gate 				    address & 0xFFFF);
64580Sstevel@tonic-gate 				break;
64590Sstevel@tonic-gate 			case 2 :
64600Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64610Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_2PAGE],
64620Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64630Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64640Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_2HPG],
64650Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64660Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64670Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_2ADR],
64680Sstevel@tonic-gate 				    address & 0xFFFF);
64690Sstevel@tonic-gate 				break;
64700Sstevel@tonic-gate 			case 3 :
64710Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64720Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_3PAGE],
64730Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64740Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64750Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_3HPG],
64760Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64770Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64780Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_3ADR],
64790Sstevel@tonic-gate 				    address & 0xFFFF);
64800Sstevel@tonic-gate 				break;
64810Sstevel@tonic-gate 			default :
64820Sstevel@tonic-gate 				FDERRPRINT(FDEP_L3, FDEM_SDMA,
64837656SSherry.Moore@Sun.COM 				    (C, "set_data_address: wrong channel %x\n",
64847656SSherry.Moore@Sun.COM 				    fdc->sb_dma_channel));
64850Sstevel@tonic-gate 			break;
64860Sstevel@tonic-gate 		}
64870Sstevel@tonic-gate 	}
64880Sstevel@tonic-gate 
64890Sstevel@tonic-gate }
64900Sstevel@tonic-gate 
64910Sstevel@tonic-gate 
64920Sstevel@tonic-gate /*
64930Sstevel@tonic-gate  * set_dma_mode(struct fdctlr *fdc, int val)
64940Sstevel@tonic-gate  * 	Set the appropriate dma direction and registers.
64950Sstevel@tonic-gate  */
64960Sstevel@tonic-gate static void
set_dma_mode(struct fdctlr * fdc,int val)64970Sstevel@tonic-gate set_dma_mode(struct fdctlr *fdc, int val)
64980Sstevel@tonic-gate {
64990Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
65000Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
65010Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
65020Sstevel@tonic-gate 		if (val == CSB_READ)
65030Sstevel@tonic-gate 			ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
65047656SSherry.Moore@Sun.COM 			    DCSR_INIT_BITS|DCSR_WRITE);
65050Sstevel@tonic-gate 		else
65060Sstevel@tonic-gate 			ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
65077656SSherry.Moore@Sun.COM 			    DCSR_INIT_BITS);
65080Sstevel@tonic-gate 
65090Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
65100Sstevel@tonic-gate 		uint8_t mode_reg_val, chn_mask;
65110Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
65120Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
65130Sstevel@tonic-gate 
65140Sstevel@tonic-gate 		if (val == CSB_READ) {
65150Sstevel@tonic-gate 			mode_reg_val = fdc->sb_dma_channel | DMAMODE_READ
65167656SSherry.Moore@Sun.COM 			    | DMAMODE_SINGLE;
65170Sstevel@tonic-gate 		} else { /* Read operation */
65180Sstevel@tonic-gate 			mode_reg_val = fdc->sb_dma_channel | DMAMODE_WRITE
65197656SSherry.Moore@Sun.COM 			    | DMAMODE_SINGLE;
65200Sstevel@tonic-gate 		}
65210Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MODE],
65227656SSherry.Moore@Sun.COM 		    mode_reg_val);
65230Sstevel@tonic-gate 		chn_mask = 1 << (fdc->sb_dma_channel & 0x3);
65240Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_dma,
65257656SSherry.Moore@Sun.COM 		    &dma_reg->sb_dma_regs[DMAC1_ALLMASK], ~chn_mask);
65260Sstevel@tonic-gate 		fdc->sb_dma_lock = 1;
65270Sstevel@tonic-gate 	}
65280Sstevel@tonic-gate }
65290Sstevel@tonic-gate 
65300Sstevel@tonic-gate /*
65310Sstevel@tonic-gate  * This function is valid only for CHEERIO/RIO based
65320Sstevel@tonic-gate  * controllers. The control register for the dma channel
65330Sstevel@tonic-gate  * is initialized by this function.
65340Sstevel@tonic-gate  */
65350Sstevel@tonic-gate 
65360Sstevel@tonic-gate static void
set_dma_control_register(struct fdctlr * fdc,uint32_t val)65370Sstevel@tonic-gate set_dma_control_register(struct fdctlr *fdc, uint32_t val)
65380Sstevel@tonic-gate {
65390Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
65400Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
65410Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
65420Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, val);
65430Sstevel@tonic-gate 	}
65440Sstevel@tonic-gate }
65450Sstevel@tonic-gate 
65460Sstevel@tonic-gate static void
release_sb_dma(struct fdctlr * fdc)65470Sstevel@tonic-gate release_sb_dma(struct fdctlr *fdc)
65480Sstevel@tonic-gate {
65490Sstevel@tonic-gate 	struct sb_dma_reg *dma_reg;
65500Sstevel@tonic-gate 	dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
65510Sstevel@tonic-gate 	/* Unmask all the channels to release the DMA controller */
65520Sstevel@tonic-gate 	ddi_put8(fdc->c_handlep_dma,
65537656SSherry.Moore@Sun.COM 	    &dma_reg->sb_dma_regs[DMAC1_ALLMASK], NULL);
65540Sstevel@tonic-gate 	fdc->sb_dma_lock = 0;
65550Sstevel@tonic-gate }
65560Sstevel@tonic-gate 
65570Sstevel@tonic-gate static void
quiesce_fd_interrupt(struct fdctlr * fdc)65580Sstevel@tonic-gate quiesce_fd_interrupt(struct fdctlr *fdc)
65590Sstevel@tonic-gate {
65600Sstevel@tonic-gate 	/*
65610Sstevel@tonic-gate 	 * The following code is put here to take care of HW problem.
65620Sstevel@tonic-gate 	 * The HW problem is as follows:
65630Sstevel@tonic-gate 	 *
65640Sstevel@tonic-gate 	 *	After poweron the Southbridge floppy controller asserts the
65650Sstevel@tonic-gate 	 * interrupt in tristate. This causes continuous interrupts to
65660Sstevel@tonic-gate 	 * be generated.
65670Sstevel@tonic-gate 	 * Until the Hardware is FIXED we will have to use the following code
65680Sstevel@tonic-gate 	 * to set the interrupt line to proper state after poweron.
65690Sstevel@tonic-gate 	 */
65700Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB) {
65710Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
65727656SSherry.Moore@Sun.COM 		    0x0);
65730Sstevel@tonic-gate 		drv_usecwait(200);
65740Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
65757656SSherry.Moore@Sun.COM 		    0xC);
65760Sstevel@tonic-gate 		drv_usecwait(200);
65770Sstevel@tonic-gate 		Set_Fifo(fdc, 0xE6);
65780Sstevel@tonic-gate 		drv_usecwait(200);
65790Sstevel@tonic-gate 	}
65800Sstevel@tonic-gate }
6581