xref: /titanic_52/usr/src/uts/sun/io/fd.c (revision 427f591e1fcd1cf040406a539ad2725469a680fc)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
519397407SSherry Moore  * Common Development and Distribution License (the "License").
619397407SSherry Moore  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*427f591eSFred Herard  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Intel 82077 Floppy Disk Driver
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * Notes
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  *	0. The driver supports two flavors of hardware design:
347c478bd9Sstevel@tonic-gate  *		"SUNW,fdtwo"	- sun4m	- 82077 with sun4m style Auxio
357c478bd9Sstevel@tonic-gate  *		"fdthree"  - sun4u - 82077 with DMA
367c478bd9Sstevel@tonic-gate  *	   In addition it supports an apparent bug in some versions of
377c478bd9Sstevel@tonic-gate  *	   the 82077 controller.
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  *	1. The driver is mostly set up for multiple controllers, multiple
407c478bd9Sstevel@tonic-gate  *	drives. However- we *do* assume the use of the AUXIO register, and
417c478bd9Sstevel@tonic-gate  *	if we ever have > 1 fdc, we'll have to see what that means. This
427c478bd9Sstevel@tonic-gate  *	is all intrinsically machine specific, but there isn't much we
437c478bd9Sstevel@tonic-gate  *	can do about it.
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  *	2. The driver also is structured to deal with one drive active at
467c478bd9Sstevel@tonic-gate  *	a time. This is because the 82072 chip (no longer supported) was
477c478bd9Sstevel@tonic-gate  *	known to be buggy with respect to overlapped seeks.
487c478bd9Sstevel@tonic-gate  *
497c478bd9Sstevel@tonic-gate  *	3. The high level interrupt code is in assembler, and runs in a
507c478bd9Sstevel@tonic-gate  *	sparc trap window. It acts as a pseudo-dma engine as well as
517c478bd9Sstevel@tonic-gate  *	handles a couple of other interrupts. When it gets its job done,
527c478bd9Sstevel@tonic-gate  *	it schedules a second stage interrupt (soft interrupt) which
537c478bd9Sstevel@tonic-gate  *	is then fielded here in fd_lointr.  When DMA is used, the fdintr_dma
547c478bd9Sstevel@tonic-gate  *	interrupt handler is used.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  *	4. Nearly all locking is done on a lower level MUTEX_DRIVER
577c478bd9Sstevel@tonic-gate  *	mutex. The locking is quite conservative, and is generally
587c478bd9Sstevel@tonic-gate  *	established very close to any of the entries into the driver.
597c478bd9Sstevel@tonic-gate  *	There is nearly no locking done of the high level MUTEX_DRIVER
607c478bd9Sstevel@tonic-gate  *	mutex (which generally is a SPIN mutex because the floppy usually
617c478bd9Sstevel@tonic-gate  *	interrupts above LOCK_LEVEL). The assembler high level interrupt
627c478bd9Sstevel@tonic-gate  *	handler grabs the high level mutex, but the code in the driver
637c478bd9Sstevel@tonic-gate  *	here is especially structured to not need to do this.
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  *	5. Fdrawioctl commands that pass data are not optimized for
667c478bd9Sstevel@tonic-gate  *	speed. If they need to be faster, the driver structure will
677c478bd9Sstevel@tonic-gate  *	have to be redone such that fdrawioctl calls physio after
687c478bd9Sstevel@tonic-gate  *	cons'ing up a uio structure and that fdstart will be able
697c478bd9Sstevel@tonic-gate  *	to detect that a particular buffer is a 'special' buffer.
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  *	6. Removable media support is not complete.
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #include <sys/param.h>
767c478bd9Sstevel@tonic-gate #include <sys/buf.h>
777c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
787c478bd9Sstevel@tonic-gate #include <sys/uio.h>
797c478bd9Sstevel@tonic-gate #include <sys/open.h>
807c478bd9Sstevel@tonic-gate #include <sys/conf.h>
817c478bd9Sstevel@tonic-gate #include <sys/file.h>
827c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
837c478bd9Sstevel@tonic-gate #include <sys/debug.h>
847c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
857c478bd9Sstevel@tonic-gate #include <sys/stat.h>
867c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate #include <sys/dklabel.h>
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
917c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
927c478bd9Sstevel@tonic-gate #include <sys/fdio.h>
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
957c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
967c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * included to check for ELC or SLC which report floppy controller that
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate #include <sys/cpu.h>
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #include "sys/fdvar.h"
1047c478bd9Sstevel@tonic-gate #include "sys/fdreg.h"
1057c478bd9Sstevel@tonic-gate #include "sys/dma_i8237A.h"
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Defines
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate #define	KIOSP	KSTAT_IO_PTR(un->un_iostat)
1117c478bd9Sstevel@tonic-gate #define	KIOIP	KSTAT_INTR_PTR(fdc->c_intrstat)
1127c478bd9Sstevel@tonic-gate #define	MEDIUM_DENSITY	0x40
1137c478bd9Sstevel@tonic-gate #define	SEC_SIZE_CODE	(fdctlr.c_csb->csb_unit]->un_chars->medium ? 3 : 2)
1147c478bd9Sstevel@tonic-gate #define	CMD_READ	(MT + SK + FDRAW_RDCMD + MFM)
1157c478bd9Sstevel@tonic-gate #define	CMD_WRITE	(MT + FDRAW_WRCMD + MFM)
1167c478bd9Sstevel@tonic-gate #define	C		CE_CONT
1177c478bd9Sstevel@tonic-gate #define	FD_POLLABLE_PROP	"pollable"	/* prom property */
1187c478bd9Sstevel@tonic-gate #define	FD_MANUAL_EJECT		"manual"	/* prom property */
1197c478bd9Sstevel@tonic-gate #define	FD_UNIT			"unit"		/* prom property */
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Sony MP-F17W-50D Drive Parameters
1237c478bd9Sstevel@tonic-gate  *				High Capacity
1247c478bd9Sstevel@tonic-gate  *	Capacity unformatted	2Mb
1257c478bd9Sstevel@tonic-gate  *	Capacity formatted	1.47Mb
1267c478bd9Sstevel@tonic-gate  *	Encoding method	 MFM
1277c478bd9Sstevel@tonic-gate  *	Recording density	17434 bpi
1287c478bd9Sstevel@tonic-gate  *	Track density		135 tpi
1297c478bd9Sstevel@tonic-gate  *	Cylinders		80
1307c478bd9Sstevel@tonic-gate  *	Heads			2
1317c478bd9Sstevel@tonic-gate  *	Tracks			160
1327c478bd9Sstevel@tonic-gate  *	Rotational speed	300 rpm
1337c478bd9Sstevel@tonic-gate  *	Transfer rate		250/500 kbps
1347c478bd9Sstevel@tonic-gate  *	Latency (average)	100 ms
1357c478bd9Sstevel@tonic-gate  *	Access time
1367c478bd9Sstevel@tonic-gate  *		Average		95 ms
1377c478bd9Sstevel@tonic-gate  *		Track to track	3 ms
1387c478bd9Sstevel@tonic-gate  *	Head settling time	15 ms
1397c478bd9Sstevel@tonic-gate  *	Motor start time	500 ms
1407c478bd9Sstevel@tonic-gate  *	Head load time		? ms
1417c478bd9Sstevel@tonic-gate  */
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  * The max_fd_dma_len is used only when southbridge is present.
1457c478bd9Sstevel@tonic-gate  * It has been observed that when IFB tests are run the floppy dma could get
1467c478bd9Sstevel@tonic-gate  * starved and result in underrun errors. After experimenting it was found that
1477c478bd9Sstevel@tonic-gate  * doing dma in chunks of 2048 works OK.
1487c478bd9Sstevel@tonic-gate  * The reason for making this a global variable is that there could be
1497c478bd9Sstevel@tonic-gate  * situations under which the customer would like to get full performance
1507c478bd9Sstevel@tonic-gate  * from floppy. He may not be having IFB boards that cause underrun errors.
1517c478bd9Sstevel@tonic-gate  * Under those conditions we could set this value to a much higher value
1527c478bd9Sstevel@tonic-gate  * by editing /etc/system file.
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate int	max_fd_dma_len = 2048;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static void quiesce_fd_interrupt(struct fdctlr *);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Character/block entry points function prototypes
1607c478bd9Sstevel@tonic-gate  */
1617c478bd9Sstevel@tonic-gate static int fd_open(dev_t *, int, int, cred_t *);
1627c478bd9Sstevel@tonic-gate static int fd_close(dev_t, int, int, cred_t *);
1637c478bd9Sstevel@tonic-gate static int fd_strategy(struct buf *);
1647c478bd9Sstevel@tonic-gate static int fd_read(dev_t, struct uio *, cred_t *);
1657c478bd9Sstevel@tonic-gate static int fd_write(dev_t, struct uio *, cred_t *);
1667c478bd9Sstevel@tonic-gate static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1677c478bd9Sstevel@tonic-gate static int
1687c478bd9Sstevel@tonic-gate fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * Device operations (dev_ops) entries function prototypes
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate static int fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1747c478bd9Sstevel@tonic-gate 		void **result);
1757c478bd9Sstevel@tonic-gate static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
1767c478bd9Sstevel@tonic-gate static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
1777c478bd9Sstevel@tonic-gate static int fd_power(dev_info_t *dip, int component, int level);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * Internal functions
1817c478bd9Sstevel@tonic-gate  */
1827c478bd9Sstevel@tonic-gate static int fd_attach_check_drive(struct fdctlr *fdc);
1837c478bd9Sstevel@tonic-gate static int fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc);
1847c478bd9Sstevel@tonic-gate static int fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc);
1857c478bd9Sstevel@tonic-gate static int fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc,
1867c478bd9Sstevel@tonic-gate     int *hard);
1877c478bd9Sstevel@tonic-gate static int fd_build_label_vtoc(struct fdunit *, struct vtoc *);
1887c478bd9Sstevel@tonic-gate static void fd_build_user_vtoc(struct fdunit *, struct vtoc *);
1897c478bd9Sstevel@tonic-gate static int fdcheckdisk(struct fdctlr *fdc, int unit);
1907c478bd9Sstevel@tonic-gate static int fd_check_media(dev_t dev, enum dkio_state state);
1917c478bd9Sstevel@tonic-gate static void fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard,
1927c478bd9Sstevel@tonic-gate     int locks);
1937c478bd9Sstevel@tonic-gate static void fdeject(struct fdctlr *, int unit);
1947c478bd9Sstevel@tonic-gate static int fdexec(struct fdctlr *fdc, int flags);
1957c478bd9Sstevel@tonic-gate static void fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit);
1967c478bd9Sstevel@tonic-gate static int fdformat(struct fdctlr *fdc, int unit, int cyl, int hd);
1977c478bd9Sstevel@tonic-gate static caddr_t fd_getauxiova();
1987c478bd9Sstevel@tonic-gate static struct fdctlr *fd_getctlr(dev_t);
1997c478bd9Sstevel@tonic-gate static void fdgetcsb(struct fdctlr *);
2007c478bd9Sstevel@tonic-gate static int fdgetlabel(struct fdctlr *fdc, int unit);
2017c478bd9Sstevel@tonic-gate enum dkio_state fd_get_media_state(struct fdctlr *, int);
2027c478bd9Sstevel@tonic-gate static uint_t fdintr_dma();
2037c478bd9Sstevel@tonic-gate static int fd_isauxiodip(dev_info_t *);
2047c478bd9Sstevel@tonic-gate static uint_t  fd_lointr(caddr_t arg);
2057c478bd9Sstevel@tonic-gate static void fd_media_watch(void *);
2067c478bd9Sstevel@tonic-gate static void fdmotoff(void *);
2077c478bd9Sstevel@tonic-gate static int fd_part_is_open(struct fdunit *un, int part);
2087c478bd9Sstevel@tonic-gate static int fdrawioctl(struct fdctlr *, int, intptr_t, int);
2097c478bd9Sstevel@tonic-gate static int fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg);
2107c478bd9Sstevel@tonic-gate static int fdrecover(struct fdctlr *);
2117c478bd9Sstevel@tonic-gate static void fdretcsb(struct fdctlr *);
2127c478bd9Sstevel@tonic-gate static int fdreset(struct fdctlr *);
2137c478bd9Sstevel@tonic-gate static int fdrw(struct fdctlr *fdc, int, int, int, int, int, caddr_t, uint_t);
2147c478bd9Sstevel@tonic-gate static void fdselect(struct fdctlr *fdc, int unit, int onoff);
2157c478bd9Sstevel@tonic-gate static int fdsensedrv(struct fdctlr *fdc, int unit);
2167c478bd9Sstevel@tonic-gate static int fdsense_chng(struct fdctlr *, int unit);
2177c478bd9Sstevel@tonic-gate static void fdstart(struct fdctlr *);
2187c478bd9Sstevel@tonic-gate static int fdstart_dma(register struct fdctlr *fdc, caddr_t addr, uint_t len);
2197c478bd9Sstevel@tonic-gate static int fd_unit_is_open(struct fdunit *);
2207c478bd9Sstevel@tonic-gate static void fdunpacklabel(struct packed_label *, struct dk_label *);
2217c478bd9Sstevel@tonic-gate static int fd_unbind_handle(struct fdctlr *);
2227c478bd9Sstevel@tonic-gate static void fdwatch(void *);
2237c478bd9Sstevel@tonic-gate static void set_rotational_speed(struct fdctlr *, int);
2247c478bd9Sstevel@tonic-gate static int fd_get_media_info(struct fdunit *un, caddr_t buf, int flag);
2257c478bd9Sstevel@tonic-gate static int fd_pm_lower_power(struct fdctlr *fdc);
2267c478bd9Sstevel@tonic-gate static int fd_pm_raise_power(struct fdctlr *fdc);
2277c478bd9Sstevel@tonic-gate static void create_pm_components(dev_info_t *dip);
2287c478bd9Sstevel@tonic-gate static void set_data_count_register(struct fdctlr *fdc, uint32_t count);
2297c478bd9Sstevel@tonic-gate static uint32_t get_data_count_register(struct fdctlr *fdc);
2307c478bd9Sstevel@tonic-gate static void reset_dma_controller(struct fdctlr *fdc);
2317c478bd9Sstevel@tonic-gate static void set_data_address_register(struct fdctlr *fdc, uint32_t address);
2327c478bd9Sstevel@tonic-gate static uint32_t get_dma_control_register(struct fdctlr *fdc);
2337c478bd9Sstevel@tonic-gate static void set_dma_mode(struct fdctlr *fdc, int val);
2347c478bd9Sstevel@tonic-gate static void set_dma_control_register(struct fdctlr *fdc, uint32_t val);
2357c478bd9Sstevel@tonic-gate static void release_sb_dma(struct fdctlr *fdc);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * External functions
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate extern uint_t fd_intr(caddr_t);	/* defined in fd_asm.s */
2417c478bd9Sstevel@tonic-gate extern void set_auxioreg();
2427c478bd9Sstevel@tonic-gate extern void call_debug();
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * The following macro checks whether the device in a SUSPENDED state.
2487c478bd9Sstevel@tonic-gate  * As per WDD guide lines the I/O requests to a suspended device should
2497c478bd9Sstevel@tonic-gate  * be blocked until the device is resumed.
2507c478bd9Sstevel@tonic-gate  * Here we cv_wait on c_suspend_cv, and there is a cv_broadcast() in
2517c478bd9Sstevel@tonic-gate  * DDI_RESUME to wake up this thread.
2527c478bd9Sstevel@tonic-gate  *
2537c478bd9Sstevel@tonic-gate  * NOTE: This code is not tested because the kernel threads are suspended
2547c478bd9Sstevel@tonic-gate  * before the device is suspended. So there can not be any I/O requests on
2557c478bd9Sstevel@tonic-gate  * a suspended device until the cpr implementation changes..
2567c478bd9Sstevel@tonic-gate  */
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate #define	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc) 	\
2597c478bd9Sstevel@tonic-gate 		{\
2607c478bd9Sstevel@tonic-gate 			while (fdc->c_un->un_state == FD_STATE_SUSPENDED) {\
2617c478bd9Sstevel@tonic-gate 				cv_wait(&fdc->c_suspend_cv, \
2627c478bd9Sstevel@tonic-gate 							&fdc->c_lolock);\
2637c478bd9Sstevel@tonic-gate 			}\
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate  * bss (uninitialized data)
2687c478bd9Sstevel@tonic-gate  */
2697c478bd9Sstevel@tonic-gate struct	fdctlr	*fdctlrs;	/* linked list of controllers */
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * initialized data
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate static int fd_check_media_time = 5000000;	/* 5 second state check */
2767c478bd9Sstevel@tonic-gate static int fd_pollable = 0;
2777c478bd9Sstevel@tonic-gate static uchar_t rwretry = 10;
2787c478bd9Sstevel@tonic-gate static uchar_t skretry = 5;
2797c478bd9Sstevel@tonic-gate /* This variable allows the dynamic change of the burst size */
2807c478bd9Sstevel@tonic-gate static int fd_burstsize = DCSR_BURST_0 | DCSR_BURST_1;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate static struct driver_minor_data {
2837c478bd9Sstevel@tonic-gate 	char	*name;
2847c478bd9Sstevel@tonic-gate 	int	minor;
2857c478bd9Sstevel@tonic-gate 	int	type;
2867c478bd9Sstevel@tonic-gate } fd_minor [] = {
2877c478bd9Sstevel@tonic-gate 	{ "a", 0, S_IFBLK},
2887c478bd9Sstevel@tonic-gate 	{ "b", 1, S_IFBLK},
2897c478bd9Sstevel@tonic-gate 	{ "c", 2, S_IFBLK},
2907c478bd9Sstevel@tonic-gate 	{ "a,raw", 0, S_IFCHR},
2917c478bd9Sstevel@tonic-gate 	{ "b,raw", 1, S_IFCHR},
2927c478bd9Sstevel@tonic-gate 	{ "c,raw", 2, S_IFCHR},
2937c478bd9Sstevel@tonic-gate 	{0}
2947c478bd9Sstevel@tonic-gate };
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * If the interrupt handler is invoked and no controllers expect an
2987c478bd9Sstevel@tonic-gate  * interrupt, the kernel panics.  The following message is printed out.
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate char *panic_msg = "fd_intr: unexpected interrupt\n";
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate  * Specify/Configure cmd parameters
3047c478bd9Sstevel@tonic-gate  */
3057c478bd9Sstevel@tonic-gate static uchar_t fdspec[2] = { 0xc2, 0x33 };	/*  "specify" parameters */
3067c478bd9Sstevel@tonic-gate static uchar_t fdconf[3] = { 0x64, 0x58, 0x00 }; /*  "configure" parameters */
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /* When DMA is used, set the ND bit to 0 */
3097c478bd9Sstevel@tonic-gate #define	SPEC_DMA_MODE	0x32
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate /*
3127c478bd9Sstevel@tonic-gate  * default characteristics
3137c478bd9Sstevel@tonic-gate  */
3147c478bd9Sstevel@tonic-gate static struct fd_char fdtypes[] = {
3157c478bd9Sstevel@tonic-gate 	{	/* struct fd_char fdchar_1.7MB density */
3167c478bd9Sstevel@tonic-gate 		0,		/* medium */
3177c478bd9Sstevel@tonic-gate 		500,		/* transfer rate */
3187c478bd9Sstevel@tonic-gate 		80,		/* number of cylinders */
3197c478bd9Sstevel@tonic-gate 		2,		/* number of heads */
3207c478bd9Sstevel@tonic-gate 		512,		/* sector size */
3217c478bd9Sstevel@tonic-gate 		21,		/* sectors per track */
3227c478bd9Sstevel@tonic-gate 		-1,		/* (NA) # steps per data track */
3237c478bd9Sstevel@tonic-gate 	},
3247c478bd9Sstevel@tonic-gate 	{	/* struct fd_char fdchar_highdens */
3257c478bd9Sstevel@tonic-gate 		0, 		/* medium */
3267c478bd9Sstevel@tonic-gate 		500, 		/* transfer rate */
3277c478bd9Sstevel@tonic-gate 		80, 		/* number of cylinders */
3287c478bd9Sstevel@tonic-gate 		2, 		/* number of heads */
3297c478bd9Sstevel@tonic-gate 		512, 		/* sector size */
3307c478bd9Sstevel@tonic-gate 		18, 		/* sectors per track */
3317c478bd9Sstevel@tonic-gate 		-1, 		/* (NA) # steps per data track */
3327c478bd9Sstevel@tonic-gate 	},
3337c478bd9Sstevel@tonic-gate 	{	/* struct fd_char fdchar_meddens */
3347c478bd9Sstevel@tonic-gate 		1, 		/* medium */
3357c478bd9Sstevel@tonic-gate 		500, 		/* transfer rate */
3367c478bd9Sstevel@tonic-gate 		77, 		/* number of cylinders */
3377c478bd9Sstevel@tonic-gate 		2, 		/* number of heads */
3387c478bd9Sstevel@tonic-gate 		1024, 		/* sector size */
3397c478bd9Sstevel@tonic-gate 		8, 		/* sectors per track */
3407c478bd9Sstevel@tonic-gate 		-1, 		/* (NA) # steps per data track */
3417c478bd9Sstevel@tonic-gate 	},
3427c478bd9Sstevel@tonic-gate 	{	/* struct fd_char fdchar_lowdens  */
3437c478bd9Sstevel@tonic-gate 		0, 		/* medium */
3447c478bd9Sstevel@tonic-gate 		250, 		/* transfer rate */
3457c478bd9Sstevel@tonic-gate 		80, 		/* number of cylinders */
3467c478bd9Sstevel@tonic-gate 		2, 		/* number of heads */
3477c478bd9Sstevel@tonic-gate 		512, 		/* sector size */
3487c478bd9Sstevel@tonic-gate 		9, 		/* sectors per track */
3497c478bd9Sstevel@tonic-gate 		-1, 		/* (NA) # steps per data track */
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate };
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate static int nfdtypes = sizeof (fdtypes) / sizeof (fdtypes[0]);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * Default Label & partition maps
3597c478bd9Sstevel@tonic-gate  */
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_high_21 = {
3627c478bd9Sstevel@tonic-gate 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 21" },
3637c478bd9Sstevel@tonic-gate 	300,				/* rotations per minute */
3647c478bd9Sstevel@tonic-gate 	80,				/* # physical cylinders */
3657c478bd9Sstevel@tonic-gate 	0,				/* alternates per cylinder */
3667c478bd9Sstevel@tonic-gate 	1,				/* interleave factor */
3677c478bd9Sstevel@tonic-gate 	80,				/* # of data cylinders */
3687c478bd9Sstevel@tonic-gate 	0,				/* # of alternate cylinders */
3697c478bd9Sstevel@tonic-gate 	2,				/* # of heads in this partition */
3707c478bd9Sstevel@tonic-gate 	21,				/* # of 512 byte sectors per track */
3717c478bd9Sstevel@tonic-gate 	{
3727c478bd9Sstevel@tonic-gate 		{ 0, 79 * 2 * 21 },	/* part 0 - all but last cyl */
3737c478bd9Sstevel@tonic-gate 		{ 79, 1 * 2 * 21 },	/* part 1 - just the last cyl */
3747c478bd9Sstevel@tonic-gate 		{ 0, 80 * 2 * 21 },	/* part 2 - "the whole thing" */
3757c478bd9Sstevel@tonic-gate 	},
3767c478bd9Sstevel@tonic-gate 	{	0,			/* version */
3777c478bd9Sstevel@tonic-gate 		"",			/* volume label */
3787c478bd9Sstevel@tonic-gate 		3,			/* no. of partitions */
3797c478bd9Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
3807c478bd9Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
3817c478bd9Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
3827c478bd9Sstevel@tonic-gate 		{ 0 },			/* reserved space */
3837c478bd9Sstevel@tonic-gate 		0,			/* timestamp */
3847c478bd9Sstevel@tonic-gate 	},
3857c478bd9Sstevel@tonic-gate };
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_high_80 = {
3887c478bd9Sstevel@tonic-gate 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 18" },
3897c478bd9Sstevel@tonic-gate 	300, 				/* rotations per minute */
3907c478bd9Sstevel@tonic-gate 	80, 				/* # physical cylinders */
3917c478bd9Sstevel@tonic-gate 	0, 				/* alternates per cylinder */
3927c478bd9Sstevel@tonic-gate 	1, 				/* interleave factor */
3937c478bd9Sstevel@tonic-gate 	80, 				/* # of data cylinders */
3947c478bd9Sstevel@tonic-gate 	0, 				/* # of alternate cylinders */
3957c478bd9Sstevel@tonic-gate 	2, 				/* # of heads in this partition */
3967c478bd9Sstevel@tonic-gate 	18, 				/* # of 512 byte sectors per track */
3977c478bd9Sstevel@tonic-gate 	{
3987c478bd9Sstevel@tonic-gate 		{ 0, 79 * 2 * 18 }, 	/* part 0 - all but last cyl */
3997c478bd9Sstevel@tonic-gate 		{ 79, 1 * 2 * 18 }, 	/* part 1 - just the last cyl */
4007c478bd9Sstevel@tonic-gate 		{ 0, 80 * 2 * 18 }, 	/* part 2 - "the whole thing" */
4017c478bd9Sstevel@tonic-gate 	},
4027c478bd9Sstevel@tonic-gate 	{	0,			/* version */
4037c478bd9Sstevel@tonic-gate 		"",			/* volume label */
4047c478bd9Sstevel@tonic-gate 		3,			/* no. of partitions */
4057c478bd9Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
4067c478bd9Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
4077c478bd9Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
4087c478bd9Sstevel@tonic-gate 		{ 0 },			/* reserved space */
4097c478bd9Sstevel@tonic-gate 		0,			/* timestamp */
4107c478bd9Sstevel@tonic-gate 	},
4117c478bd9Sstevel@tonic-gate };
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate /*
4147c478bd9Sstevel@tonic-gate  * A medium density diskette has 1024 byte sectors.  The dk_label structure
4157c478bd9Sstevel@tonic-gate  * assumes a sector is DEVBSIZE (512) bytes.
4167c478bd9Sstevel@tonic-gate  */
4177c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_medium_80 = {
4187c478bd9Sstevel@tonic-gate 	{ "3.5\" floppy cyl 77 alt 0 hd 2 sec 8" },
4197c478bd9Sstevel@tonic-gate 	360, 				/* rotations per minute */
4207c478bd9Sstevel@tonic-gate 	77, 				/* # physical cylinders */
4217c478bd9Sstevel@tonic-gate 	0, 				/* alternates per cylinder */
4227c478bd9Sstevel@tonic-gate 	1, 				/* interleave factor */
4237c478bd9Sstevel@tonic-gate 	77, 				/* # of data cylinders */
4247c478bd9Sstevel@tonic-gate 	0, 				/* # of alternate cylinders */
4257c478bd9Sstevel@tonic-gate 	2, 				/* # of heads in this partition */
4267c478bd9Sstevel@tonic-gate 	16, 				/* # of 512 byte sectors per track */
4277c478bd9Sstevel@tonic-gate 	{
4287c478bd9Sstevel@tonic-gate 		{ 0, 76 * 2 * 8 * 2 },  /* part 0 - all but last cyl */
4297c478bd9Sstevel@tonic-gate 		{ 76, 1 * 2 * 8 * 2 },  /* part 1 - just the last cyl */
4307c478bd9Sstevel@tonic-gate 		{ 0, 77 * 2 * 8 * 2 },  /* part 2 - "the whole thing" */
4317c478bd9Sstevel@tonic-gate 	},
4327c478bd9Sstevel@tonic-gate 	{	0,			/* version */
4337c478bd9Sstevel@tonic-gate 		"",			/* volume label */
4347c478bd9Sstevel@tonic-gate 		3,			/* no. of partitions */
4357c478bd9Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
4367c478bd9Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
4377c478bd9Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
4387c478bd9Sstevel@tonic-gate 		{ 0 },			/* reserved space */
4397c478bd9Sstevel@tonic-gate 		0,			/* timestamp */
4407c478bd9Sstevel@tonic-gate 	},
4417c478bd9Sstevel@tonic-gate };
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_low_80 = {
4447c478bd9Sstevel@tonic-gate 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 9" },
4457c478bd9Sstevel@tonic-gate 	300, 				/* rotations per minute */
4467c478bd9Sstevel@tonic-gate 	80, 				/* # physical cylinders */
4477c478bd9Sstevel@tonic-gate 	0, 				/* alternates per cylinder */
4487c478bd9Sstevel@tonic-gate 	1, 				/* interleave factor */
4497c478bd9Sstevel@tonic-gate 	80, 				/* # of data cylinders */
4507c478bd9Sstevel@tonic-gate 	0, 				/* # of alternate cylinders */
4517c478bd9Sstevel@tonic-gate 	2, 				/* # of heads in this partition */
4527c478bd9Sstevel@tonic-gate 	9, 				/* # of 512 byte sectors per track */
4537c478bd9Sstevel@tonic-gate 	{
4547c478bd9Sstevel@tonic-gate 		{ 0, 79 * 2 * 9 }, 	/* part 0 - all but last cyl */
4557c478bd9Sstevel@tonic-gate 		{ 79, 1 * 2 * 9 }, 	/* part 1 - just the last cyl */
4567c478bd9Sstevel@tonic-gate 		{ 0, 80 * 2 * 9 }, 	/* part 2 - "the whole thing" */
4577c478bd9Sstevel@tonic-gate 	},
4587c478bd9Sstevel@tonic-gate 	{	0,			/* version */
4597c478bd9Sstevel@tonic-gate 		"",			/* volume label */
4607c478bd9Sstevel@tonic-gate 		3,			/* no. of partitions */
4617c478bd9Sstevel@tonic-gate 		{ 0 },			/* partition hdrs, sec 2 */
4627c478bd9Sstevel@tonic-gate 		{ 0 },			/* mboot info.  unsupported */
4637c478bd9Sstevel@tonic-gate 		VTOC_SANE,		/* verify vtoc sanity */
4647c478bd9Sstevel@tonic-gate 		{ 0 },			/* reserved space */
4657c478bd9Sstevel@tonic-gate 		0,			/* timestamp */
4667c478bd9Sstevel@tonic-gate 	},
4677c478bd9Sstevel@tonic-gate };
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate static struct fdcmdinfo {
4707c478bd9Sstevel@tonic-gate 	char *cmdname;		/* command name */
4717c478bd9Sstevel@tonic-gate 	uchar_t ncmdbytes;	/* number of bytes of command */
4727c478bd9Sstevel@tonic-gate 	uchar_t nrsltbytes;	/* number of bytes in result */
4737c478bd9Sstevel@tonic-gate 	uchar_t cmdtype;		/* characteristics */
4747c478bd9Sstevel@tonic-gate } fdcmds[] = {
4757c478bd9Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4767c478bd9Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4777c478bd9Sstevel@tonic-gate 	"read_track", 9, 7, 1, 		/* 2 */
4787c478bd9Sstevel@tonic-gate 	"specify", 3, 0, 3, 		/* 3 */
4797c478bd9Sstevel@tonic-gate 	"sense_drv_status", 2, 1, 3, 	/* 4 */
4807c478bd9Sstevel@tonic-gate 	"write", 9, 7, 1, 		/* 5 */
4817c478bd9Sstevel@tonic-gate 	"read", 9, 7, 1, 		/* 6 */
4827c478bd9Sstevel@tonic-gate 	"recalibrate", 2, 0, 2, 		/* 7 */
4837c478bd9Sstevel@tonic-gate 	"sense_int_status", 1, 2, 3, 	/* 8 */
4847c478bd9Sstevel@tonic-gate 	"write_del", 9, 7, 1, 		/* 9 */
4857c478bd9Sstevel@tonic-gate 	"read_id", 2, 7, 2, 		/* A */
4867c478bd9Sstevel@tonic-gate 	"motor_on/off", 1, 0, 4, 	/* B */
4877c478bd9Sstevel@tonic-gate 	"read_del", 9, 7, 1, 		/* C */
4887c478bd9Sstevel@tonic-gate 	"format_track", 10, 7, 1, 	/* D */
4897c478bd9Sstevel@tonic-gate 	"dump_reg", 1, 10, 4, 		/* E */
4907c478bd9Sstevel@tonic-gate 	"seek", 3, 0, 2, 		/* F */
4917c478bd9Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4927c478bd9Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4937c478bd9Sstevel@tonic-gate 	"", 0, 0, 0, 			/* - */
4947c478bd9Sstevel@tonic-gate 	"configure", 4, 0, 4, 		/* 13 */
4957c478bd9Sstevel@tonic-gate 	/* relative seek */
4967c478bd9Sstevel@tonic-gate };
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate static struct cb_ops fd_cb_ops = {
4997c478bd9Sstevel@tonic-gate 	fd_open, 		/* open */
5007c478bd9Sstevel@tonic-gate 	fd_close, 		/* close */
5017c478bd9Sstevel@tonic-gate 	fd_strategy, 		/* strategy */
5027c478bd9Sstevel@tonic-gate 	nodev, 			/* print */
5037c478bd9Sstevel@tonic-gate 	nodev, 			/* dump */
5047c478bd9Sstevel@tonic-gate 	fd_read, 		/* read */
5057c478bd9Sstevel@tonic-gate 	fd_write, 		/* write */
5067c478bd9Sstevel@tonic-gate 	fd_ioctl, 		/* ioctl */
5077c478bd9Sstevel@tonic-gate 	nodev, 			/* devmap */
5087c478bd9Sstevel@tonic-gate 	nodev, 			/* mmap */
5097c478bd9Sstevel@tonic-gate 	nodev, 			/* segmap */
5107c478bd9Sstevel@tonic-gate 	nochpoll, 		/* poll */
5117c478bd9Sstevel@tonic-gate 	fd_prop_op, 		/* cb_prop_op */
5127c478bd9Sstevel@tonic-gate 	0, 			/* streamtab  */
5137c478bd9Sstevel@tonic-gate 	D_NEW | D_MP		/* Driver compatibility flag */
5147c478bd9Sstevel@tonic-gate };
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate static struct dev_ops	fd_ops = {
5177c478bd9Sstevel@tonic-gate 	DEVO_REV, 		/* devo_rev, */
5187c478bd9Sstevel@tonic-gate 	0, 			/* refcnt  */
5197c478bd9Sstevel@tonic-gate 	fd_info, 		/* info */
5207c478bd9Sstevel@tonic-gate 	nulldev, 		/* identify */
5217c478bd9Sstevel@tonic-gate 	nulldev, 		/* probe */
5227c478bd9Sstevel@tonic-gate 	fd_attach, 		/* attach */
5237c478bd9Sstevel@tonic-gate 	fd_detach, 		/* detach */
5247c478bd9Sstevel@tonic-gate 	nodev, 			/* reset */
5257c478bd9Sstevel@tonic-gate 	&fd_cb_ops, 		/* driver operations */
5267c478bd9Sstevel@tonic-gate 	(struct bus_ops *)0,	/* bus operations */
52719397407SSherry Moore 	fd_power,		/* power */
52819397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
5297c478bd9Sstevel@tonic-gate };
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate  * error handling
5347c478bd9Sstevel@tonic-gate  *
5357c478bd9Sstevel@tonic-gate  * for debugging, set rwretry and skretry = 1
5367c478bd9Sstevel@tonic-gate  *		set fderrlevel to 1
5377c478bd9Sstevel@tonic-gate  *		set fderrmask  to 224  or 100644
5387c478bd9Sstevel@tonic-gate  *
5397c478bd9Sstevel@tonic-gate  * after debug set rwretry to 10, skretry to 5, and fderrlevel to 3
5407c478bd9Sstevel@tonic-gate  * set fderrmask to FDEM_ALL
5417c478bd9Sstevel@tonic-gate  * remove the define FD_DEBUG
5427c478bd9Sstevel@tonic-gate  *
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate static unsigned int fderrmask = (unsigned int)FDEM_ALL;
5467c478bd9Sstevel@tonic-gate static int fderrlevel = 3;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate static int tosec = 16;  /* long timeouts for sundiag for now */
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate  * loadable module support
5527c478bd9Sstevel@tonic-gate  */
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
5577c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
5587c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* Type of module. driver here */
55919397407SSherry Moore 	"Floppy Driver", 	/* Name of the module. */
5607c478bd9Sstevel@tonic-gate 	&fd_ops, 		/* Driver ops vector */
5617c478bd9Sstevel@tonic-gate };
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
5647c478bd9Sstevel@tonic-gate 	MODREV_1,
5657c478bd9Sstevel@tonic-gate 	&modldrv,
5667c478bd9Sstevel@tonic-gate 	NULL
5677c478bd9Sstevel@tonic-gate };
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate int
5707c478bd9Sstevel@tonic-gate _init(void)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate int
5767c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate int
5827c478bd9Sstevel@tonic-gate _fini(void)
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate 	int e;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) != 0)
5877c478bd9Sstevel@tonic-gate 		return (e);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/* ddi_soft_state_fini() */
5907c478bd9Sstevel@tonic-gate 	return (0);
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate /* ARGSUSED */
5947c478bd9Sstevel@tonic-gate static int
5957c478bd9Sstevel@tonic-gate fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	struct 			fdctlr *fdc;
5987c478bd9Sstevel@tonic-gate 	struct 			driver_minor_data *dmdp;
5997c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
6007c478bd9Sstevel@tonic-gate 	int			hard_intr_set = 0;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: start\n"));
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	switch (cmd) {
6057c478bd9Sstevel@tonic-gate 		case DDI_ATTACH:
6067c478bd9Sstevel@tonic-gate 			break;
6077c478bd9Sstevel@tonic-gate 		case DDI_RESUME:
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 			if (!(fdc = fd_getctlr(instance << FDINSTSHIFT))) {
6107c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
6117c478bd9Sstevel@tonic-gate 			}
6127c478bd9Sstevel@tonic-gate 			quiesce_fd_interrupt(fdc);
6137c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB)
6147c478bd9Sstevel@tonic-gate 				if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
6157c478bd9Sstevel@tonic-gate 				    fdintr_dma, (caddr_t)0) != DDI_SUCCESS) {
6167c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
6177c478bd9Sstevel@tonic-gate 			}
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 			(void) pm_raise_power(dip, 0, PM_LEVEL_ON);
6207c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
6217c478bd9Sstevel@tonic-gate 			/*
6227c478bd9Sstevel@tonic-gate 			 * Wake up any thread blocked due to I/O requests
6237c478bd9Sstevel@tonic-gate 			 * while the device was suspended.
6247c478bd9Sstevel@tonic-gate 			 */
6257c478bd9Sstevel@tonic-gate 			cv_broadcast(&fdc->c_suspend_cv);
6267c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
6277c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		default:
6307c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	/*
6357c478bd9Sstevel@tonic-gate 	 * Check for the pollable property
6367c478bd9Sstevel@tonic-gate 	 * A pollable floppy drive currently only exists on the
6377c478bd9Sstevel@tonic-gate 	 * Sparcstation Voyager.  This drive does not need to
6387c478bd9Sstevel@tonic-gate 	 * be turned on in order to sense whether or not a diskette
6397c478bd9Sstevel@tonic-gate 	 * is present.
6407c478bd9Sstevel@tonic-gate 	 */
6417c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, dip,
6427c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, FD_POLLABLE_PROP, 0))
6437c478bd9Sstevel@tonic-gate 		fd_pollable = 1;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	fdc = kmem_zalloc(sizeof (*fdc), KM_SLEEP);
6467c478bd9Sstevel@tonic-gate 	fdc->c_dip = dip;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	fdc->c_next = fdctlrs;
6507c478bd9Sstevel@tonic-gate 	fdctlrs = fdc;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* Determine which type of controller is present and initialize it */
6537c478bd9Sstevel@tonic-gate 	if (fd_attach_det_ctlr(dip, fdc) == DDI_FAILURE) {
6547c478bd9Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 0);
6557c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 	/* Finish mapping the device registers & setting up structures */
6587c478bd9Sstevel@tonic-gate 	if (fd_attach_map_regs(dip, fdc) == DDI_FAILURE) {
6597c478bd9Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 0);
6607c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	/*
6647c478bd9Sstevel@tonic-gate 	 * Initialize the DMA limit structures if it's being used.
6657c478bd9Sstevel@tonic-gate 	 */
6667c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
6677c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_version = DMA_ATTR_V0;
6687c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_addr_lo = 0x00000000ull;
6697c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_addr_hi = 0xfffffffeull;
6707c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_count_max = 0xffffff;
6717c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB) {
6727c478bd9Sstevel@tonic-gate 			fdc->c_fd_dma_lim.dma_attr_align = FD_SB_DMA_ALIGN;
6737c478bd9Sstevel@tonic-gate 		} else {
6747c478bd9Sstevel@tonic-gate 			fdc->c_fd_dma_lim.dma_attr_align = 1;
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_burstsizes = 0x0;
6777c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_minxfer = 1;
6787c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_maxxfer = 0xffff;
6797c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_seg = 0xffff;
6807c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_sgllen = 1;
6817c478bd9Sstevel@tonic-gate 		fdc->c_fd_dma_lim.dma_attr_granular = 512;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dip, &fdc->c_fd_dma_lim,
6847c478bd9Sstevel@tonic-gate 		    DDI_DMA_DONTWAIT, 0, &fdc->c_dmahandle) != DDI_SUCCESS) {
6857c478bd9Sstevel@tonic-gate 			fd_cleanup(dip, fdc, hard_intr_set, 0);
6867c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB) {
6907c478bd9Sstevel@tonic-gate 			ddi_device_acc_attr_t dev_attr;
6917c478bd9Sstevel@tonic-gate 			size_t	rlen;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 			dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6947c478bd9Sstevel@tonic-gate 			dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
6957c478bd9Sstevel@tonic-gate 			dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 			if (ddi_dma_mem_alloc(fdc->c_dmahandle,
6987c478bd9Sstevel@tonic-gate 			    (size_t)(32*1024), &dev_attr, DDI_DMA_CONSISTENT,
6997c478bd9Sstevel@tonic-gate 			    DDI_DMA_SLEEP, NULL, (caddr_t *)&fdc->dma_buf,
7007c478bd9Sstevel@tonic-gate 			    &rlen, &fdc->c_dma_buf_handle) != DDI_SUCCESS) {
7017c478bd9Sstevel@tonic-gate 				fd_cleanup(dip, fdc, hard_intr_set, 0);
7027c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
7037c478bd9Sstevel@tonic-gate 			}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 		}
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	/* Register the interrupts */
7107c478bd9Sstevel@tonic-gate 	if (fd_attach_register_interrupts(dip, fdc,
7117c478bd9Sstevel@tonic-gate 	    &hard_intr_set) == DDI_FAILURE) {
7127c478bd9Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 0);
7137c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
7147c478bd9Sstevel@tonic-gate 		    (C, "fd_attach: registering interrupts failed\n"));
7157c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	/*
7207c478bd9Sstevel@tonic-gate 	 * set initial controller/drive/disk "characteristics/geometry"
7217c478bd9Sstevel@tonic-gate 	 *
7227c478bd9Sstevel@tonic-gate 	 * NOTE:  The driver only supports one floppy drive.  The hardware
7237c478bd9Sstevel@tonic-gate 	 * only supports one drive because there is only one auxio register
7247c478bd9Sstevel@tonic-gate 	 * for one drive.
7257c478bd9Sstevel@tonic-gate 	 */
7267c478bd9Sstevel@tonic-gate 	fdc->c_un = kmem_zalloc(sizeof (struct fdunit), KM_SLEEP);
7277c478bd9Sstevel@tonic-gate 	fdc->c_un->un_chars = kmem_alloc(sizeof (struct fd_char), KM_SLEEP);
7287c478bd9Sstevel@tonic-gate 	fdc->c_un->un_iostat = kstat_create("fd", 0, "fd0", "disk",
7297c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
7307c478bd9Sstevel@tonic-gate 	if (fdc->c_un->un_iostat) {
7317c478bd9Sstevel@tonic-gate 		fdc->c_un->un_iostat->ks_lock = &fdc->c_lolock;
7327c478bd9Sstevel@tonic-gate 		kstat_install(fdc->c_un->un_iostat);
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	fdc->c_un->un_drive = kmem_zalloc(sizeof (struct fd_drive), KM_SLEEP);
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/* check for the manual eject property */
7387c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, dip,
7397c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, FD_MANUAL_EJECT, 0)) {
7407c478bd9Sstevel@tonic-gate 		fdc->c_un->un_drive->fdd_ejectable = 0;
7417c478bd9Sstevel@tonic-gate 	} else {
7427c478bd9Sstevel@tonic-gate 		/* an absence of the property indicates auto eject */
7437c478bd9Sstevel@tonic-gate 		fdc->c_un->un_drive->fdd_ejectable = -1;
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: ejectable? %d\n",
7477c478bd9Sstevel@tonic-gate 	    fdc->c_un->un_drive->fdd_ejectable));
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	/*
7507c478bd9Sstevel@tonic-gate 	 * Check for the drive id.  If the drive id property doesn't exist
7517c478bd9Sstevel@tonic-gate 	 * then the drive id is set to 0
7527c478bd9Sstevel@tonic-gate 	 */
7537c478bd9Sstevel@tonic-gate 	fdc->c_un->un_unit_no = ddi_getprop(DDI_DEV_T_ANY, dip,
7547c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, FD_UNIT, 0);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB) {
7587c478bd9Sstevel@tonic-gate 		fdc->sb_dma_channel = ddi_getprop(DDI_DEV_T_ANY, dip,
7597c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "dma-channel", 0);
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: unit %d\n",
7647c478bd9Sstevel@tonic-gate 	    fdc->c_un->un_unit_no));
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	/* Initially set the characteristics to high density */
7677c478bd9Sstevel@tonic-gate 	fdc->c_un->un_curfdtype = 1;
7687c478bd9Sstevel@tonic-gate 	*fdc->c_un->un_chars = fdtypes[fdc->c_un->un_curfdtype];
7697c478bd9Sstevel@tonic-gate 	fdunpacklabel(&fdlbl_high_80, &fdc->c_un->un_label);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/* Make sure drive is present */
7727c478bd9Sstevel@tonic-gate 	if (fd_attach_check_drive(fdc) == DDI_FAILURE) {
7737c478bd9Sstevel@tonic-gate 		fd_cleanup(dip, fdc, hard_intr_set, 1);
7747c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
7787c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
7797c478bd9Sstevel@tonic-gate 		    (instance << FDINSTSHIFT) | dmdp->minor,
7807c478bd9Sstevel@tonic-gate 		    DDI_NT_FD, 0) == DDI_FAILURE) {
7817c478bd9Sstevel@tonic-gate 			fd_cleanup(dip, fdc, hard_intr_set, 1);
7827c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	create_pm_components(dip);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/*
7897c478bd9Sstevel@tonic-gate 	 * Add a zero-length attribute to tell the world we support
7907c478bd9Sstevel@tonic-gate 	 * kernel ioctls (for layered drivers)
7917c478bd9Sstevel@tonic-gate 	 */
7927c478bd9Sstevel@tonic-gate 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
7937c478bd9Sstevel@tonic-gate 	    DDI_KERNEL_IOCTL, NULL, 0);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
7987c478bd9Sstevel@tonic-gate 	    (C, "attached 0x%x\n", ddi_get_instance(dip)));
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate /*
8047c478bd9Sstevel@tonic-gate  * Finish mapping the registers and initializing structures
8057c478bd9Sstevel@tonic-gate  */
8067c478bd9Sstevel@tonic-gate static int
8077c478bd9Sstevel@tonic-gate fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8127c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
8137c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	/* Map the DMA registers of the platform supports DMA */
8167c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB) {
8177c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
8187c478bd9Sstevel@tonic-gate 		    0, sizeof (struct sb_dma_reg), &attr,
8197c478bd9Sstevel@tonic-gate 		    &fdc->c_handlep_dma)) {
8207c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8217c478bd9Sstevel@tonic-gate 		}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
8257c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
8267c478bd9Sstevel@tonic-gate 		    0, sizeof (struct cheerio_dma_reg), &attr,
8277c478bd9Sstevel@tonic-gate 		    &fdc->c_handlep_dma)) {
8287c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8297c478bd9Sstevel@tonic-gate 		}
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/* Reset the DMA engine and enable floppy interrupts */
8337c478bd9Sstevel@tonic-gate 	reset_dma_controller(fdc);
8347c478bd9Sstevel@tonic-gate 	set_dma_control_register(fdc, DCSR_INIT_BITS);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	/* Finish initializing structures associated with the device regs */
8377c478bd9Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
8387c478bd9Sstevel@tonic-gate 	case FDCTYPE_82077:
8397c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "type is 82077\n"));
8407c478bd9Sstevel@tonic-gate 		/*
8417c478bd9Sstevel@tonic-gate 		 * Initialize addrs of key registers
8427c478bd9Sstevel@tonic-gate 		 */
8437c478bd9Sstevel@tonic-gate 		fdc->c_control =
8447c478bd9Sstevel@tonic-gate 		    (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_control;
8457c478bd9Sstevel@tonic-gate 		fdc->c_fifo = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_fifo;
8467c478bd9Sstevel@tonic-gate 		fdc->c_dor = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dor;
8477c478bd9Sstevel@tonic-gate 		fdc->c_dir = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dir;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, ((int)C,
8517c478bd9Sstevel@tonic-gate 		    (char *)"fdattach: msr/dsr at %p\n",
8527c478bd9Sstevel@tonic-gate 		    (void *)fdc->c_control));
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 		/*
8557c478bd9Sstevel@tonic-gate 		 * The 82077 doesn't use the first configuration parameter
8567c478bd9Sstevel@tonic-gate 		 * so let's adjust that while we know we're an 82077.
8577c478bd9Sstevel@tonic-gate 		 */
8587c478bd9Sstevel@tonic-gate 		fdconf[0] = 0;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 		quiesce_fd_interrupt(fdc);
8617c478bd9Sstevel@tonic-gate 		break;
8627c478bd9Sstevel@tonic-gate 	default:
8637c478bd9Sstevel@tonic-gate 		break;
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	return (0);
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate /*
8707c478bd9Sstevel@tonic-gate  * Determine which type of floppy controller is present and
8717c478bd9Sstevel@tonic-gate  * initialize the registers accordingly
8727c478bd9Sstevel@tonic-gate  */
8737c478bd9Sstevel@tonic-gate static int
8747c478bd9Sstevel@tonic-gate fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc)
8757c478bd9Sstevel@tonic-gate {
8767c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
8777c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8787c478bd9Sstevel@tonic-gate 	/* DDI_NEVERSWAP_ACC since the controller has a byte interface. */
8797c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
8807c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
8837c478bd9Sstevel@tonic-gate 	    (C, "fdattach_det_cltr: start \n"));
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	/*
8867c478bd9Sstevel@tonic-gate 	 * First, map in the controller's registers
8877c478bd9Sstevel@tonic-gate 	 * The controller has an 8-bit interface, so byte
8887c478bd9Sstevel@tonic-gate 	 * swapping isn't needed
8897c478bd9Sstevel@tonic-gate 	 */
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&fdc->c_reg,
8927c478bd9Sstevel@tonic-gate 	    0, sizeof (union fdcreg),
8937c478bd9Sstevel@tonic-gate 	    &attr,
8947c478bd9Sstevel@tonic-gate 	    &fdc->c_handlep_cont)) {
8957c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
8997c478bd9Sstevel@tonic-gate 	    (C, "fdattach_det_cltr: mapped floppy regs\n"));
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	/*
9037c478bd9Sstevel@tonic-gate 	 * Set platform specific characteristics based on the device-tree
9047c478bd9Sstevel@tonic-gate 	 * node name.
9057c478bd9Sstevel@tonic-gate 	 */
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_get_name(dip), "SUNW,fdtwo") == 0) {
9097c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_SLAVIO;
9107c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_82077;
9117c478bd9Sstevel@tonic-gate 		fdc->c_auxiova = fd_getauxiova(dip);
9127c478bd9Sstevel@tonic-gate 		fdc->c_auxiodata = (uchar_t)(AUX_MBO4M|AUX_TC4M);
9137c478bd9Sstevel@tonic-gate 		fdc->c_auxiodata2 = (uchar_t)AUX_TC4M;
9147c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9157c478bd9Sstevel@tonic-gate 		    (C, "fdattach: slavio will be used!\n"));
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate /*
9197c478bd9Sstevel@tonic-gate  * Check the binding name to identify whether it is a South bridge based
9207c478bd9Sstevel@tonic-gate  * system or not.
9217c478bd9Sstevel@tonic-gate  */
9227c478bd9Sstevel@tonic-gate 	} else if (strcmp(ddi_get_name(dip), "pnpALI,1533,0") == 0) {
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_SB;
9257c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_82077;
9267c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_DMA;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9297c478bd9Sstevel@tonic-gate 		    (C, "fdattach: southbridge will be used!\n"));
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 		/*
9327c478bd9Sstevel@tonic-gate 		 * The driver assumes high density characteristics until
9337c478bd9Sstevel@tonic-gate 		 * the diskette is looked at.
9347c478bd9Sstevel@tonic-gate 		 */
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_DMA8237;
9377c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	} else if (strcmp(ddi_get_name(dip), "fdthree") == 0) {
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_CHEERIO;
9437c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_82077;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9467c478bd9Sstevel@tonic-gate 		    (C, "fdattach: cheerio will be used!\n"));
9477c478bd9Sstevel@tonic-gate 		/*
9487c478bd9Sstevel@tonic-gate 		 * The cheerio auxio register should be memory mapped.  The
9497c478bd9Sstevel@tonic-gate 		 * auxio register on other platforms is shared and mapped
9507c478bd9Sstevel@tonic-gate 		 * elsewhere in the kernel
9517c478bd9Sstevel@tonic-gate 		 */
9527c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 2, (caddr_t *)&fdc->c_auxio_reg,
9537c478bd9Sstevel@tonic-gate 		    0, sizeof (uint_t), &attr, &fdc->c_handlep_aux)) {
9547c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 		/*
9587c478bd9Sstevel@tonic-gate 		 * The driver assumes high density characteristics until
9597c478bd9Sstevel@tonic-gate 		 * the diskette is looked at.
9607c478bd9Sstevel@tonic-gate 		 */
9617c478bd9Sstevel@tonic-gate 		Set_auxio(fdc, AUX_HIGH_DENSITY);
9627c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9637c478bd9Sstevel@tonic-gate 		    (C, "fdattach: auxio register 0x%x\n",
9647c478bd9Sstevel@tonic-gate 		    *fdc->c_auxio_reg));
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		fdc->c_fdtype |= FDCTYPE_DMA;
9677c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype == 0) {
9727c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9737c478bd9Sstevel@tonic-gate 		    (C, "fdattach: no controller!\n"));
9747c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9757c478bd9Sstevel@tonic-gate 	} else {
9767c478bd9Sstevel@tonic-gate 		return (0);
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate /*
9827c478bd9Sstevel@tonic-gate  * Register the floppy interrupts
9837c478bd9Sstevel@tonic-gate  */
9847c478bd9Sstevel@tonic-gate static int
9857c478bd9Sstevel@tonic-gate fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc, int *hard)
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t  iblock_cookie_soft;
9887c478bd9Sstevel@tonic-gate 	int status;
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	/*
9917c478bd9Sstevel@tonic-gate 	 * First call ddi_get_iblock_cookie() to retrieve the
9927c478bd9Sstevel@tonic-gate 	 * the interrupt block cookie so that the mutexes may
9937c478bd9Sstevel@tonic-gate 	 * be initialized before adding the interrupt.  If the
9947c478bd9Sstevel@tonic-gate 	 * mutexes are initialized after adding the interrupt, there
9957c478bd9Sstevel@tonic-gate 	 * could be a race condition.
9967c478bd9Sstevel@tonic-gate 	 */
9977c478bd9Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dip, 0, &fdc->c_block) != DDI_SUCCESS) {
9987c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
9997c478bd9Sstevel@tonic-gate 		    (C, "fdattach: ddi_get_iblock_cookie failed\n"));
10007c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/* Initialize high level mutex */
10057c478bd9Sstevel@tonic-gate 	mutex_init(&fdc->c_hilock, NULL, MUTEX_DRIVER, fdc->c_block);
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	/*
10087c478bd9Sstevel@tonic-gate 	 * Try to register fast trap handler, if unable try standard
10097c478bd9Sstevel@tonic-gate 	 * interrupt handler, else bad
10107c478bd9Sstevel@tonic-gate 	 */
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
10137c478bd9Sstevel@tonic-gate 		if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
10147c478bd9Sstevel@tonic-gate 		    fdintr_dma, (caddr_t)0) == DDI_SUCCESS) {
10157c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10167c478bd9Sstevel@tonic-gate 			    (C, "fdattach: standard intr\n"));
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 				/*
10197c478bd9Sstevel@tonic-gate 				 * When DMA is used, the low level lock
10207c478bd9Sstevel@tonic-gate 				 * is used in the hard interrupt handler.
10217c478bd9Sstevel@tonic-gate 				 */
10227c478bd9Sstevel@tonic-gate 				mutex_init(&fdc->c_lolock, NULL,
10237c478bd9Sstevel@tonic-gate 				    MUTEX_DRIVER, fdc->c_block);
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 				*hard = 1;
10267c478bd9Sstevel@tonic-gate 		} else {
10277c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10287c478bd9Sstevel@tonic-gate 			    (C, "fdattach: can't add dma intr\n"));
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10337c478bd9Sstevel@tonic-gate 		}
10347c478bd9Sstevel@tonic-gate 	} else {
10357c478bd9Sstevel@tonic-gate 		/*
10367c478bd9Sstevel@tonic-gate 		 * Platforms that don't support DMA have both hard
10377c478bd9Sstevel@tonic-gate 		 * and soft interrupts.
10387c478bd9Sstevel@tonic-gate 		 */
10397c478bd9Sstevel@tonic-gate 		if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
10407c478bd9Sstevel@tonic-gate 		    fd_intr, (caddr_t)0) == DDI_SUCCESS) {
10417c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10427c478bd9Sstevel@tonic-gate 			    (C, "fdattach: standard intr\n"));
10437c478bd9Sstevel@tonic-gate 			*hard = 1;
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 			/* fast traps are not enabled */
10467c478bd9Sstevel@tonic-gate 			fdc->c_fasttrap = 0;
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 		} else {
10497c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
10507c478bd9Sstevel@tonic-gate 			    (C, "fdattach: can't add intr\n"));
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10557c478bd9Sstevel@tonic-gate 		}
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 		/*
10597c478bd9Sstevel@tonic-gate 		 * Initialize the soft interrupt handler.  First call
10607c478bd9Sstevel@tonic-gate 		 * ddi_get_soft_iblock_cookie() so that the mutex may
10617c478bd9Sstevel@tonic-gate 		 * be initialized before the handler is added.
10627c478bd9Sstevel@tonic-gate 		 */
10637c478bd9Sstevel@tonic-gate 		status = ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
10647c478bd9Sstevel@tonic-gate 		    &iblock_cookie_soft);
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 		if (status != DDI_SUCCESS) {
10687c478bd9Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10697c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10707c478bd9Sstevel@tonic-gate 		}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		/*
10737c478bd9Sstevel@tonic-gate 		 * Initialize low level mutex which is used in the soft
10747c478bd9Sstevel@tonic-gate 		 * interrupt handler
10757c478bd9Sstevel@tonic-gate 		 */
10767c478bd9Sstevel@tonic-gate 		mutex_init(&fdc->c_lolock, NULL, MUTEX_DRIVER,
10777c478bd9Sstevel@tonic-gate 		    iblock_cookie_soft);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 		if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &fdc->c_softid,
10807c478bd9Sstevel@tonic-gate 		    NULL, NULL,
10817c478bd9Sstevel@tonic-gate 		    fd_lointr,
10827c478bd9Sstevel@tonic-gate 		    (caddr_t)fdc) != DDI_SUCCESS) {
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 			mutex_destroy(&fdc->c_hilock);
10857c478bd9Sstevel@tonic-gate 			mutex_destroy(&fdc->c_lolock);
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10887c478bd9Sstevel@tonic-gate 		}
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	fdc->c_intrstat = kstat_create("fd", 0, "fdc0", "controller",
10927c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
10937c478bd9Sstevel@tonic-gate 	if (fdc->c_intrstat) {
10947c478bd9Sstevel@tonic-gate 		fdc->c_hiintct = &KIOIP->intrs[KSTAT_INTR_HARD];
10957c478bd9Sstevel@tonic-gate 		kstat_install(fdc->c_intrstat);
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	/* condition variable to wait on while an io transaction occurs */
10997c478bd9Sstevel@tonic-gate 	cv_init(&fdc->c_iocv, NULL, CV_DRIVER, NULL);
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	/* condition variable for the csb */
11027c478bd9Sstevel@tonic-gate 	cv_init(&fdc->c_csbcv, NULL, CV_DRIVER, NULL);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	/* condition variable for motor on waiting period */
11057c478bd9Sstevel@tonic-gate 	cv_init(&fdc->c_motoncv, NULL, CV_DRIVER, NULL);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	/* semaphore to serialize opens and closes */
11087c478bd9Sstevel@tonic-gate 	sema_init(&fdc->c_ocsem, 1, NULL, SEMA_DRIVER, NULL);
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	/* condition variable to wait on suspended floppy controller. */
11117c478bd9Sstevel@tonic-gate 	cv_init(&fdc->c_suspend_cv, NULL, CV_DRIVER, NULL);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	return (0);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate /*
11177c478bd9Sstevel@tonic-gate  * Make sure the drive is present
11187c478bd9Sstevel@tonic-gate  * 	- acquires the low level lock
11197c478bd9Sstevel@tonic-gate  */
11207c478bd9Sstevel@tonic-gate static int
11217c478bd9Sstevel@tonic-gate fd_attach_check_drive(struct fdctlr *fdc)
11227c478bd9Sstevel@tonic-gate {
11237c478bd9Sstevel@tonic-gate 	int tmp_fderrlevel;
11247c478bd9Sstevel@tonic-gate 	int unit = fdc->c_un->un_unit_no;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
11277c478bd9Sstevel@tonic-gate 	    (C, "fd_attach_check_drive\n"));
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
11317c478bd9Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	/* insure that the eject line is reset */
11347c478bd9Sstevel@tonic-gate 	case FDCTYPE_82077:
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 		/*
11377c478bd9Sstevel@tonic-gate 		 * Everything but the motor enable, drive select,
11387c478bd9Sstevel@tonic-gate 		 * and reset bits are turned off.  These three
11397c478bd9Sstevel@tonic-gate 		 * bits remain as they are.
11407c478bd9Sstevel@tonic-gate 		 */
11417c478bd9Sstevel@tonic-gate 		/* LINTED */
11427c478bd9Sstevel@tonic-gate 		Set_dor(fdc, ~((MOTEN(unit))|DRVSEL|RESET), 0);
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
11457c478bd9Sstevel@tonic-gate 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 		drv_usecwait(5);
11487c478bd9Sstevel@tonic-gate 		if (unit == 0) {
11497c478bd9Sstevel@tonic-gate 			/* LINTED */
11507c478bd9Sstevel@tonic-gate 			Set_dor(fdc, RESET|DRVSEL, 1);
11517c478bd9Sstevel@tonic-gate 		} else {
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 			/* LINTED */
11547c478bd9Sstevel@tonic-gate 			Set_dor(fdc, DRVSEL, 0);
11557c478bd9Sstevel@tonic-gate 			/* LINTED */
11567c478bd9Sstevel@tonic-gate 			Set_dor(fdc, RESET, 1);
11577c478bd9Sstevel@tonic-gate 		}
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 		drv_usecwait(5);
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
11627c478bd9Sstevel@tonic-gate 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		if (!((fdc->c_fdtype & FDCTYPE_CHEERIO) ||
11657c478bd9Sstevel@tonic-gate 		    (fdc->c_fdtype & FDCTYPE_SB))) {
11667c478bd9Sstevel@tonic-gate 			set_auxioreg(AUX_TC4M, 0);
11677c478bd9Sstevel@tonic-gate 		}
11687c478bd9Sstevel@tonic-gate 		break;
11697c478bd9Sstevel@tonic-gate 	default:
11707c478bd9Sstevel@tonic-gate 		break;
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	fdgetcsb(fdc);
11757c478bd9Sstevel@tonic-gate 	if (fdreset(fdc) != 0) {
11767c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
11777c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11787c478bd9Sstevel@tonic-gate 	}
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	/* check for drive present */
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	tmp_fderrlevel = fderrlevel;
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	fderrlevel = FDEP_LMAX;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
11897c478bd9Sstevel@tonic-gate 	    (C, "fdattach: call fdrecalseek\n"));
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	/* Make sure the drive is present */
11927c478bd9Sstevel@tonic-gate 	if (fdrecalseek(fdc, unit, -1, 0) != 0) {
11937c478bd9Sstevel@tonic-gate 		timeout_id_t timeid = fdc->c_mtimeid;
11947c478bd9Sstevel@tonic-gate 		fderrlevel = tmp_fderrlevel;
11957c478bd9Sstevel@tonic-gate 		fdc->c_mtimeid = 0;
11967c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 		/* Do not hold the mutex over the call to untimeout */
12007c478bd9Sstevel@tonic-gate 		if (timeid) {
12017c478bd9Sstevel@tonic-gate 			(void) untimeout(timeid);
12027c478bd9Sstevel@tonic-gate 		}
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_ATTA,
12057c478bd9Sstevel@tonic-gate 		    (C, "fd_attach: no drive?\n"));
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	fderrlevel = tmp_fderrlevel;
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	fdselect(fdc, unit, 0);    /* deselect drive zero (used in fdreset) */
12137c478bd9Sstevel@tonic-gate 	fdretcsb(fdc);
12147c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	return (0);
12177c478bd9Sstevel@tonic-gate }
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate /*
12207c478bd9Sstevel@tonic-gate  * Clean up routine used by fd_detach and fd_attach
12217c478bd9Sstevel@tonic-gate  *
12227c478bd9Sstevel@tonic-gate  * Note: if the soft id is non-zero, then ddi_add_softintr() completed
12237c478bd9Sstevel@tonic-gate  * successfully.  I can not make the same assumption about the iblock_cookie
12247c478bd9Sstevel@tonic-gate  * for the high level interrupt handler.  So, the hard parameter indicates
12257c478bd9Sstevel@tonic-gate  * whether or not a high level interrupt handler has been added.
12267c478bd9Sstevel@tonic-gate  *
12277c478bd9Sstevel@tonic-gate  * If the locks parameter is nonzero, then all mutexes, semaphores and
12287c478bd9Sstevel@tonic-gate  * condition variables will be destroyed.
12297c478bd9Sstevel@tonic-gate  *
12307c478bd9Sstevel@tonic-gate  * Does not assume the low level mutex is held.
12317c478bd9Sstevel@tonic-gate  *
12327c478bd9Sstevel@tonic-gate  */
12337c478bd9Sstevel@tonic-gate static void
12347c478bd9Sstevel@tonic-gate fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard, int locks)
12357c478bd9Sstevel@tonic-gate {
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
123929df58e5Spc157239 	    (C, "fd_cleanup instance: %d ctlr: 0x%p\n",
124029df58e5Spc157239 	    ddi_get_instance(dip), (void *)fdc));
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	if (fdc == NULL) {
12447c478bd9Sstevel@tonic-gate 		return;
12457c478bd9Sstevel@tonic-gate 	}
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	/*
12487c478bd9Sstevel@tonic-gate 	 * Remove interrupt handlers first before anything else
12497c478bd9Sstevel@tonic-gate 	 * is deallocated.
12507c478bd9Sstevel@tonic-gate 	 */
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	/* Remove hard interrupt if one is registered */
12537c478bd9Sstevel@tonic-gate 	if (hard) {
12547c478bd9Sstevel@tonic-gate 		ddi_remove_intr(dip, (uint_t)0, fdc->c_block);
12557c478bd9Sstevel@tonic-gate 	}
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	/* Remove soft interrupt if one is registered */
12587c478bd9Sstevel@tonic-gate 	if (fdc->c_softid != NULL)
12597c478bd9Sstevel@tonic-gate 		ddi_remove_softintr(fdc->c_softid);
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	/* Remove timers */
12637c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_82077) {
12647c478bd9Sstevel@tonic-gate 		if (fdc->c_mtimeid)
12657c478bd9Sstevel@tonic-gate 			(void) untimeout(fdc->c_mtimeid);
12667c478bd9Sstevel@tonic-gate 		/*
12677c478bd9Sstevel@tonic-gate 		 * Need to turn off motor (includes select/LED for South Bridge
12687c478bd9Sstevel@tonic-gate 		 * chipset) just in case it was on when timer was removed
12697c478bd9Sstevel@tonic-gate 		 */
12707c478bd9Sstevel@tonic-gate 		fdmotoff(fdc);
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 	if (fdc->c_timeid)
12737c478bd9Sstevel@tonic-gate 		(void) untimeout(fdc->c_timeid);
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	/* Remove memory handles */
12777c478bd9Sstevel@tonic-gate 	if (fdc->c_handlep_cont)
12787c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&fdc->c_handlep_cont);
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	if (fdc->c_handlep_aux)
12817c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&fdc->c_handlep_aux);
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	if (fdc->c_handlep_dma)
12847c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&fdc->c_handlep_dma);
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	if (fdc->c_dma_buf_handle != NULL)
12877c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&fdc->c_dma_buf_handle);
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	if (fdc->c_dmahandle != NULL)
12907c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&fdc->c_dmahandle);
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	/* Remove all minor nodes */
12947c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	/* Remove unit structure if one exists */
12997c478bd9Sstevel@tonic-gate 	if (fdc->c_un != (struct fdunit *)NULL) {
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 		ASSERT(!mutex_owned(&fdc->c_lolock));
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 		if (fdc->c_un->un_iostat)
13047c478bd9Sstevel@tonic-gate 			kstat_delete(fdc->c_un->un_iostat);
13057c478bd9Sstevel@tonic-gate 		fdc->c_un->un_iostat = NULL;
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 		if (fdc->c_un->un_chars)
13087c478bd9Sstevel@tonic-gate 			kmem_free(fdc->c_un->un_chars, sizeof (struct fd_char));
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 		if (fdc->c_un->un_drive)
13117c478bd9Sstevel@tonic-gate 			kmem_free(fdc->c_un->un_drive,
13127c478bd9Sstevel@tonic-gate 			    sizeof (struct fd_drive));
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)fdc->c_un, sizeof (struct fdunit));
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	if (fdc->c_intrstat) {
13187c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
13197c478bd9Sstevel@tonic-gate 		    (C, "fd_cleanup: delete intrstat\n"));
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 		kstat_delete(fdc->c_intrstat);
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	fdc->c_intrstat = NULL;
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	if (locks) {
13277c478bd9Sstevel@tonic-gate 		cv_destroy(&fdc->c_iocv);
13287c478bd9Sstevel@tonic-gate 		cv_destroy(&fdc->c_csbcv);
13297c478bd9Sstevel@tonic-gate 		cv_destroy(&fdc->c_motoncv);
13307c478bd9Sstevel@tonic-gate 		cv_destroy(&fdc->c_suspend_cv);
13317c478bd9Sstevel@tonic-gate 		sema_destroy(&fdc->c_ocsem);
13327c478bd9Sstevel@tonic-gate 		mutex_destroy(&fdc->c_hilock);
13337c478bd9Sstevel@tonic-gate 		mutex_destroy(&fdc->c_lolock);
13347c478bd9Sstevel@tonic-gate 	}
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 	fdctlrs = fdc->c_next;
13387c478bd9Sstevel@tonic-gate 	kmem_free(fdc, sizeof (*fdc));
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate }
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate static int
13457c478bd9Sstevel@tonic-gate fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
13467c478bd9Sstevel@tonic-gate {
13477c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
13487c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc = fd_getctlr(instance << FDINSTSHIFT);
13497c478bd9Sstevel@tonic-gate 	timeout_id_t c_mtimeid;
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_detach\n"));
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	switch (cmd) {
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
13567c478bd9Sstevel@tonic-gate 		/*
13577c478bd9Sstevel@tonic-gate 		 * The hard parameter is set to 1.  If detach is called, then
13587c478bd9Sstevel@tonic-gate 		 * attach must have passed meaning that the high level
13597c478bd9Sstevel@tonic-gate 		 * interrupt handler was successfully added.
13607c478bd9Sstevel@tonic-gate 		 * Similarly, the locks parameter is also set to 1.
13617c478bd9Sstevel@tonic-gate 		 */
13627c478bd9Sstevel@tonic-gate 		fd_cleanup(dip, fdc, 1, 1);
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
13697c478bd9Sstevel@tonic-gate 		if (!fdc)
13707c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
13747c478bd9Sstevel@tonic-gate 		fdgetcsb(fdc);	/* Wait for I/O to finish */
13757c478bd9Sstevel@tonic-gate 		c_mtimeid = fdc->c_mtimeid;
13767c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
13777c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 		(void) untimeout(c_mtimeid);
13807c478bd9Sstevel@tonic-gate 		/*
13817c478bd9Sstevel@tonic-gate 		 * After suspend, the system could be powered off.
13827c478bd9Sstevel@tonic-gate 		 * When it is later powered on the southbridge floppy
13837c478bd9Sstevel@tonic-gate 		 * controller will tristate the interrupt line causing
13847c478bd9Sstevel@tonic-gate 		 * continuous dma interrupts.
13857c478bd9Sstevel@tonic-gate 		 * To avoid getting continuous fd interrupts we will remove the
13867c478bd9Sstevel@tonic-gate 		 * dma interrupt handler installed. We will re-install the
13877c478bd9Sstevel@tonic-gate 		 * handler when we RESUME.
13887c478bd9Sstevel@tonic-gate 		 */
13897c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB)
13907c478bd9Sstevel@tonic-gate 			ddi_remove_intr(dip, 0, fdc->c_block);
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 		fdc->c_un->un_state = FD_STATE_SUSPENDED;
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	default:
13977c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13987c478bd9Sstevel@tonic-gate 	}
13997c478bd9Sstevel@tonic-gate }
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate /* ARGSUSED */
14027c478bd9Sstevel@tonic-gate static int
14037c478bd9Sstevel@tonic-gate fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
14047c478bd9Sstevel@tonic-gate {
14057c478bd9Sstevel@tonic-gate 	register struct fdctlr *fdc;
14067c478bd9Sstevel@tonic-gate 	register int error;
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 	switch (infocmd) {
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
14117c478bd9Sstevel@tonic-gate 		if ((fdc = fd_getctlr((dev_t)arg)) == NULL) {
14127c478bd9Sstevel@tonic-gate 			error = DDI_FAILURE;
14137c478bd9Sstevel@tonic-gate 		} else {
14147c478bd9Sstevel@tonic-gate 			*result = fdc->c_dip;
14157c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
14167c478bd9Sstevel@tonic-gate 		}
14177c478bd9Sstevel@tonic-gate 		break;
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
14207c478bd9Sstevel@tonic-gate 		*result = 0;
14217c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
14227c478bd9Sstevel@tonic-gate 		break;
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	default:
14257c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate 	return (error);
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate /*
14317c478bd9Sstevel@tonic-gate  * property operation routine.  return the number of blocks for the partition
14327c478bd9Sstevel@tonic-gate  * in question or forward the request to the property facilities.
14337c478bd9Sstevel@tonic-gate  */
14347c478bd9Sstevel@tonic-gate static int
14357c478bd9Sstevel@tonic-gate fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
14367c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate 	struct fdunit	*un;
14397c478bd9Sstevel@tonic-gate 	struct fdctlr	*fdc;
14407c478bd9Sstevel@tonic-gate 	uint64_t	nblocks64;
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	/*
14437c478bd9Sstevel@tonic-gate 	 * Our dynamic properties are all device specific and size oriented.
14447c478bd9Sstevel@tonic-gate 	 * Requests issued under conditions where size is valid are passed
14457c478bd9Sstevel@tonic-gate 	 * to ddi_prop_op_nblocks with the size information, otherwise the
14467c478bd9Sstevel@tonic-gate 	 * request is passed to ddi_prop_op.
14477c478bd9Sstevel@tonic-gate 	 */
14487c478bd9Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY) {
14497c478bd9Sstevel@tonic-gate pass:  		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
14507c478bd9Sstevel@tonic-gate 		    name, valuep, lengthp));
14517c478bd9Sstevel@tonic-gate 	} else {
14527c478bd9Sstevel@tonic-gate 		fdc = fd_getctlr(dev);
14537c478bd9Sstevel@tonic-gate 		if (fdc == NULL)
14547c478bd9Sstevel@tonic-gate 			goto pass;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 		/* we have size if diskette opened and label read */
14577c478bd9Sstevel@tonic-gate 		un = fdc->c_un;
14587c478bd9Sstevel@tonic-gate 		if ((un == NULL) || !fd_unit_is_open(fdc->c_un))
14597c478bd9Sstevel@tonic-gate 			goto pass;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 		/* get nblocks value */
14627c478bd9Sstevel@tonic-gate 		nblocks64 = (ulong_t)
14637c478bd9Sstevel@tonic-gate 		    un->un_label.dkl_map[FDPARTITION(dev)].dkl_nblk;
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 		return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
14667c478bd9Sstevel@tonic-gate 		    name, valuep, lengthp, nblocks64));
14677c478bd9Sstevel@tonic-gate 	}
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
14717c478bd9Sstevel@tonic-gate static int
14727c478bd9Sstevel@tonic-gate fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
14737c478bd9Sstevel@tonic-gate {
14747c478bd9Sstevel@tonic-gate 	dev_t dev;
14757c478bd9Sstevel@tonic-gate 	int  part;
14767c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc;
14777c478bd9Sstevel@tonic-gate 	struct fdunit *un;
14787c478bd9Sstevel@tonic-gate 	struct dk_map32 *dkm;
14797c478bd9Sstevel@tonic-gate 	uchar_t	pbit;
14807c478bd9Sstevel@tonic-gate 	int	err, part_is_open;
14817c478bd9Sstevel@tonic-gate 	int 	unit;
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	dev = *devp;
14847c478bd9Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
14857c478bd9Sstevel@tonic-gate 	if ((fdc == NULL) || ((un = fdc->c_un) == NULL)) {
14867c478bd9Sstevel@tonic-gate 		return (ENXIO);
14877c478bd9Sstevel@tonic-gate 	}
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	/*
14927c478bd9Sstevel@tonic-gate 	 * Serialize opens/closes
14937c478bd9Sstevel@tonic-gate 	 */
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	sema_p(&fdc->c_ocsem);
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	/* check partition */
14987c478bd9Sstevel@tonic-gate 	part = FDPARTITION(dev);
14997c478bd9Sstevel@tonic-gate 	pbit = 1 << part;
15007c478bd9Sstevel@tonic-gate 	dkm = &un->un_label.dkl_map[part];
15017c478bd9Sstevel@tonic-gate 	if (dkm->dkl_nblk == 0) {
15027c478bd9Sstevel@tonic-gate 		sema_v(&fdc->c_ocsem);
15037c478bd9Sstevel@tonic-gate 		return (ENXIO);
15047c478bd9Sstevel@tonic-gate 	}
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
15077c478bd9Sstevel@tonic-gate 	    (C, "fdopen: ctlr %d unit %d part %d\n",
15087c478bd9Sstevel@tonic-gate 	    ddi_get_instance(fdc->c_dip), unit, part));
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
15117c478bd9Sstevel@tonic-gate 	    (C, "fdopen: flag 0x%x", flag));
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	/*
15157c478bd9Sstevel@tonic-gate 	 * Insure that drive is present with a recalibrate on first open.
15167c478bd9Sstevel@tonic-gate 	 */
15177c478bd9Sstevel@tonic-gate 	(void) pm_busy_component(fdc->c_dip, 0);
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
15247c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
15257c478bd9Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
15267c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
15277c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
15287c478bd9Sstevel@tonic-gate 			    failed. \n"));
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 				sema_v(&fdc->c_ocsem);
15317c478bd9Sstevel@tonic-gate 				(void) pm_idle_component(fdc->c_dip, 0);
15327c478bd9Sstevel@tonic-gate 				return (EIO);
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 	if (fd_unit_is_open(un) == 0) {
15377c478bd9Sstevel@tonic-gate 		fdgetcsb(fdc);
15387c478bd9Sstevel@tonic-gate 		/*
15397c478bd9Sstevel@tonic-gate 		 * no check changed!
15407c478bd9Sstevel@tonic-gate 		 */
15417c478bd9Sstevel@tonic-gate 		err = fdrecalseek(fdc, unit, -1, 0);
15427c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
15437c478bd9Sstevel@tonic-gate 		if (err) {
15447c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_OPEN,
15457c478bd9Sstevel@tonic-gate 			    (C, "fd%d: drive not ready\n", 0));
15467c478bd9Sstevel@tonic-gate 			/* deselect drv on last close */
15477c478bd9Sstevel@tonic-gate 			fdselect(fdc, unit, 0);
15487c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
15497c478bd9Sstevel@tonic-gate 			sema_v(&fdc->c_ocsem);
15507c478bd9Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
15517c478bd9Sstevel@tonic-gate 			return (EIO);
15527c478bd9Sstevel@tonic-gate 		}
15537c478bd9Sstevel@tonic-gate 	}
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	/*
15567c478bd9Sstevel@tonic-gate 	 * Check for previous exclusive open, or trying to exclusive open
15577c478bd9Sstevel@tonic-gate 	 */
15587c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
15597c478bd9Sstevel@tonic-gate 		part_is_open = (un->un_lyropen[part] != 0);
15607c478bd9Sstevel@tonic-gate 	} else {
15617c478bd9Sstevel@tonic-gate 		part_is_open = fd_part_is_open(un, part);
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 	if ((un->un_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
15647c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
15657c478bd9Sstevel@tonic-gate 		sema_v(&fdc->c_ocsem);
15667c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_OPEN, (C, "fd:just return\n"));
15677c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
15687c478bd9Sstevel@tonic-gate 		return (EBUSY);
15697c478bd9Sstevel@tonic-gate 	}
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	/* don't attempt access, just return successfully */
15727c478bd9Sstevel@tonic-gate 	if (flag & (FNDELAY | FNONBLOCK)) {
15737c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_OPEN,
15747c478bd9Sstevel@tonic-gate 		    (C, "fd: return busy..\n"));
15757c478bd9Sstevel@tonic-gate 		goto out;
15767c478bd9Sstevel@tonic-gate 	}
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	fdc->c_csb.csb_unit = (uchar_t)unit;
15797c478bd9Sstevel@tonic-gate 	if (fdgetlabel(fdc, unit)) {
15807c478bd9Sstevel@tonic-gate 		/* didn't find label (couldn't read anything) */
15817c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_OPEN,
15827c478bd9Sstevel@tonic-gate 		    (C,
15837c478bd9Sstevel@tonic-gate 		    "fd%d: unformatted diskette or no diskette in the drive\n",
15847c478bd9Sstevel@tonic-gate 		    0));
15857c478bd9Sstevel@tonic-gate 		if (fd_unit_is_open(un) == 0) {
15867c478bd9Sstevel@tonic-gate 			/* deselect drv on last close */
15877c478bd9Sstevel@tonic-gate 			fdselect(fdc, unit, 0);
15887c478bd9Sstevel@tonic-gate 		}
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
15917c478bd9Sstevel@tonic-gate 		sema_v(&fdc->c_ocsem);
15927c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
15937c478bd9Sstevel@tonic-gate 		return (EIO);
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	/*
15977c478bd9Sstevel@tonic-gate 	 * if opening for writing, check write protect on diskette
15987c478bd9Sstevel@tonic-gate 	 */
15997c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
16007c478bd9Sstevel@tonic-gate 		fdgetcsb(fdc);
16017c478bd9Sstevel@tonic-gate 		err = fdsensedrv(fdc, unit) & WP_SR3;
16027c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
16037c478bd9Sstevel@tonic-gate 		if (err) {
16047c478bd9Sstevel@tonic-gate 			if (fd_unit_is_open(un) == 0)
16057c478bd9Sstevel@tonic-gate 				fdselect(fdc, unit, 0);
16067c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
16077c478bd9Sstevel@tonic-gate 			sema_v(&fdc->c_ocsem);
16087c478bd9Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
16097c478bd9Sstevel@tonic-gate 			return (EROFS);
16107c478bd9Sstevel@tonic-gate 		}
16117c478bd9Sstevel@tonic-gate 	}
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate out:
16147c478bd9Sstevel@tonic-gate 	/*
16157c478bd9Sstevel@tonic-gate 	 * mark open as having succeeded
16167c478bd9Sstevel@tonic-gate 	 */
16177c478bd9Sstevel@tonic-gate 	if (flag & FEXCL) {
16187c478bd9Sstevel@tonic-gate 		un->un_exclmask |= pbit;
16197c478bd9Sstevel@tonic-gate 	}
16207c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
16217c478bd9Sstevel@tonic-gate 		un->un_lyropen[part]++;
16227c478bd9Sstevel@tonic-gate 	} else {
16237c478bd9Sstevel@tonic-gate 		un->un_regopen[otyp] |= pbit;
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
16267c478bd9Sstevel@tonic-gate 	sema_v(&fdc->c_ocsem);
16277c478bd9Sstevel@tonic-gate 	(void) pm_idle_component(fdc->c_dip, 0);
16287c478bd9Sstevel@tonic-gate 	return (0);
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate /*
16317c478bd9Sstevel@tonic-gate  * fd_part_is_open
16327c478bd9Sstevel@tonic-gate  *	return 1 if the partition is open
16337c478bd9Sstevel@tonic-gate  *	return 0 otherwise
16347c478bd9Sstevel@tonic-gate  */
16357c478bd9Sstevel@tonic-gate static int
16367c478bd9Sstevel@tonic-gate fd_part_is_open(struct fdunit *un, int part)
16377c478bd9Sstevel@tonic-gate {
16387c478bd9Sstevel@tonic-gate 	int i;
16397c478bd9Sstevel@tonic-gate 	for (i = 0; i < OTYPCNT - 1; i++)
16407c478bd9Sstevel@tonic-gate 		if (un->un_regopen[i] & (1 << part))
16417c478bd9Sstevel@tonic-gate 			return (1);
16427c478bd9Sstevel@tonic-gate 	return (0);
16437c478bd9Sstevel@tonic-gate }
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate /* ARGSUSED */
16477c478bd9Sstevel@tonic-gate static int
16487c478bd9Sstevel@tonic-gate fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
16497c478bd9Sstevel@tonic-gate {
16507c478bd9Sstevel@tonic-gate 	int unit, part_is_closed, part;
16517c478bd9Sstevel@tonic-gate 	register struct fdctlr *fdc;
16527c478bd9Sstevel@tonic-gate 	register struct fdunit *un;
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
16557c478bd9Sstevel@tonic-gate 	if (!fdc || !(un = fdc->c_un))
16567c478bd9Sstevel@tonic-gate 		return (ENXIO);
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
16607c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CLOS, (C, "fd_close\n"));
16617c478bd9Sstevel@tonic-gate 	part = FDPARTITION(dev);
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	sema_p(&fdc->c_ocsem);
16647c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
16677c478bd9Sstevel@tonic-gate 		un->un_lyropen[part]--;
16687c478bd9Sstevel@tonic-gate 		part_is_closed = (un->un_lyropen[part] == 0);
16697c478bd9Sstevel@tonic-gate 	} else {
16707c478bd9Sstevel@tonic-gate 		un->un_regopen[otyp] &= ~(1<<part);
16717c478bd9Sstevel@tonic-gate 		part_is_closed = 1;
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 	if (part_is_closed)
16747c478bd9Sstevel@tonic-gate 		un->un_exclmask &= ~(1<<part);
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	if (fd_unit_is_open(un) == 0) {
16777c478bd9Sstevel@tonic-gate 		/* deselect drive on last close */
16787c478bd9Sstevel@tonic-gate 		fdselect(fdc, unit, 0);
16797c478bd9Sstevel@tonic-gate 		un->un_flags &= ~FDUNIT_CHANGED;
16807c478bd9Sstevel@tonic-gate 	}
16817c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
16827c478bd9Sstevel@tonic-gate 	sema_v(&fdc->c_ocsem);
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	return (0);
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate /*
16887c478bd9Sstevel@tonic-gate  * fd_strategy
16897c478bd9Sstevel@tonic-gate  *	checks operation, hangs buf struct off fdctlr, calls fdstart
16907c478bd9Sstevel@tonic-gate  *	if not already busy.  Note that if we call start, then the operation
16917c478bd9Sstevel@tonic-gate  *	will already be done on return (start sleeps).
16927c478bd9Sstevel@tonic-gate  */
16937c478bd9Sstevel@tonic-gate static int
16947c478bd9Sstevel@tonic-gate fd_strategy(register struct buf *bp)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc;
16977c478bd9Sstevel@tonic-gate 	struct fdunit *un;
16987c478bd9Sstevel@tonic-gate 	uint_t	phys_blkno;
16997c478bd9Sstevel@tonic-gate 	struct dk_map32 *dkm;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_STRA,
17027c478bd9Sstevel@tonic-gate 	    (C, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
17037c478bd9Sstevel@tonic-gate 	    (void *)bp, bp->b_edev));
17047c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_STRA,
17057c478bd9Sstevel@tonic-gate 	    (C, "b_blkno=%x b_flags=%x b_count=%x\n",
17067c478bd9Sstevel@tonic-gate 	    (int)bp->b_blkno, bp->b_flags, (int)bp->b_bcount));
17077c478bd9Sstevel@tonic-gate 	fdc = fd_getctlr(bp->b_edev);
17087c478bd9Sstevel@tonic-gate 	un = fdc->c_un;
17097c478bd9Sstevel@tonic-gate 	dkm = &un->un_label.dkl_map[FDPARTITION(bp->b_edev)];
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	/*
17127c478bd9Sstevel@tonic-gate 	 * If it's medium density and the block no. isn't a multiple
17137c478bd9Sstevel@tonic-gate 	 * of 1K, then return an error.
17147c478bd9Sstevel@tonic-gate 	 */
17157c478bd9Sstevel@tonic-gate 	if (un->un_chars->fdc_medium) {
17167c478bd9Sstevel@tonic-gate 		phys_blkno = (uint_t)bp->b_blkno >> 1;
17177c478bd9Sstevel@tonic-gate 		if (bp->b_blkno & 1) {
17187c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_STRA,
17197c478bd9Sstevel@tonic-gate 			    (C, "b_blkno=0x%lx is not 1k aligned\n",
17207c478bd9Sstevel@tonic-gate 			    (long)bp->b_blkno));
17217c478bd9Sstevel@tonic-gate 			bp->b_error = EINVAL;
17227c478bd9Sstevel@tonic-gate 			bp->b_resid = bp->b_bcount;
17237c478bd9Sstevel@tonic-gate 			bp->b_flags |= B_ERROR;
17247c478bd9Sstevel@tonic-gate 			biodone(bp);
17257c478bd9Sstevel@tonic-gate 			return (0);
17267c478bd9Sstevel@tonic-gate 		}
17277c478bd9Sstevel@tonic-gate 	} else {
17287c478bd9Sstevel@tonic-gate 		phys_blkno = (uint_t)bp->b_blkno;
17297c478bd9Sstevel@tonic-gate 	}
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	/* If the block number is past the end, return an error */
17337c478bd9Sstevel@tonic-gate 	if ((phys_blkno > dkm->dkl_nblk)) {
17347c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
17357c478bd9Sstevel@tonic-gate 		    (C, "fd%d: block %ld is past the end! (nblk=%d)\n",
17367c478bd9Sstevel@tonic-gate 		    0, (long)bp->b_blkno, dkm->dkl_nblk));
17377c478bd9Sstevel@tonic-gate 		bp->b_error = ENOSPC;
17387c478bd9Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
17397c478bd9Sstevel@tonic-gate 		bp->b_flags |= B_ERROR;
17407c478bd9Sstevel@tonic-gate 		biodone(bp);
17417c478bd9Sstevel@tonic-gate 		return (0);
17427c478bd9Sstevel@tonic-gate 	}
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	/* if at end of file, skip out now */
17457c478bd9Sstevel@tonic-gate 	if (phys_blkno == dkm->dkl_nblk) {
17467c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_STRA,
17477c478bd9Sstevel@tonic-gate 		    (C, "b_blkno is at the end!\n"));
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 		if ((bp->b_flags & B_READ) == 0) {
17507c478bd9Sstevel@tonic-gate 			/* a write needs to get an error! */
17517c478bd9Sstevel@tonic-gate 			bp->b_error = ENOSPC;
17527c478bd9Sstevel@tonic-gate 			bp->b_flags |= B_ERROR;
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRA,
17557c478bd9Sstevel@tonic-gate 			    (C, "block is at end and this is a write\n"));
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 		}
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
17607c478bd9Sstevel@tonic-gate 		biodone(bp);
17617c478bd9Sstevel@tonic-gate 		return (0);
17627c478bd9Sstevel@tonic-gate 	}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	/* if operation not a multiple of sector size, is error! */
17657c478bd9Sstevel@tonic-gate 	if (bp->b_bcount % un->un_chars->fdc_sec_size)	{
17667c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
17677c478bd9Sstevel@tonic-gate 		    (C, "fd%d: requested transfer size(0x%lx) is not"
17687c478bd9Sstevel@tonic-gate 		    " multiple of sector size(0x%x)\n", 0,
17697c478bd9Sstevel@tonic-gate 		    bp->b_bcount, un->un_chars->fdc_sec_size));
17707c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
17717c478bd9Sstevel@tonic-gate 		    (C, "	b_blkno=0x%lx b_flags=0x%x\n",
17727c478bd9Sstevel@tonic-gate 		    (long)bp->b_blkno, bp->b_flags));
17737c478bd9Sstevel@tonic-gate 		bp->b_error = EINVAL;
17747c478bd9Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
17757c478bd9Sstevel@tonic-gate 		bp->b_flags |= B_ERROR;
17767c478bd9Sstevel@tonic-gate 		biodone(bp);
17777c478bd9Sstevel@tonic-gate 		return (0);
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	}
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate 	/*
17827c478bd9Sstevel@tonic-gate 	 * Put the buf request in the controller's queue, FIFO.
17837c478bd9Sstevel@tonic-gate 	 */
17847c478bd9Sstevel@tonic-gate 	bp->av_forw = 0;
17857c478bd9Sstevel@tonic-gate 	sema_p(&fdc->c_ocsem);
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 	(void) pm_busy_component(fdc->c_dip, 0);
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
17947c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
17957c478bd9Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
17967c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
17977c478bd9Sstevel@tonic-gate 			sema_v(&fdc->c_ocsem);
17987c478bd9Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
17997c478bd9Sstevel@tonic-gate 			bp->b_error = EIO;
18007c478bd9Sstevel@tonic-gate 			bp->b_resid = bp->b_bcount;
18017c478bd9Sstevel@tonic-gate 			bp->b_flags |= B_ERROR;
18027c478bd9Sstevel@tonic-gate 			biodone(bp);
18037c478bd9Sstevel@tonic-gate 			return (0);
18047c478bd9Sstevel@tonic-gate 		} else {
18057c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
18067c478bd9Sstevel@tonic-gate 		}
18077c478bd9Sstevel@tonic-gate 	}
18087c478bd9Sstevel@tonic-gate 	if (un->un_iostat) {
18097c478bd9Sstevel@tonic-gate 		kstat_waitq_enter(KIOSP);
18107c478bd9Sstevel@tonic-gate 	}
18117c478bd9Sstevel@tonic-gate 	if (fdc->c_actf)
18127c478bd9Sstevel@tonic-gate 		fdc->c_actl->av_forw = bp;
18137c478bd9Sstevel@tonic-gate 	else
18147c478bd9Sstevel@tonic-gate 		fdc->c_actf = bp;
18157c478bd9Sstevel@tonic-gate 	fdc->c_actl = bp;
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	/* call fdstart to start the transfer */
18197c478bd9Sstevel@tonic-gate 	fdstart(fdc);
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
18227c478bd9Sstevel@tonic-gate 	sema_v(&fdc->c_ocsem);
18237c478bd9Sstevel@tonic-gate 	(void) pm_idle_component(fdc->c_dip, 0);
18247c478bd9Sstevel@tonic-gate 	return (0);
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
18287c478bd9Sstevel@tonic-gate static int
18297c478bd9Sstevel@tonic-gate fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
18307c478bd9Sstevel@tonic-gate {
18317c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_read\n"));
18327c478bd9Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
18337c478bd9Sstevel@tonic-gate }
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
18367c478bd9Sstevel@tonic-gate static int
18377c478bd9Sstevel@tonic-gate fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
18387c478bd9Sstevel@tonic-gate {
18397c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_write\n"));
18407c478bd9Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
18417c478bd9Sstevel@tonic-gate }
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate static void
18447c478bd9Sstevel@tonic-gate fdmotoff(void *arg)
18457c478bd9Sstevel@tonic-gate {
18467c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc = arg;
18477c478bd9Sstevel@tonic-gate 	int unit = fdc->c_un->un_unit_no;
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 	/* Just return if we're about to call untimeout */
18527c478bd9Sstevel@tonic-gate 	if (fdc->c_mtimeid == 0) {
18537c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
18547c478bd9Sstevel@tonic-gate 		return;
18557c478bd9Sstevel@tonic-gate 	}
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_MOFF, (C, "fdmotoff\n"));
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	fdc->c_mtimeid = 0;
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	if (!(Msr(fdc) & CB) && (Dor(fdc) & (MOTEN(unit)))) {
18627c478bd9Sstevel@tonic-gate 		/* LINTED */
18637c478bd9Sstevel@tonic-gate 		Set_dor(fdc, MOTEN(unit), 0);
18647c478bd9Sstevel@tonic-gate 	}
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
18677c478bd9Sstevel@tonic-gate }
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate /* ARGSUSED */
18707c478bd9Sstevel@tonic-gate static int
18717c478bd9Sstevel@tonic-gate fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
18727c478bd9Sstevel@tonic-gate 	cred_t *cred_p, int *rval_p)
18737c478bd9Sstevel@tonic-gate {
18747c478bd9Sstevel@tonic-gate 	union {
18757c478bd9Sstevel@tonic-gate 		struct dk_cinfo dki;
18767c478bd9Sstevel@tonic-gate 		struct dk_geom dkg;
18777c478bd9Sstevel@tonic-gate 		struct dk_allmap32 dka;
18787c478bd9Sstevel@tonic-gate 		struct fd_char fdchar;
18797c478bd9Sstevel@tonic-gate 		struct fd_drive drvchar;
18807c478bd9Sstevel@tonic-gate 		int	temp;
18817c478bd9Sstevel@tonic-gate 	} cpy;
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	struct vtoc	vtoc;
18847c478bd9Sstevel@tonic-gate 	struct fdunit *un;
18857c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc;
18867c478bd9Sstevel@tonic-gate 	int unit, dkunit;
18877c478bd9Sstevel@tonic-gate 	int err = 0;
18887c478bd9Sstevel@tonic-gate 	uint_t	sec_size;
18897c478bd9Sstevel@tonic-gate 	enum dkio_state state;
18907c478bd9Sstevel@tonic-gate 	int	transfer_rate;
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
18937c478bd9Sstevel@tonic-gate 	    (C, "fd_ioctl: cmd 0x%x, arg 0x%lx\n", cmd, (long)arg));
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	/* The minor number should always be 0 */
18967c478bd9Sstevel@tonic-gate 	if (FDUNIT(dev) != 0)
18977c478bd9Sstevel@tonic-gate 		return (ENXIO);
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
19007c478bd9Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
19017c478bd9Sstevel@tonic-gate 	un = fdc->c_un;
19027c478bd9Sstevel@tonic-gate 	sec_size = un->un_chars->fdc_sec_size;
19037c478bd9Sstevel@tonic-gate 	bzero(&cpy, sizeof (cpy));
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	switch (cmd) {
19067c478bd9Sstevel@tonic-gate 	case DKIOCINFO:
19077c478bd9Sstevel@tonic-gate 		cpy.dki.dki_addr = 0;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 		/*
19107c478bd9Sstevel@tonic-gate 		 * The meaning of the dki_slave and dki_unit fields
19117c478bd9Sstevel@tonic-gate 		 * is unclear.  The sparc floppy driver follows the same
19127c478bd9Sstevel@tonic-gate 		 * convention as sd.c in that the instance number is
19137c478bd9Sstevel@tonic-gate 		 * returned in the dki_cnum field.  The dki_slave field is
19147c478bd9Sstevel@tonic-gate 		 * ignored.
19157c478bd9Sstevel@tonic-gate 		 *
19167c478bd9Sstevel@tonic-gate 		 * The dki_cnum contains the controller instance
19177c478bd9Sstevel@tonic-gate 		 * and its value can be any positive number. Even
19187c478bd9Sstevel@tonic-gate 		 * though currently Sparc platforms only support
19197c478bd9Sstevel@tonic-gate 		 * one controller, the controller instance number
19207c478bd9Sstevel@tonic-gate 		 * can be any number since it is assigned by the
19217c478bd9Sstevel@tonic-gate 		 * system depending on the device properties.
19227c478bd9Sstevel@tonic-gate 		 */
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 		cpy.dki.dki_cnum = FDCTLR(dev);
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 		/*
19277c478bd9Sstevel@tonic-gate 		 * Sparc platforms support only one floppy drive.
19287c478bd9Sstevel@tonic-gate 		 * The device node for the controller is the same as
19297c478bd9Sstevel@tonic-gate 		 * the device node for the drive.  The x86 driver is
19307c478bd9Sstevel@tonic-gate 		 * different in that it has a node for the controller
19317c478bd9Sstevel@tonic-gate 		 * and a child node for each drive. Since Sparc supports
19327c478bd9Sstevel@tonic-gate 		 * only one drive, the unit number will always be zero.
19337c478bd9Sstevel@tonic-gate 		 */
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 		cpy.dki.dki_unit = FDUNIT(dev);
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 		/*
19387c478bd9Sstevel@tonic-gate 		 * The meaning of the dki_slave field is unclear.
19397c478bd9Sstevel@tonic-gate 		 * So, I will leave it set to 0.
19407c478bd9Sstevel@tonic-gate 		 */
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 		cpy.dki.dki_slave = 0;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 		cpy.dki.dki_ctype = (ushort_t)-1;
19457c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_82077)
19467c478bd9Sstevel@tonic-gate 			cpy.dki.dki_ctype = DKC_INTEL82077;
19477c478bd9Sstevel@tonic-gate 		cpy.dki.dki_flags = DKI_FMTTRK;
19487c478bd9Sstevel@tonic-gate 		cpy.dki.dki_partition = FDPARTITION(dev);
19497c478bd9Sstevel@tonic-gate 		cpy.dki.dki_maxtransfer = maxphys / DEV_BSIZE;
19507c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.dki, (caddr_t)arg,
19517c478bd9Sstevel@tonic-gate 		    sizeof (cpy.dki), flag))
19527c478bd9Sstevel@tonic-gate 			err = EFAULT;
19537c478bd9Sstevel@tonic-gate 		break;
19547c478bd9Sstevel@tonic-gate 	case DKIOCGGEOM:
19557c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_ncyl = un->un_chars->fdc_ncyl;
19567c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_nhead = un->un_chars->fdc_nhead;
19577c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_nsect = un->un_chars->fdc_secptrack;
19587c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_intrlv = un->un_label.dkl_intrlv;
19597c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_rpm = un->un_label.dkl_rpm;
19607c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_pcyl = un->un_chars->fdc_ncyl;
19617c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_read_reinstruct =
19627c478bd9Sstevel@tonic-gate 		    (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
19637c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
19647c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.dkg, (caddr_t)arg,
19657c478bd9Sstevel@tonic-gate 		    sizeof (cpy.dkg), flag))
19667c478bd9Sstevel@tonic-gate 			err = EFAULT;
19677c478bd9Sstevel@tonic-gate 		break;
19687c478bd9Sstevel@tonic-gate 	case DKIOCSGEOM:
19697c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
19707c478bd9Sstevel@tonic-gate 		    (C, "fd_ioctl: DKIOCSGEOM not supported\n"));
19717c478bd9Sstevel@tonic-gate 		err = ENOTTY;
19727c478bd9Sstevel@tonic-gate 		break;
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	/*
19757c478bd9Sstevel@tonic-gate 	 * return the map of all logical partitions
19767c478bd9Sstevel@tonic-gate 	 */
19777c478bd9Sstevel@tonic-gate 	case DKIOCGAPART:
19787c478bd9Sstevel@tonic-gate 		/*
19797c478bd9Sstevel@tonic-gate 		 * We don't have anything to do if the application is ILP32
19807c478bd9Sstevel@tonic-gate 		 * because the label map has a 32-bit format. Otherwise
19817c478bd9Sstevel@tonic-gate 		 * convert.
19827c478bd9Sstevel@tonic-gate 		 */
19837c478bd9Sstevel@tonic-gate 		if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
19847c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&un->un_label.dkl_map,
19857c478bd9Sstevel@tonic-gate 			    (void *)arg, sizeof (struct dk_allmap32), flag))
19867c478bd9Sstevel@tonic-gate 				err = EFAULT;
19877c478bd9Sstevel@tonic-gate 		}
19887c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
19897c478bd9Sstevel@tonic-gate 		else {
19907c478bd9Sstevel@tonic-gate 			struct dk_allmap dk_allmap;
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 			ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
19937c478bd9Sstevel@tonic-gate 			for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
19947c478bd9Sstevel@tonic-gate 				dk_allmap.dka_map[dkunit].dkl_cylno =
19957c478bd9Sstevel@tonic-gate 				    un->un_label.dkl_map[dkunit].dkl_cylno;
19967c478bd9Sstevel@tonic-gate 				dk_allmap.dka_map[dkunit].dkl_nblk =
19977c478bd9Sstevel@tonic-gate 				    un->un_label.dkl_map[dkunit].dkl_nblk;
19987c478bd9Sstevel@tonic-gate 			}
19997c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&dk_allmap, (void *)arg,
20007c478bd9Sstevel@tonic-gate 			    sizeof (struct dk_allmap), flag))
20017c478bd9Sstevel@tonic-gate 				err = EFAULT;
20027c478bd9Sstevel@tonic-gate 		}
20037c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20047c478bd9Sstevel@tonic-gate 		break;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	/*
20077c478bd9Sstevel@tonic-gate 	 * Set the map of all logical partitions
20087c478bd9Sstevel@tonic-gate 	 */
20097c478bd9Sstevel@tonic-gate 	case DKIOCSAPART:
20107c478bd9Sstevel@tonic-gate 		if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
20117c478bd9Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &cpy.dka,
20127c478bd9Sstevel@tonic-gate 			    sizeof (cpy.dka), flag))
20137c478bd9Sstevel@tonic-gate 				return (EFAULT);
20147c478bd9Sstevel@tonic-gate 			else {
20157c478bd9Sstevel@tonic-gate 				mutex_enter(&fdc->c_lolock);
20167c478bd9Sstevel@tonic-gate 				for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
20177c478bd9Sstevel@tonic-gate 					un->un_label.dkl_map[dkunit] =
20187c478bd9Sstevel@tonic-gate 					    cpy.dka.dka_map[dkunit];
20197c478bd9Sstevel@tonic-gate 				}
20207c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
20217c478bd9Sstevel@tonic-gate 			}
20227c478bd9Sstevel@tonic-gate 		}
20237c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20247c478bd9Sstevel@tonic-gate 		else {
20257c478bd9Sstevel@tonic-gate 			struct dk_allmap dk_allmap;
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 			ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
20287c478bd9Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &dk_allmap,
20297c478bd9Sstevel@tonic-gate 			    sizeof (dk_allmap), flag))
20307c478bd9Sstevel@tonic-gate 				return (EFAULT);
20317c478bd9Sstevel@tonic-gate 			else {
20327c478bd9Sstevel@tonic-gate 				mutex_enter(&fdc->c_lolock);
20337c478bd9Sstevel@tonic-gate 				for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
20347c478bd9Sstevel@tonic-gate 					un->un_label.dkl_map[dkunit].dkl_cylno =
20357c478bd9Sstevel@tonic-gate 					    dk_allmap.dka_map[dkunit].dkl_cylno;
20367c478bd9Sstevel@tonic-gate 					un->un_label.dkl_map[dkunit].dkl_nblk =
20377c478bd9Sstevel@tonic-gate 					    dk_allmap.dka_map[dkunit].dkl_nblk;
20387c478bd9Sstevel@tonic-gate 				}
20397c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
20407c478bd9Sstevel@tonic-gate 			}
20417c478bd9Sstevel@tonic-gate 		}
20427c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20437c478bd9Sstevel@tonic-gate 		break;
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	case DKIOCGVTOC:
20467c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 		/*
20497c478bd9Sstevel@tonic-gate 		 * Exit if the diskette has no label.
20507c478bd9Sstevel@tonic-gate 		 * Also, get the label to make sure the
20517c478bd9Sstevel@tonic-gate 		 * correct one is being used since the diskette
20527c478bd9Sstevel@tonic-gate 		 * may have changed
20537c478bd9Sstevel@tonic-gate 		 */
20547c478bd9Sstevel@tonic-gate 		if (fdgetlabel(fdc, unit)) {
20557c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
20567c478bd9Sstevel@tonic-gate 			err = EINVAL;
20577c478bd9Sstevel@tonic-gate 			break;
20587c478bd9Sstevel@tonic-gate 		}
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 		/* Build a vtoc from the diskette's label */
20617c478bd9Sstevel@tonic-gate 		fd_build_user_vtoc(un, &vtoc);
20627c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20657c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
20667c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
20677c478bd9Sstevel@tonic-gate 			struct vtoc32 vtoc32;
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 			vtoctovtoc32(vtoc, vtoc32);
20707c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&vtoc32, (void *)arg,
20717c478bd9Sstevel@tonic-gate 			    sizeof (struct vtoc32), flag))
20727c478bd9Sstevel@tonic-gate 				return (EFAULT);
20737c478bd9Sstevel@tonic-gate 			break;
20747c478bd9Sstevel@tonic-gate 		}
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
20777c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&vtoc, (void *)arg,
20787c478bd9Sstevel@tonic-gate 			    sizeof (vtoc), flag))
20797c478bd9Sstevel@tonic-gate 				return (EFAULT);
20807c478bd9Sstevel@tonic-gate 			break;
20817c478bd9Sstevel@tonic-gate 		}
20827c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */
20837c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&vtoc, (void *)arg, sizeof (vtoc), flag))
20847c478bd9Sstevel@tonic-gate 			return (EFAULT);
20857c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20867c478bd9Sstevel@tonic-gate 		break;
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 	case DKIOCSVTOC:
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20917c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
20927c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
20937c478bd9Sstevel@tonic-gate 			struct vtoc32 vtoc32;
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &vtoc32,
20967c478bd9Sstevel@tonic-gate 			    sizeof (struct vtoc32), flag)) {
20977c478bd9Sstevel@tonic-gate 				return (EFAULT);
20987c478bd9Sstevel@tonic-gate 			}
20997c478bd9Sstevel@tonic-gate 			vtoc32tovtoc(vtoc32, vtoc);
21007c478bd9Sstevel@tonic-gate 			break;
21017c478bd9Sstevel@tonic-gate 		}
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
21047c478bd9Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &vtoc,
21057c478bd9Sstevel@tonic-gate 			    sizeof (vtoc), flag)) {
21067c478bd9Sstevel@tonic-gate 				return (EFAULT);
21077c478bd9Sstevel@tonic-gate 			}
21087c478bd9Sstevel@tonic-gate 			break;
21097c478bd9Sstevel@tonic-gate 		}
21107c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */
21117c478bd9Sstevel@tonic-gate 		if (ddi_copyin((const void *)arg, &vtoc, sizeof (vtoc), flag))
21127c478bd9Sstevel@tonic-gate 			return (EFAULT);
21137c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 		/*
21187c478bd9Sstevel@tonic-gate 		 * The characteristics structure must be filled in because
21197c478bd9Sstevel@tonic-gate 		 * it helps build the vtoc.
21207c478bd9Sstevel@tonic-gate 		 */
21217c478bd9Sstevel@tonic-gate 		if ((un->un_chars->fdc_ncyl == 0) ||
21227c478bd9Sstevel@tonic-gate 		    (un->un_chars->fdc_nhead == 0) ||
21237c478bd9Sstevel@tonic-gate 		    (un->un_chars->fdc_secptrack == 0)) {
21247c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
21257c478bd9Sstevel@tonic-gate 			err = EINVAL;
21267c478bd9Sstevel@tonic-gate 			break;
21277c478bd9Sstevel@tonic-gate 		}
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate 		if ((err = fd_build_label_vtoc(un, &vtoc)) != 0) {
21307c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
21317c478bd9Sstevel@tonic-gate 			break;
21327c478bd9Sstevel@tonic-gate 		}
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 		err = fdrw(fdc, unit, FDWRITE, 0, 0, 1,
21377c478bd9Sstevel@tonic-gate 		    (caddr_t)&un->un_label, sizeof (struct dk_label));
21387c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
21397c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
21407c478bd9Sstevel@tonic-gate 		break;
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate 	case DKIOCSTATE:
21437c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&state,
21447c478bd9Sstevel@tonic-gate 		    sizeof (int), flag)) {
21457c478bd9Sstevel@tonic-gate 			err = EFAULT;
21467c478bd9Sstevel@tonic-gate 			break;
21477c478bd9Sstevel@tonic-gate 		}
21487c478bd9Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 		err = fd_check_media(dev, state);
21517c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&un->un_media_state,
21547c478bd9Sstevel@tonic-gate 		    (caddr_t)arg, sizeof (int), flag))
21557c478bd9Sstevel@tonic-gate 			err = EFAULT;
21567c478bd9Sstevel@tonic-gate 		break;
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate 	case FDIOGCHAR:
21597c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)un->un_chars, (caddr_t)arg,
21607c478bd9Sstevel@tonic-gate 		    sizeof (struct fd_char), flag))
21617c478bd9Sstevel@tonic-gate 			err = EFAULT;
21627c478bd9Sstevel@tonic-gate 		break;
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	case FDIOSCHAR:
21657c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.fdchar,
21667c478bd9Sstevel@tonic-gate 				sizeof (struct fd_char), flag)) {
21677c478bd9Sstevel@tonic-gate 			err = EFAULT;
21687c478bd9Sstevel@tonic-gate 			break;
21697c478bd9Sstevel@tonic-gate 		}
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 		/*
21727c478bd9Sstevel@tonic-gate 		 * Check the fields in the fdchar structure that are either
21737c478bd9Sstevel@tonic-gate 		 * driver or controller dependent.
21747c478bd9Sstevel@tonic-gate 		 */
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 		transfer_rate = cpy.fdchar.fdc_transfer_rate;
21777c478bd9Sstevel@tonic-gate 		if ((transfer_rate != 500) && (transfer_rate != 300) &&
21787c478bd9Sstevel@tonic-gate 		    (transfer_rate != 250) && (transfer_rate != 1000)) {
21797c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
21807c478bd9Sstevel@tonic-gate 			    (C, "fd_ioctl: FDIOSCHAR odd transfer rate %d\n",
21817c478bd9Sstevel@tonic-gate 			    cpy.fdchar.fdc_transfer_rate));
21827c478bd9Sstevel@tonic-gate 			err = EINVAL;
21837c478bd9Sstevel@tonic-gate 			break;
21847c478bd9Sstevel@tonic-gate 		}
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 		if ((cpy.fdchar.fdc_nhead < 1) ||
21877c478bd9Sstevel@tonic-gate 		    (cpy.fdchar.fdc_nhead > 2)) {
21887c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
21897c478bd9Sstevel@tonic-gate 			    (C, "fd_ioctl: FDIOSCHAR bad no. of heads %d\n",
21907c478bd9Sstevel@tonic-gate 			    cpy.fdchar.fdc_nhead));
21917c478bd9Sstevel@tonic-gate 			err = EINVAL;
21927c478bd9Sstevel@tonic-gate 			break;
21937c478bd9Sstevel@tonic-gate 		}
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 		/*
21967c478bd9Sstevel@tonic-gate 		 * The number of cylinders must be between 0 and 255
21977c478bd9Sstevel@tonic-gate 		 */
21987c478bd9Sstevel@tonic-gate 		if ((cpy.fdchar.fdc_ncyl < 0) || (cpy.fdchar.fdc_ncyl > 255)) {
21997c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
22007c478bd9Sstevel@tonic-gate 			    (C, "fd_ioctl: FDIOSCHAR bad cyl no %d\n",
22017c478bd9Sstevel@tonic-gate 			    cpy.fdchar.fdc_ncyl));
22027c478bd9Sstevel@tonic-gate 			err = EINVAL;
22037c478bd9Sstevel@tonic-gate 			break;
22047c478bd9Sstevel@tonic-gate 		}
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 		/* Copy the fdchar structure */
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
22097c478bd9Sstevel@tonic-gate 		*(un->un_chars) = cpy.fdchar;
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 		un->un_curfdtype = -1;
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 		break;
22167c478bd9Sstevel@tonic-gate 	case FDEJECT:  /* eject disk */
22177c478bd9Sstevel@tonic-gate 	case DKIOCEJECT:
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate 		/*
22207c478bd9Sstevel@tonic-gate 		 * Fail the ioctl if auto-eject isn't supported
22217c478bd9Sstevel@tonic-gate 		 */
22227c478bd9Sstevel@tonic-gate 		if (fdc->c_un->un_drive->fdd_ejectable == 0) {
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 			err = ENOSYS;
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 		} else {
22277c478bd9Sstevel@tonic-gate 			(void) pm_busy_component(fdc->c_dip, 0);
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 			CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate 			if (fdc->c_un->un_state == FD_STATE_STOPPED) {
22347c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
22357c478bd9Sstevel@tonic-gate 				if ((pm_raise_power(fdc->c_dip, 0,
22367c478bd9Sstevel@tonic-gate 				    PM_LEVEL_ON)) != DDI_SUCCESS) {
22377c478bd9Sstevel@tonic-gate 					(void) pm_idle_component(fdc->c_dip, 0);
22387c478bd9Sstevel@tonic-gate 					err = EIO;
22397c478bd9Sstevel@tonic-gate 				}
22407c478bd9Sstevel@tonic-gate 				mutex_enter(&fdc->c_lolock);
22417c478bd9Sstevel@tonic-gate 			}
22427c478bd9Sstevel@tonic-gate 		}
22437c478bd9Sstevel@tonic-gate 		if (err == 0) {
22447c478bd9Sstevel@tonic-gate 			fdselect(fdc, unit, 1);
22457c478bd9Sstevel@tonic-gate 			fdeject(fdc, unit);
22467c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
22477c478bd9Sstevel@tonic-gate 		}
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 		/*
22527c478bd9Sstevel@tonic-gate 		 * Make sure the drive is turned off
22537c478bd9Sstevel@tonic-gate 		 */
22547c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_82077) {
22557c478bd9Sstevel@tonic-gate 			if (fdc->c_mtimeid == 0) {
22567c478bd9Sstevel@tonic-gate 				fdc->c_mtimeid = timeout(fdmotoff, fdc,
22577c478bd9Sstevel@tonic-gate 				    Motoff_delay);
22587c478bd9Sstevel@tonic-gate 			}
22597c478bd9Sstevel@tonic-gate 		}
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 		break;
22627c478bd9Sstevel@tonic-gate 	case FDGETCHANGE: /* disk changed */
22637c478bd9Sstevel@tonic-gate 
22647c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.temp,
22657c478bd9Sstevel@tonic-gate 		    sizeof (int), flag)) {
22667c478bd9Sstevel@tonic-gate 			err = EFAULT;
22677c478bd9Sstevel@tonic-gate 			break;
22687c478bd9Sstevel@tonic-gate 		}
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 		/* zero out the user's parameter */
22717c478bd9Sstevel@tonic-gate 		cpy.temp = 0;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 		CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate 		if (fdc->c_un->un_state == FD_STATE_STOPPED) {
22807c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
22817c478bd9Sstevel@tonic-gate 			if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
22827c478bd9Sstevel@tonic-gate 			    != DDI_SUCCESS) {
22837c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
22847c478bd9Sstevel@tonic-gate 				    change failed. \n"));
22857c478bd9Sstevel@tonic-gate 				(void) pm_idle_component(fdc->c_dip, 0);
22867c478bd9Sstevel@tonic-gate 				return (EIO);
22877c478bd9Sstevel@tonic-gate 			}
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
22907c478bd9Sstevel@tonic-gate 		}
22917c478bd9Sstevel@tonic-gate 		if (un->un_flags & FDUNIT_CHANGED)
22927c478bd9Sstevel@tonic-gate 			cpy.temp |= FDGC_HISTORY;
22937c478bd9Sstevel@tonic-gate 		else
22947c478bd9Sstevel@tonic-gate 			cpy.temp &= ~FDGC_HISTORY;
22957c478bd9Sstevel@tonic-gate 		un->un_flags &= ~FDUNIT_CHANGED;
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 		if (fd_pollable) {
22987c478bd9Sstevel@tonic-gate 			/*
22997c478bd9Sstevel@tonic-gate 			 * If it's a "pollable" floppy, then we don't
23007c478bd9Sstevel@tonic-gate 			 * have to do all the fdcheckdisk nastyness to
23017c478bd9Sstevel@tonic-gate 			 * figure out if the thing is still there.
23027c478bd9Sstevel@tonic-gate 			 */
23037c478bd9Sstevel@tonic-gate 			if (fdsense_chng(fdc, unit)) {
23047c478bd9Sstevel@tonic-gate 				cpy.temp |= FDGC_CURRENT;
23057c478bd9Sstevel@tonic-gate 			} else {
23067c478bd9Sstevel@tonic-gate 				cpy.temp &= ~FDGC_CURRENT;
23077c478bd9Sstevel@tonic-gate 			}
23087c478bd9Sstevel@tonic-gate 		} else {
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 			if (fdsense_chng(fdc, unit)) {
23117c478bd9Sstevel@tonic-gate 				/*
23127c478bd9Sstevel@tonic-gate 				 * check disk change signal is asserted.
23137c478bd9Sstevel@tonic-gate 				 * Now find out if the floppy is
23147c478bd9Sstevel@tonic-gate 				 * inserted
23157c478bd9Sstevel@tonic-gate 				 */
23167c478bd9Sstevel@tonic-gate 				if (fdcheckdisk(fdc, unit)) {
23177c478bd9Sstevel@tonic-gate 					cpy.temp |= FDGC_CURRENT;
23187c478bd9Sstevel@tonic-gate 				} else {
23197c478bd9Sstevel@tonic-gate 					/*
23207c478bd9Sstevel@tonic-gate 					 * Yes, the floppy was
23217c478bd9Sstevel@tonic-gate 					 * reinserted. Implies
23227c478bd9Sstevel@tonic-gate 					 * floppy change.
23237c478bd9Sstevel@tonic-gate 					 */
23247c478bd9Sstevel@tonic-gate 					cpy.temp &= ~FDGC_CURRENT;
23257c478bd9Sstevel@tonic-gate 					cpy.temp |= FDGC_HISTORY;
23267c478bd9Sstevel@tonic-gate 				}
23277c478bd9Sstevel@tonic-gate 			} else {
23287c478bd9Sstevel@tonic-gate 				cpy.temp &= ~FDGC_CURRENT;
23297c478bd9Sstevel@tonic-gate 			}
23307c478bd9Sstevel@tonic-gate 		}
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 		/*
23337c478bd9Sstevel@tonic-gate 		 * For a pollable floppy, the floppy_change signal
23347c478bd9Sstevel@tonic-gate 		 * reflects whether the floppy is in there or not.
23357c478bd9Sstevel@tonic-gate 		 * We can not detect a floppy change if we don't poll
23367c478bd9Sstevel@tonic-gate 		 * this signal when the floppy is being changed.
23377c478bd9Sstevel@tonic-gate 		 * Because as soon as the floppy is put back, the
23387c478bd9Sstevel@tonic-gate 		 * signal is reset.
23397c478bd9Sstevel@tonic-gate 		 * BUT the pollable floppies are available only on
23407c478bd9Sstevel@tonic-gate 		 * Sparcstation Voyager Voyagers (Gypsy) only and
23417c478bd9Sstevel@tonic-gate 		 * those are motorized floppies. For motorized floppies,
23427c478bd9Sstevel@tonic-gate 		 * the floppy can only (assuming the user doesn't use a
23437c478bd9Sstevel@tonic-gate 		 * pin to take out the floppy) be taken out by
23447c478bd9Sstevel@tonic-gate 		 * issuing 'eject' command which sets the
23457c478bd9Sstevel@tonic-gate 		 * un->un_ejected flag. So, if the following
23467c478bd9Sstevel@tonic-gate 		 * condition is true, we can assume there
23477c478bd9Sstevel@tonic-gate 		 * was a floppy change.
23487c478bd9Sstevel@tonic-gate 		 */
23497c478bd9Sstevel@tonic-gate 		if (un->un_ejected && !(cpy.temp & FDGC_CURRENT)) {
23507c478bd9Sstevel@tonic-gate 			cpy.temp |= FDGC_HISTORY;
23517c478bd9Sstevel@tonic-gate 		}
23527c478bd9Sstevel@tonic-gate 		un->un_ejected = 0;
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 		/* return the write-protection status */
23567c478bd9Sstevel@tonic-gate 		fdgetcsb(fdc);
23577c478bd9Sstevel@tonic-gate 		if (fdsensedrv(fdc, unit) & WP_SR3) {
23587c478bd9Sstevel@tonic-gate 			cpy.temp |= FDGC_CURWPROT;
23597c478bd9Sstevel@tonic-gate 		}
23607c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
23617c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.temp, (caddr_t)arg,
23647c478bd9Sstevel@tonic-gate 		    sizeof (int), flag))
23657c478bd9Sstevel@tonic-gate 			err = EFAULT;
23667c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
23677c478bd9Sstevel@tonic-gate 		break;
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 	case FDGETDRIVECHAR:
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.drvchar,
23727c478bd9Sstevel@tonic-gate 				sizeof (struct fd_drive), flag)) {
23737c478bd9Sstevel@tonic-gate 			err = EFAULT;
23747c478bd9Sstevel@tonic-gate 			break;
23757c478bd9Sstevel@tonic-gate 		}
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate 		/*
23787c478bd9Sstevel@tonic-gate 		 * Return the ejectable value based on the FD_MANUAL_EJECT
23797c478bd9Sstevel@tonic-gate 		 * property
23807c478bd9Sstevel@tonic-gate 		 */
23817c478bd9Sstevel@tonic-gate 		cpy.drvchar.fdd_ejectable = fdc->c_un->un_drive->fdd_ejectable;
23827c478bd9Sstevel@tonic-gate 		cpy.drvchar.fdd_maxsearch = nfdtypes; /* 3 - hi m lo density */
23837c478bd9Sstevel@tonic-gate 		if (fd_pollable)	/* pollable device */
23847c478bd9Sstevel@tonic-gate 			cpy.drvchar.fdd_flags |= FDD_POLLABLE;
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 		/* the rest of the fd_drive struct is meaningless to us */
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&cpy.drvchar, (caddr_t)arg,
23897c478bd9Sstevel@tonic-gate 		    sizeof (struct fd_drive), flag))
23907c478bd9Sstevel@tonic-gate 			err = EFAULT;
23917c478bd9Sstevel@tonic-gate 		break;
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 	case FDSETDRIVECHAR:
23947c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
23957c478bd9Sstevel@tonic-gate 		    (C, "fd_ioctl: FDSETDRIVECHAR not supportedn\n"));
23967c478bd9Sstevel@tonic-gate 		err = ENOTTY;
23977c478bd9Sstevel@tonic-gate 		break;
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	case DKIOCREMOVABLE: {
24007c478bd9Sstevel@tonic-gate 		int	i = 1;
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 		/* no brainer: floppies are always removable */
24037c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&i, (caddr_t)arg, sizeof (int),
24047c478bd9Sstevel@tonic-gate 		    flag)) {
24057c478bd9Sstevel@tonic-gate 			err = EFAULT;
24067c478bd9Sstevel@tonic-gate 		}
24077c478bd9Sstevel@tonic-gate 		break;
24087c478bd9Sstevel@tonic-gate 	}
24097c478bd9Sstevel@tonic-gate 	case DKIOCGMEDIAINFO:
24107c478bd9Sstevel@tonic-gate 		err = fd_get_media_info(un, (caddr_t)arg, flag);
24117c478bd9Sstevel@tonic-gate 		break;
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	case FDIOCMD:
24157c478bd9Sstevel@tonic-gate 	{
24167c478bd9Sstevel@tonic-gate 		struct fd_cmd fc;
24177c478bd9Sstevel@tonic-gate 		int cyl, hd, spc, spt;
24187c478bd9Sstevel@tonic-gate 		int nblks; /* total no. of blocks */
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
24217c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
24227c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32: {
24237c478bd9Sstevel@tonic-gate 			struct fd_cmd32 fc32;
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &fc32,
24267c478bd9Sstevel@tonic-gate 			    sizeof (fc32), flag)) {
24277c478bd9Sstevel@tonic-gate 				return (EFAULT);
24287c478bd9Sstevel@tonic-gate 			}
24297c478bd9Sstevel@tonic-gate 			fc.fdc_cmd	= fc32.fdc_cmd;
24307c478bd9Sstevel@tonic-gate 			fc.fdc_flags	= fc32.fdc_flags;
24317c478bd9Sstevel@tonic-gate 			fc.fdc_blkno	= (daddr_t)fc32.fdc_blkno;
24327c478bd9Sstevel@tonic-gate 			fc.fdc_secnt	= fc32.fdc_secnt;
243329df58e5Spc157239 			fc.fdc_bufaddr	= (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
24347c478bd9Sstevel@tonic-gate 			fc.fdc_buflen	= fc32.fdc_buflen;
24357c478bd9Sstevel@tonic-gate 			fc.fdc_cmd	= fc32.fdc_cmd;
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 			break;
24387c478bd9Sstevel@tonic-gate 		}
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
24417c478bd9Sstevel@tonic-gate 			if (ddi_copyin((const void *)arg, &fc,
24427c478bd9Sstevel@tonic-gate 			    sizeof (fc), flag)) {
24437c478bd9Sstevel@tonic-gate 				return (EFAULT);
24447c478bd9Sstevel@tonic-gate 			}
24457c478bd9Sstevel@tonic-gate 			break;
24467c478bd9Sstevel@tonic-gate 		}
24477c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */
24487c478bd9Sstevel@tonic-gate 		if (ddi_copyin((const void *)arg, &fc, sizeof (fc), flag)) {
24497c478bd9Sstevel@tonic-gate 			return (EFAULT);
24507c478bd9Sstevel@tonic-gate 		}
24517c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
24527c478bd9Sstevel@tonic-gate 
24537c478bd9Sstevel@tonic-gate 		if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
24547c478bd9Sstevel@tonic-gate 			auto struct iovec aiov;
24557c478bd9Sstevel@tonic-gate 			auto struct uio auio;
24567c478bd9Sstevel@tonic-gate 			struct uio *uio = &auio;
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 			spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate 			bzero(&auio, sizeof (struct uio));
24617c478bd9Sstevel@tonic-gate 			bzero(&aiov, sizeof (struct iovec));
24627c478bd9Sstevel@tonic-gate 			aiov.iov_base = fc.fdc_bufaddr;
24637c478bd9Sstevel@tonic-gate 			aiov.iov_len = (uint_t)fc.fdc_secnt * sec_size;
24647c478bd9Sstevel@tonic-gate 			uio->uio_iov = &aiov;
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate 			uio->uio_iovcnt = 1;
24677c478bd9Sstevel@tonic-gate 			uio->uio_resid = aiov.iov_len;
24687c478bd9Sstevel@tonic-gate 			uio->uio_segflg = UIO_USERSPACE;
24697c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L2, FDEM_IOCT,
24707c478bd9Sstevel@tonic-gate 			    (C, "fd_ioctl: call physio\n"));
24717c478bd9Sstevel@tonic-gate 			err = physio(fd_strategy, NULL, dev,
24727c478bd9Sstevel@tonic-gate 			    spc, minphys, uio);
24737c478bd9Sstevel@tonic-gate 			break;
24747c478bd9Sstevel@tonic-gate 		} else if (fc.fdc_cmd != FDCMD_FORMAT_TRACK) {
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 			/*
24777c478bd9Sstevel@tonic-gate 			 * The manpage states that only the FDCMD_WRITE,
24787c478bd9Sstevel@tonic-gate 			 * FDCMD_READ, and the FDCMD_FORMAT_TR are available.
24797c478bd9Sstevel@tonic-gate 			 */
24807c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_IOCT,
24817c478bd9Sstevel@tonic-gate 			    (C, "fd_ioctl: FDIOCMD invalid command\n"));
24827c478bd9Sstevel@tonic-gate 			err = EINVAL;
24837c478bd9Sstevel@tonic-gate 			break;
24847c478bd9Sstevel@tonic-gate 		}
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 		/* The command is FDCMD_FORMAT_TRACK */
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate 		spt = un->un_chars->fdc_secptrack;	/* sec/trk */
24897c478bd9Sstevel@tonic-gate 		spc = un->un_chars->fdc_nhead * spt;	/* sec/cyl */
24907c478bd9Sstevel@tonic-gate 		cyl = fc.fdc_blkno / spc;
24917c478bd9Sstevel@tonic-gate 		hd = (fc.fdc_blkno % spc) / spt;
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate 		/*
24947c478bd9Sstevel@tonic-gate 		 * Make sure the specified block number is in the correct
24957c478bd9Sstevel@tonic-gate 		 * range. (block numbers start at 0)
24967c478bd9Sstevel@tonic-gate 		 */
24977c478bd9Sstevel@tonic-gate 		nblks = spc * un->un_chars->fdc_ncyl;
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 		if (fc.fdc_blkno < 0 || fc.fdc_blkno > (nblks - 1)) {
25007c478bd9Sstevel@tonic-gate 			err = EINVAL;
25017c478bd9Sstevel@tonic-gate 			break;
25027c478bd9Sstevel@tonic-gate 		}
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
25077c478bd9Sstevel@tonic-gate 		CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
25087c478bd9Sstevel@tonic-gate 		if (fdc->c_un->un_state == FD_STATE_STOPPED) {
25097c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
25107c478bd9Sstevel@tonic-gate 			if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
25117c478bd9Sstevel@tonic-gate 			    != DDI_SUCCESS) {
25127c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
25137c478bd9Sstevel@tonic-gate 				    change failed. \n"));
25147c478bd9Sstevel@tonic-gate 				(void) pm_idle_component(fdc->c_dip, 0);
25157c478bd9Sstevel@tonic-gate 				return (EIO);
25167c478bd9Sstevel@tonic-gate 			}
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
25197c478bd9Sstevel@tonic-gate 		}
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 		if (fdformat(fdc, unit, cyl, hd))
25227c478bd9Sstevel@tonic-gate 			err = EIO;
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
25257c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 		break;
25287c478bd9Sstevel@tonic-gate 	}
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 	case FDRAW:
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate 		(void) pm_busy_component(fdc->c_dip, 0);
25337c478bd9Sstevel@tonic-gate 		err = fdrawioctl(fdc, unit, arg, flag);
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(fdc->c_dip, 0);
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 		break;
25387c478bd9Sstevel@tonic-gate #ifdef FD_DEBUG
25397c478bd9Sstevel@tonic-gate 	case IOCTL_DEBUG:
25407c478bd9Sstevel@tonic-gate 		fderrlevel--;
25417c478bd9Sstevel@tonic-gate 		if (fderrlevel < 0)
25427c478bd9Sstevel@tonic-gate 			fderrlevel = 3;
25437c478bd9Sstevel@tonic-gate 		cmn_err(C, "fdioctl: CHANGING debug to %d", fderrlevel);
25447c478bd9Sstevel@tonic-gate 		return (0);
25457c478bd9Sstevel@tonic-gate #endif /* FD_DEBUG */
25467c478bd9Sstevel@tonic-gate 	default:
25477c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_IOCT,
25487c478bd9Sstevel@tonic-gate 		    (C, "fd_ioctl: invalid ioctl 0x%x\n", cmd));
25497c478bd9Sstevel@tonic-gate 		err = ENOTTY;
25507c478bd9Sstevel@tonic-gate 		break;
25517c478bd9Sstevel@tonic-gate 	}
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 	return (err);
25547c478bd9Sstevel@tonic-gate }
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate /*
25577c478bd9Sstevel@tonic-gate  * fdrawioctl
25587c478bd9Sstevel@tonic-gate  *
25597c478bd9Sstevel@tonic-gate  * 	- acquires the low level lock
25607c478bd9Sstevel@tonic-gate  */
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate static int
25637c478bd9Sstevel@tonic-gate fdrawioctl(struct fdctlr *fdc, int unit, intptr_t arg, int mode)
25647c478bd9Sstevel@tonic-gate {
25657c478bd9Sstevel@tonic-gate 	struct fd_raw fdr;
25667c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
25677c478bd9Sstevel@tonic-gate 	struct fd_raw32 fdr32;
25687c478bd9Sstevel@tonic-gate #endif
25697c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
25707c478bd9Sstevel@tonic-gate 	int i, err, flag;
25717c478bd9Sstevel@tonic-gate 	caddr_t fa;
25727c478bd9Sstevel@tonic-gate 	uint_t	fc;
25737c478bd9Sstevel@tonic-gate 	size_t	real_length;
25747c478bd9Sstevel@tonic-gate 	int	res;
25757c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
25767c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	mem_handle;
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
25797c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
25807c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 	flag = B_READ;
25857c478bd9Sstevel@tonic-gate 	err = 0;
25867c478bd9Sstevel@tonic-gate 	fa = NULL;
25877c478bd9Sstevel@tonic-gate 	fc = (uint_t)0;
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	/* Copy in the arguments */
25907c478bd9Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode)) {
25917c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
25927c478bd9Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
25937c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr32,
25947c478bd9Sstevel@tonic-gate 		    sizeof (fdr32), mode)) {
25957c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
25967c478bd9Sstevel@tonic-gate 			    (C, "fdrawioctl: copyin error, args32\n"));
25977c478bd9Sstevel@tonic-gate 			return (EFAULT);
25987c478bd9Sstevel@tonic-gate 		}
25997c478bd9Sstevel@tonic-gate 		bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
26007c478bd9Sstevel@tonic-gate 		fdr.fdr_cnum = fdr32.fdr_cnum;
26017c478bd9Sstevel@tonic-gate 		bcopy(fdr32.fdr_result, fdr.fdr_result,
26027c478bd9Sstevel@tonic-gate 		    sizeof (fdr.fdr_result));
26037c478bd9Sstevel@tonic-gate 		fdr.fdr_nbytes = fdr32.fdr_nbytes;
260429df58e5Spc157239 		fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
26057c478bd9Sstevel@tonic-gate 		break;
26067c478bd9Sstevel@tonic-gate #endif
26077c478bd9Sstevel@tonic-gate 	default:
26087c478bd9Sstevel@tonic-gate 	case DDI_MODEL_NONE:
26097c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr,
26107c478bd9Sstevel@tonic-gate 		    sizeof (fdr), mode)) {
26117c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
26127c478bd9Sstevel@tonic-gate 			    (C, "fdrawioctl: copyin error, args\n"));
26137c478bd9Sstevel@tonic-gate 			return (EFAULT);
26147c478bd9Sstevel@tonic-gate 		}
26157c478bd9Sstevel@tonic-gate 		break;
26167c478bd9Sstevel@tonic-gate 	}
26177c478bd9Sstevel@tonic-gate 
2618*427f591eSFred Herard 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
2619*427f591eSFred Herard 	    (C, "fdrawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
2620*427f591eSFred Herard 
26217c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
26267c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
26277c478bd9Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
26287c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
26297c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
26307c478bd9Sstevel@tonic-gate 			    failed. \n"));
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
26337c478bd9Sstevel@tonic-gate 			return (EIO);
26347c478bd9Sstevel@tonic-gate 		}
26357c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
26367c478bd9Sstevel@tonic-gate 	}
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate 	fdgetcsb(fdc);
26397c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
26407c478bd9Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 	/* copy cmd bytes into csb */
26437c478bd9Sstevel@tonic-gate 	for (i = 0; i <= fdr.fdr_cnum; i++)
26447c478bd9Sstevel@tonic-gate 		csb->csb_cmds[i] = fdr.fdr_cmd[i];
26457c478bd9Sstevel@tonic-gate 	csb->csb_ncmds = (uchar_t)fdr.fdr_cnum;
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 	csb->csb_maxretry = 0;	/* let the application deal with errors */
26487c478bd9Sstevel@tonic-gate 	csb->csb_retrys = 0;
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate 	switch (fdr.fdr_cmd[0] & 0x0f) {
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate 	case FDRAW_SPECIFY:
26537c478bd9Sstevel@tonic-gate 		/*
26547c478bd9Sstevel@tonic-gate 		 * Ensure that the right DMA mode is selected.  There is
26557c478bd9Sstevel@tonic-gate 		 * currently no way for the user to tell if DMA is
26567c478bd9Sstevel@tonic-gate 		 * happening so set the value for the user.
26577c478bd9Sstevel@tonic-gate 		 */
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA)
26607c478bd9Sstevel@tonic-gate 			csb->csb_cmds[2] = csb->csb_cmds[2] & 0xFE;
26617c478bd9Sstevel@tonic-gate 		else
26627c478bd9Sstevel@tonic-gate 			csb->csb_cmds[2] = csb->csb_cmds[2] | 0x1;
26637c478bd9Sstevel@tonic-gate 
26647c478bd9Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFNORESULTS;
26657c478bd9Sstevel@tonic-gate 		csb->csb_nrslts = 0;
26667c478bd9Sstevel@tonic-gate 		break;
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	case FDRAW_SENSE_DRV:
26697c478bd9Sstevel@tonic-gate 		/* Insert the appropriate drive number */
26707c478bd9Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
26717c478bd9Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFIMMEDIATE;
26727c478bd9Sstevel@tonic-gate 		csb->csb_nrslts = 1;
26737c478bd9Sstevel@tonic-gate 		break;
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 	case FDRAW_REZERO:
26767c478bd9Sstevel@tonic-gate 	case FDRAW_SEEK:
26777c478bd9Sstevel@tonic-gate 		/* Insert the appropriate drive number */
26787c478bd9Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
26797c478bd9Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFSEEKOPS + CSB_OFTIMEIT;
26807c478bd9Sstevel@tonic-gate 		csb->csb_nrslts = 2;
26817c478bd9Sstevel@tonic-gate 		break;
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate 	case FDRAW_FORMAT:
26847c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RAWI,
26857c478bd9Sstevel@tonic-gate 		    (C, "fdrawioctl: cmd is fdfraw format\n"));
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 		/* Insert the appropriate drive number */
26887c478bd9Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
26897c478bd9Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
26907c478bd9Sstevel@tonic-gate 		csb->csb_nrslts = NRBRW;
26917c478bd9Sstevel@tonic-gate 		flag = B_WRITE;
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 		/*
26947c478bd9Sstevel@tonic-gate 		 * Allocate memory for the command.
26957c478bd9Sstevel@tonic-gate 		 * If PIO is being used, then add an extra 16 bytes
26967c478bd9Sstevel@tonic-gate 		 */
26977c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA) {
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate 			fc = (uint_t)(fdr.fdr_nbytes);
27007c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_hilock);
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 			res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
27037c478bd9Sstevel@tonic-gate 			    &attr, DDI_DMA_STREAMING,
27047c478bd9Sstevel@tonic-gate 			    DDI_DMA_DONTWAIT, 0, &fa, &real_length,
27057c478bd9Sstevel@tonic-gate 			    &mem_handle);
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 			if (res != DDI_SUCCESS) {
27087c478bd9Sstevel@tonic-gate 				fdretcsb(fdc);
27097c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
27107c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
27117c478bd9Sstevel@tonic-gate 				return (EIO);
27127c478bd9Sstevel@tonic-gate 			}
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_read = CSB_WRITE;
27157c478bd9Sstevel@tonic-gate 			if (fdstart_dma(fdc, fa, fc) != 0) {
27167c478bd9Sstevel@tonic-gate 				ddi_dma_mem_free(&mem_handle);
27177c478bd9Sstevel@tonic-gate 				fdretcsb(fdc);
27187c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_lolock);
27197c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
27207c478bd9Sstevel@tonic-gate 				return (EIO);
27217c478bd9Sstevel@tonic-gate 			}
27227c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate 		} else {
27257c478bd9Sstevel@tonic-gate 			fc = (uint_t)(fdr.fdr_nbytes + 16);
27267c478bd9Sstevel@tonic-gate 			fa = kmem_zalloc(fc, KM_SLEEP);
27277c478bd9Sstevel@tonic-gate 		}
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate 		/* copy in the user's command bytes */
27307c478bd9Sstevel@tonic-gate 		if (ddi_copyin(fdr.fdr_addr, fa,
27317c478bd9Sstevel@tonic-gate 		    (uint_t)fdr.fdr_nbytes, mode)) {
27327c478bd9Sstevel@tonic-gate 			fdretcsb(fdc);
27337c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_DMA) {
27367c478bd9Sstevel@tonic-gate 				ddi_dma_mem_free(&mem_handle);
27377c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_RAWI,
27387c478bd9Sstevel@tonic-gate 				    (C, "fdrawioctl: (err)free dma memory\n"));
27397c478bd9Sstevel@tonic-gate 			} else {
27407c478bd9Sstevel@tonic-gate 				kmem_free(fa, fc);
27417c478bd9Sstevel@tonic-gate 			}
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
27447c478bd9Sstevel@tonic-gate 			    (C, "fdrawioctl: ddi_copyin error\n"));
27457c478bd9Sstevel@tonic-gate 			return (EFAULT);
27467c478bd9Sstevel@tonic-gate 		}
27477c478bd9Sstevel@tonic-gate 
27487c478bd9Sstevel@tonic-gate 		break;
27497c478bd9Sstevel@tonic-gate 	case FDRAW_WRCMD:
27507c478bd9Sstevel@tonic-gate 	case FDRAW_WRITEDEL:
27517c478bd9Sstevel@tonic-gate 		flag = B_WRITE;
27527c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
27537c478bd9Sstevel@tonic-gate 	case FDRAW_RDCMD:
27547c478bd9Sstevel@tonic-gate 	case FDRAW_READDEL:
27557c478bd9Sstevel@tonic-gate 	case FDRAW_READTRACK:
27567c478bd9Sstevel@tonic-gate 		/* Insert the appropriate drive number */
27577c478bd9Sstevel@tonic-gate 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
27587c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB)
27597c478bd9Sstevel@tonic-gate 			csb->csb_cmds[1] |= IPS;
27607c478bd9Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
27617c478bd9Sstevel@tonic-gate 		csb->csb_nrslts = NRBRW;
27627c478bd9Sstevel@tonic-gate 		break;
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate 	default:
27657c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
27667c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
27677c478bd9Sstevel@tonic-gate 		return (EINVAL);
27687c478bd9Sstevel@tonic-gate 	}
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 	if ((csb->csb_opflags & CSB_OFXFEROPS) && (fdr.fdr_nbytes == 0)) {
27717c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
27727c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
27737c478bd9Sstevel@tonic-gate 		return (EINVAL);
27747c478bd9Sstevel@tonic-gate 	}
27757c478bd9Sstevel@tonic-gate 	csb->csb_opflags |= CSB_OFRAWIOCTL;
27767c478bd9Sstevel@tonic-gate 
27777c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
27787c478bd9Sstevel@tonic-gate 	    (C, "fdrawioctl: nbytes = %u\n", fdr.fdr_nbytes));
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 	if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT) {
27817c478bd9Sstevel@tonic-gate 		if ((fc = (uint_t)fdr.fdr_nbytes) > 0) {
27827c478bd9Sstevel@tonic-gate 			/*
27837c478bd9Sstevel@tonic-gate 			 * In SunOS 4.X, we used to as_fault things in.
27847c478bd9Sstevel@tonic-gate 			 * We really cannot do this in 5.0/SVr4. Unless
27857c478bd9Sstevel@tonic-gate 			 * someone really believes that speed is of the
27867c478bd9Sstevel@tonic-gate 			 * essence here, it is just much simpler to do
27877c478bd9Sstevel@tonic-gate 			 * this in kernel space and use copyin/copyout.
27887c478bd9Sstevel@tonic-gate 			 */
27897c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_DMA) {
27907c478bd9Sstevel@tonic-gate 				mutex_enter(&fdc->c_hilock);
27917c478bd9Sstevel@tonic-gate 				res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
27927c478bd9Sstevel@tonic-gate 				    &attr, DDI_DMA_STREAMING,
27937c478bd9Sstevel@tonic-gate 				    DDI_DMA_DONTWAIT, 0, &fa, &real_length,
27947c478bd9Sstevel@tonic-gate 				    &mem_handle);
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 				if (res != DDI_SUCCESS) {
27977c478bd9Sstevel@tonic-gate 					fdretcsb(fdc);
27987c478bd9Sstevel@tonic-gate 					mutex_exit(&fdc->c_lolock);
27997c478bd9Sstevel@tonic-gate 					mutex_exit(&fdc->c_hilock);
28007c478bd9Sstevel@tonic-gate 					return (EIO);
28017c478bd9Sstevel@tonic-gate 				}
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate 				if (flag == B_WRITE)
28047c478bd9Sstevel@tonic-gate 					fdc->c_csb.csb_read = CSB_WRITE;
28057c478bd9Sstevel@tonic-gate 				else
28067c478bd9Sstevel@tonic-gate 					fdc->c_csb.csb_read = CSB_READ;
28077c478bd9Sstevel@tonic-gate 
28087c478bd9Sstevel@tonic-gate 				if (fdstart_dma(fdc, fa, fc) != 0) {
28097c478bd9Sstevel@tonic-gate 					ddi_dma_mem_free(&mem_handle);
28107c478bd9Sstevel@tonic-gate 					fdretcsb(fdc);
28117c478bd9Sstevel@tonic-gate 					mutex_exit(&fdc->c_lolock);
28127c478bd9Sstevel@tonic-gate 					mutex_exit(&fdc->c_hilock);
28137c478bd9Sstevel@tonic-gate 					return (EIO);
28147c478bd9Sstevel@tonic-gate 				}
28157c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 			} else {
28187c478bd9Sstevel@tonic-gate 				fa = kmem_zalloc(fc, KM_SLEEP);
28197c478bd9Sstevel@tonic-gate 			}
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 			if (flag == B_WRITE) {
28227c478bd9Sstevel@tonic-gate 				if (ddi_copyin(fdr.fdr_addr, fa, fc, mode)) {
28237c478bd9Sstevel@tonic-gate 					if (fdc->c_fdtype & FDCTYPE_DMA)
28247c478bd9Sstevel@tonic-gate 						ddi_dma_mem_free(&mem_handle);
28257c478bd9Sstevel@tonic-gate 					else
28267c478bd9Sstevel@tonic-gate 						kmem_free(fa, fc);
28277c478bd9Sstevel@tonic-gate 					fdretcsb(fdc);
28287c478bd9Sstevel@tonic-gate 					mutex_exit(&fdc->c_lolock);
282919397407SSherry Moore 					FDERRPRINT(FDEP_L1, FDEM_RAWI, (C,
283019397407SSherry Moore 					    "fdrawioctl: can't copy data\n"));
28317c478bd9Sstevel@tonic-gate 
28327c478bd9Sstevel@tonic-gate 					return (EFAULT);
28337c478bd9Sstevel@tonic-gate 				}
28347c478bd9Sstevel@tonic-gate 			}
28357c478bd9Sstevel@tonic-gate 			csb->csb_addr = fa;
28367c478bd9Sstevel@tonic-gate 			csb->csb_len = fc;
28377c478bd9Sstevel@tonic-gate 		} else {
28387c478bd9Sstevel@tonic-gate 			csb->csb_addr = 0;
28397c478bd9Sstevel@tonic-gate 			csb->csb_len = 0;
28407c478bd9Sstevel@tonic-gate 		}
28417c478bd9Sstevel@tonic-gate 	} else {
28427c478bd9Sstevel@tonic-gate 		csb->csb_addr = fa;
28437c478bd9Sstevel@tonic-gate 		csb->csb_len = fc;
28447c478bd9Sstevel@tonic-gate 	}
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
28477c478bd9Sstevel@tonic-gate 	    (C, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmds[0],
28487c478bd9Sstevel@tonic-gate 	    csb->csb_cmds[1], csb->csb_cmds[2], csb->csb_cmds[3],
28497c478bd9Sstevel@tonic-gate 	    csb->csb_cmds[4], csb->csb_cmds[5], csb->csb_cmds[6],
28507c478bd9Sstevel@tonic-gate 	    csb->csb_cmds[7], csb->csb_cmds[8], csb->csb_cmds[9]));
28517c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
28527c478bd9Sstevel@tonic-gate 	    (C, "nbytes: %x, opflags: %x, addr: %p, len: %x\n",
28537c478bd9Sstevel@tonic-gate 	    csb->csb_ncmds, csb->csb_opflags, (void *)csb->csb_addr,
28547c478bd9Sstevel@tonic-gate 	    csb->csb_len));
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate 	/*
28587c478bd9Sstevel@tonic-gate 	 * Note that we ignore any error return s from fdexec.
28597c478bd9Sstevel@tonic-gate 	 * This is the way the driver has been, and it may be
28607c478bd9Sstevel@tonic-gate 	 * that the raw ioctl senders simply don't want to
28617c478bd9Sstevel@tonic-gate 	 * see any errors returned in this fashion.
28627c478bd9Sstevel@tonic-gate 	 */
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 	if ((csb->csb_opflags & CSB_OFNORESULTS) ||
28657c478bd9Sstevel@tonic-gate 	    (csb->csb_opflags & CSB_OFIMMEDIATE)) {
28667c478bd9Sstevel@tonic-gate 		(void) fdexec(fdc, 0); /* don't sleep, don't check change */
28677c478bd9Sstevel@tonic-gate 	} else {
28687c478bd9Sstevel@tonic-gate 		(void) fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG);
28697c478bd9Sstevel@tonic-gate 	}
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate 
28727c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
28737c478bd9Sstevel@tonic-gate 	    (C, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0],
28747c478bd9Sstevel@tonic-gate 	    csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3],
28757c478bd9Sstevel@tonic-gate 	    csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6],
28767c478bd9Sstevel@tonic-gate 	    csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9]));
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate 	if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT && fc &&
28797c478bd9Sstevel@tonic-gate 	    flag == B_READ && err == 0) {
28807c478bd9Sstevel@tonic-gate 		if (ddi_copyout(fa, fdr.fdr_addr, fc, mode)) {
28817c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
28827c478bd9Sstevel@tonic-gate 			    (C, "fdrawioctl: can't copy read data\n"));
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate 			err = EFAULT;
28857c478bd9Sstevel@tonic-gate 		}
28867c478bd9Sstevel@tonic-gate 	}
28877c478bd9Sstevel@tonic-gate 
28887c478bd9Sstevel@tonic-gate 
28897c478bd9Sstevel@tonic-gate 	if (fc) {
28907c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA) {
28917c478bd9Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
28927c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
28937c478bd9Sstevel@tonic-gate 			    (C, "fdrawioctl: free dma memory\n"));
28947c478bd9Sstevel@tonic-gate 		} else {
28957c478bd9Sstevel@tonic-gate 			kmem_free(fa, fc);
28967c478bd9Sstevel@tonic-gate 		}
28977c478bd9Sstevel@tonic-gate 	}
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	/* copy cmd results into fdr */
29017c478bd9Sstevel@tonic-gate 	for (i = 0; (int)i <= (int)csb->csb_nrslts; i++)
29027c478bd9Sstevel@tonic-gate 		fdr.fdr_result[i] = csb->csb_rslt[i];
29037c478bd9Sstevel@tonic-gate 	fdr.fdr_nbytes = fdc->c_csb.csb_rlen; /* return resid */
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode)) {
29067c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
29077c478bd9Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
29087c478bd9Sstevel@tonic-gate 		bcopy(fdr.fdr_cmd, fdr32.fdr_cmd, sizeof (fdr32.fdr_cmd));
29097c478bd9Sstevel@tonic-gate 		fdr32.fdr_cnum = fdr.fdr_cnum;
29107c478bd9Sstevel@tonic-gate 		bcopy(fdr.fdr_result, fdr32.fdr_result,
29117c478bd9Sstevel@tonic-gate 		    sizeof (fdr32.fdr_result));
29127c478bd9Sstevel@tonic-gate 		fdr32.fdr_nbytes = fdr.fdr_nbytes;
291329df58e5Spc157239 		fdr32.fdr_addr = (caddr32_t)(uintptr_t)fdr.fdr_addr;
29147c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&fdr32, (caddr_t)arg, sizeof (fdr32), mode)) {
29157c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
29167c478bd9Sstevel@tonic-gate 			    (C, "fdrawioctl: can't copy results32\n"));
29177c478bd9Sstevel@tonic-gate 			err = EFAULT;
29187c478bd9Sstevel@tonic-gate 		}
29197c478bd9Sstevel@tonic-gate 		break;
29207c478bd9Sstevel@tonic-gate #endif
29217c478bd9Sstevel@tonic-gate 	case DDI_MODEL_NONE:
29227c478bd9Sstevel@tonic-gate 	default:
29237c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&fdr, (caddr_t)arg, sizeof (fdr), mode)) {
29247c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
29257c478bd9Sstevel@tonic-gate 			    (C, "fdrawioctl: can't copy results\n"));
29267c478bd9Sstevel@tonic-gate 			err = EFAULT;
29277c478bd9Sstevel@tonic-gate 		}
29287c478bd9Sstevel@tonic-gate 		break;
29297c478bd9Sstevel@tonic-gate 	}
29307c478bd9Sstevel@tonic-gate 
29317c478bd9Sstevel@tonic-gate 	fdretcsb(fdc);
29327c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
29337c478bd9Sstevel@tonic-gate 	return (0);
29347c478bd9Sstevel@tonic-gate }
29357c478bd9Sstevel@tonic-gate 
29367c478bd9Sstevel@tonic-gate /*
29377c478bd9Sstevel@tonic-gate  * fdformat
29387c478bd9Sstevel@tonic-gate  *	format a track
29397c478bd9Sstevel@tonic-gate  * For PIO, builds a table of sector data values with 16 bytes
29407c478bd9Sstevel@tonic-gate  * (sizeof fdc's fifo) of dummy on end.	 This is so than when fdc->c_len
29417c478bd9Sstevel@tonic-gate  * goes to 0 and fd_intr sends a TC that all the real formatting will
29427c478bd9Sstevel@tonic-gate  * have already been done.
29437c478bd9Sstevel@tonic-gate  *
29447c478bd9Sstevel@tonic-gate  *	- called with the low level lock held
29457c478bd9Sstevel@tonic-gate  */
29467c478bd9Sstevel@tonic-gate static int
29477c478bd9Sstevel@tonic-gate fdformat(struct fdctlr *fdc, int unit, int cyl, int hd)
29487c478bd9Sstevel@tonic-gate {
29497c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
29507c478bd9Sstevel@tonic-gate 	struct fdunit *un;
29517c478bd9Sstevel@tonic-gate 	struct fd_char *ch;
29527c478bd9Sstevel@tonic-gate 	int	cmdresult;
29537c478bd9Sstevel@tonic-gate 	uchar_t	*fmthdrs;
29547c478bd9Sstevel@tonic-gate 	caddr_t fd;
29557c478bd9Sstevel@tonic-gate 	int	i;
29567c478bd9Sstevel@tonic-gate 	size_t	real_length;
29577c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
29587c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t mem_handle;
29597c478bd9Sstevel@tonic-gate 
29607c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_FORM,
29617c478bd9Sstevel@tonic-gate 	    (C, "fdformat cyl %d, hd %d\n", cyl, hd));
29627c478bd9Sstevel@tonic-gate 	fdgetcsb(fdc);
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
29657c478bd9Sstevel@tonic-gate 
29667c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
29677c478bd9Sstevel@tonic-gate 	un = fdc->c_un;
29687c478bd9Sstevel@tonic-gate 	ch = un->un_chars;
29697c478bd9Sstevel@tonic-gate 
29707c478bd9Sstevel@tonic-gate 	/* setup common things in csb */
29717c478bd9Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
29727c478bd9Sstevel@tonic-gate 
29737c478bd9Sstevel@tonic-gate 	/*
29747c478bd9Sstevel@tonic-gate 	 * The controller needs to do a seek before
29757c478bd9Sstevel@tonic-gate 	 * each format to get to right cylinder.
29767c478bd9Sstevel@tonic-gate 	 */
29777c478bd9Sstevel@tonic-gate 	if (fdrecalseek(fdc, unit, cyl, FDXC_CHECKCHG)) {
29787c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
29797c478bd9Sstevel@tonic-gate 		return (EIO);
29807c478bd9Sstevel@tonic-gate 	}
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	/*
29837c478bd9Sstevel@tonic-gate 	 * now do the format itself
29847c478bd9Sstevel@tonic-gate 	 */
29857c478bd9Sstevel@tonic-gate 	csb->csb_nrslts = NRBRW;
29867c478bd9Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
29877c478bd9Sstevel@tonic-gate 
29887c478bd9Sstevel@tonic-gate 	csb->csb_cmds[0] = FDRAW_FORMAT;
29897c478bd9Sstevel@tonic-gate 	/* always or in MFM bit */
29907c478bd9Sstevel@tonic-gate 	csb->csb_cmds[0] |= MFM;
29917c478bd9Sstevel@tonic-gate 	csb->csb_cmds[1] = (hd << 2) | (unit & 0x03);
29927c478bd9Sstevel@tonic-gate 	csb->csb_cmds[2] = ch->fdc_medium ? 3 : 2;
29937c478bd9Sstevel@tonic-gate 	csb->csb_cmds[3] = ch->fdc_secptrack;
29947c478bd9Sstevel@tonic-gate 	csb->csb_cmds[4] = GPLF;
29957c478bd9Sstevel@tonic-gate 	csb->csb_cmds[5] = FDATA;
29967c478bd9Sstevel@tonic-gate 	csb->csb_ncmds = 6;
29977c478bd9Sstevel@tonic-gate 	csb->csb_maxretry = rwretry;
29987c478bd9Sstevel@tonic-gate 	csb->csb_retrys = 0;
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 	/*
30017c478bd9Sstevel@tonic-gate 	 * NOTE: have to add size of fifo also - for dummy format action
30027c478bd9Sstevel@tonic-gate 	 * if PIO is being used.
30037c478bd9Sstevel@tonic-gate 	 */
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
30077c478bd9Sstevel@tonic-gate 
30087c478bd9Sstevel@tonic-gate 		csb->csb_len = (uint_t)4 * ch->fdc_secptrack;
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
30117c478bd9Sstevel@tonic-gate 		attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
30127c478bd9Sstevel@tonic-gate 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
30137c478bd9Sstevel@tonic-gate 
30147c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate 		cmdresult = ddi_dma_mem_alloc(fdc->c_dmahandle, csb->csb_len,
30177c478bd9Sstevel@tonic-gate 		    &attr, DDI_DMA_STREAMING,
30187c478bd9Sstevel@tonic-gate 		    DDI_DMA_DONTWAIT, 0, &fd, &real_length,
30197c478bd9Sstevel@tonic-gate 		    &mem_handle);
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 		if (cmdresult != DDI_SUCCESS) {
30227c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
30237c478bd9Sstevel@tonic-gate 			return (cmdresult);
30247c478bd9Sstevel@tonic-gate 		}
30257c478bd9Sstevel@tonic-gate 
30267c478bd9Sstevel@tonic-gate 		fdc->c_csb.csb_read = CSB_WRITE;
30277c478bd9Sstevel@tonic-gate 		if (fdstart_dma(fdc, fd,  csb->csb_len) != 0) {
30287c478bd9Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
30297c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
30307c478bd9Sstevel@tonic-gate 			return (-1);
30317c478bd9Sstevel@tonic-gate 		}
30327c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate 
30357c478bd9Sstevel@tonic-gate 	} else {
30367c478bd9Sstevel@tonic-gate 		csb->csb_len = (uint_t)4 * ch->fdc_secptrack + 16;
30377c478bd9Sstevel@tonic-gate 		fd = kmem_zalloc(csb->csb_len, KM_SLEEP);
30387c478bd9Sstevel@tonic-gate 		fmthdrs = (uchar_t *)fd;
30397c478bd9Sstevel@tonic-gate 	}
30407c478bd9Sstevel@tonic-gate 
30417c478bd9Sstevel@tonic-gate 	csb->csb_addr = (caddr_t)fd;
30427c478bd9Sstevel@tonic-gate 
30437c478bd9Sstevel@tonic-gate 	for (i = 1; i <= ch->fdc_secptrack; i++) {
30447c478bd9Sstevel@tonic-gate 		*fd++ = (uchar_t)cyl;		/* cylinder */
30457c478bd9Sstevel@tonic-gate 		*fd++ = (uchar_t)hd;		/* head */
30467c478bd9Sstevel@tonic-gate 		*fd++ = (uchar_t)i;	/* sector number */
30477c478bd9Sstevel@tonic-gate 		*fd++ = ch->fdc_medium ? 3 : 2; /* sec_size code */
30487c478bd9Sstevel@tonic-gate 	}
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate 	if ((cmdresult = fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG)) == 0) {
30517c478bd9Sstevel@tonic-gate 		if (csb->csb_cmdstat)
30527c478bd9Sstevel@tonic-gate 			cmdresult = EIO;	/* XXX TBD NYD for now */
30537c478bd9Sstevel@tonic-gate 	}
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
30567c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&mem_handle);
30577c478bd9Sstevel@tonic-gate 	} else {
30587c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)fmthdrs, csb->csb_len);
30597c478bd9Sstevel@tonic-gate 	}
30607c478bd9Sstevel@tonic-gate 
30617c478bd9Sstevel@tonic-gate 	fdretcsb(fdc);
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 	return (cmdresult);
30647c478bd9Sstevel@tonic-gate }
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate /*
30677c478bd9Sstevel@tonic-gate  * fdstart
30687c478bd9Sstevel@tonic-gate  *	called from fd_strategy() or from fdXXXX() to setup and
30697c478bd9Sstevel@tonic-gate  *	start operations of read or write only (using buf structs).
30707c478bd9Sstevel@tonic-gate  *	Because the chip doesn't handle crossing cylinder boundaries on
30717c478bd9Sstevel@tonic-gate  *	the fly, this takes care of those boundary conditions.	Note that
30727c478bd9Sstevel@tonic-gate  *	it sleeps until the operation is done *within fdstart* - so that
30737c478bd9Sstevel@tonic-gate  *	when fdstart returns, the operation is already done.
30747c478bd9Sstevel@tonic-gate  *
30757c478bd9Sstevel@tonic-gate  *	- called with the low level lock held
30767c478bd9Sstevel@tonic-gate  *
30777c478bd9Sstevel@tonic-gate  */
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate static int slavio_index_pulse_work_around = 0;
30807c478bd9Sstevel@tonic-gate 
30817c478bd9Sstevel@tonic-gate static void
30827c478bd9Sstevel@tonic-gate fdstart(struct fdctlr *fdc)
30837c478bd9Sstevel@tonic-gate {
30847c478bd9Sstevel@tonic-gate 	struct buf *bp;
30857c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
30867c478bd9Sstevel@tonic-gate 	struct fdunit *un;
30877c478bd9Sstevel@tonic-gate 	struct fd_char *ch;
30887c478bd9Sstevel@tonic-gate 	struct dk_map32 *dkm;
30897c478bd9Sstevel@tonic-gate 	uint_t	part;		/* partition number for the transfer */
30907c478bd9Sstevel@tonic-gate 	uint_t	start_part;	/* starting block of the partition */
30917c478bd9Sstevel@tonic-gate 	uint_t	last_part;	/* last block of the partition */
30927c478bd9Sstevel@tonic-gate 	uint_t	blk;		/* starting block of transfer on diskette */
30937c478bd9Sstevel@tonic-gate 	uint_t	sect;		/* starting block's offset into track */
30947c478bd9Sstevel@tonic-gate 	uint_t	cyl;		/* starting cylinder of the transfer */
30957c478bd9Sstevel@tonic-gate 	uint_t	bincyl;		/* starting blocks's offset into cylinder */
30967c478bd9Sstevel@tonic-gate 	uint_t	secpcyl;	/* number of sectors per cylinder */
30977c478bd9Sstevel@tonic-gate 	uint_t	phys_blkno;	/* no. of blocks on the diskette */
30987c478bd9Sstevel@tonic-gate 	uint_t	head;		/* one of two diskette heads */
30997c478bd9Sstevel@tonic-gate 	uint_t	unit;
31007c478bd9Sstevel@tonic-gate 	uint_t	len, tlen;
31017c478bd9Sstevel@tonic-gate 	caddr_t addr;
31027c478bd9Sstevel@tonic-gate 	caddr_t temp_addr;
31037c478bd9Sstevel@tonic-gate 	uint_t	partial_read = 0;
31047c478bd9Sstevel@tonic-gate 	int sb_temp_buf_used = 0;
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate 	bp = fdc->c_actf;
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate 	while (bp != NULL) {
31097c478bd9Sstevel@tonic-gate 
31107c478bd9Sstevel@tonic-gate 		fdc->c_actf = bp->av_forw;
31117c478bd9Sstevel@tonic-gate 		fdc->c_current = bp;
31127c478bd9Sstevel@tonic-gate 
31137c478bd9Sstevel@tonic-gate 		/*
31147c478bd9Sstevel@tonic-gate 		 * Initialize the buf structure.  The residual count is
31157c478bd9Sstevel@tonic-gate 		 * initially the number of bytes to be read or written
31167c478bd9Sstevel@tonic-gate 		 */
31177c478bd9Sstevel@tonic-gate 		bp->b_flags &= ~B_ERROR;
31187c478bd9Sstevel@tonic-gate 		bp->b_error = 0;
31197c478bd9Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
31207c478bd9Sstevel@tonic-gate 		bp_mapin(bp);			/* map in buffers */
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 		addr = bp->b_un.b_addr;		/* assign buffer address */
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate 		/*
31257c478bd9Sstevel@tonic-gate 		 * Find the unit and partition numbers.
31267c478bd9Sstevel@tonic-gate 		 */
31277c478bd9Sstevel@tonic-gate 		unit = fdc->c_un->un_unit_no;
31287c478bd9Sstevel@tonic-gate 		un = fdc->c_un;
31297c478bd9Sstevel@tonic-gate 		ch = un->un_chars;
31307c478bd9Sstevel@tonic-gate 		part = FDPARTITION(bp->b_edev);
31317c478bd9Sstevel@tonic-gate 		dkm = &un->un_label.dkl_map[part];
31327c478bd9Sstevel@tonic-gate 
31337c478bd9Sstevel@tonic-gate 		if (un->un_chars->fdc_medium) {
31347c478bd9Sstevel@tonic-gate 			phys_blkno = bp->b_blkno >> 1;
31357c478bd9Sstevel@tonic-gate 		} else {
31367c478bd9Sstevel@tonic-gate 			phys_blkno = bp->b_blkno;
31377c478bd9Sstevel@tonic-gate 		}
31387c478bd9Sstevel@tonic-gate 
31397c478bd9Sstevel@tonic-gate 		if (un->un_iostat) {
31407c478bd9Sstevel@tonic-gate 			kstat_waitq_to_runq(KIOSP);
31417c478bd9Sstevel@tonic-gate 		}
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_STRT,
31447c478bd9Sstevel@tonic-gate 		    (C, "fdstart: bp=0x%p blkno=0x%x bcount=0x%x\n",
31457c478bd9Sstevel@tonic-gate 		    (void *)bp, (int)bp->b_blkno, (int)bp->b_bcount));
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate 		/*
31487c478bd9Sstevel@tonic-gate 		 * Get the csb and initialize the values that are the same
31497c478bd9Sstevel@tonic-gate 		 * for DMA and PIO.
31507c478bd9Sstevel@tonic-gate 		 */
31517c478bd9Sstevel@tonic-gate 		fdgetcsb(fdc);		/* get csb (maybe wait for it) */
31527c478bd9Sstevel@tonic-gate 		csb = &fdc->c_csb;
31537c478bd9Sstevel@tonic-gate 		csb->csb_unit = unit;		/* floppy unit number */
31547c478bd9Sstevel@tonic-gate 
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 		/*
31577c478bd9Sstevel@tonic-gate 		 * bugID:4133425 : If the controller is SLAVIO, and
31587c478bd9Sstevel@tonic-gate 		 * the read does not reach end of track, then modify
31597c478bd9Sstevel@tonic-gate 		 * the tlen to read until the end of track to a temp
31607c478bd9Sstevel@tonic-gate 		 * buffer and disable MT. After the read is over,
31617c478bd9Sstevel@tonic-gate 		 * copy the useful portion of the data to 'addr'.
31627c478bd9Sstevel@tonic-gate 		 * Enable this feature only when
31637c478bd9Sstevel@tonic-gate 		 * slavio_index_pulse_work_aound variable is
31647c478bd9Sstevel@tonic-gate 		 * set in /etc/system.
31657c478bd9Sstevel@tonic-gate 		 */
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate 		if (bp->b_flags & B_READ) {
31697c478bd9Sstevel@tonic-gate 			if (((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
31707c478bd9Sstevel@tonic-gate 			    slavio_index_pulse_work_around) ||
31717c478bd9Sstevel@tonic-gate 			    (fdc->c_fdtype & FDCTYPE_TCBUG))
31727c478bd9Sstevel@tonic-gate 				csb->csb_cmds[0] = SK | FDRAW_RDCMD | MFM;
31737c478bd9Sstevel@tonic-gate 			else
31747c478bd9Sstevel@tonic-gate 				csb->csb_cmds[0] = MT | SK | FDRAW_RDCMD | MFM;
31757c478bd9Sstevel@tonic-gate 		} else {
31767c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_TCBUG)
31777c478bd9Sstevel@tonic-gate 				csb->csb_cmds[0] = FDRAW_WRCMD | MFM;
31787c478bd9Sstevel@tonic-gate 			else
31797c478bd9Sstevel@tonic-gate 				csb->csb_cmds[0] = MT | FDRAW_WRCMD | MFM;
31807c478bd9Sstevel@tonic-gate 		}
31817c478bd9Sstevel@tonic-gate 
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 		if (bp->b_flags & B_READ)
31847c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_read = CSB_READ;
31857c478bd9Sstevel@tonic-gate 		else
31867c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_read = CSB_WRITE;
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 		csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size  */
31907c478bd9Sstevel@tonic-gate 		csb->csb_cmds[6] = ch->fdc_secptrack; /* EOT-# of sectors/trk */
31917c478bd9Sstevel@tonic-gate 		csb->csb_cmds[7] = GPLN;	/* GPL - gap 3 size code */
31927c478bd9Sstevel@tonic-gate 		csb->csb_cmds[8] = SSSDTL;	/* DTL - be 0xFF if N != 0 */
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 		csb->csb_ncmds = NCBRW;		/* number of command bytes */
31957c478bd9Sstevel@tonic-gate 		csb->csb_nrslts = NRBRW;	/* number of result bytes */
31967c478bd9Sstevel@tonic-gate 
31977c478bd9Sstevel@tonic-gate 
31987c478bd9Sstevel@tonic-gate 		/*
31997c478bd9Sstevel@tonic-gate 		 * opflags for interrupt handler, et.al.
32007c478bd9Sstevel@tonic-gate 		 */
32017c478bd9Sstevel@tonic-gate 		csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 
32047c478bd9Sstevel@tonic-gate 		/*
32057c478bd9Sstevel@tonic-gate 		 * Make sure the transfer does not go off the end
32067c478bd9Sstevel@tonic-gate 		 * of the partition.  Limit the actual amount transferred
32077c478bd9Sstevel@tonic-gate 		 * to fit the partition.
32087c478bd9Sstevel@tonic-gate 		 */
32097c478bd9Sstevel@tonic-gate 
32107c478bd9Sstevel@tonic-gate 		blk = phys_blkno;
32117c478bd9Sstevel@tonic-gate 		start_part = (dkm->dkl_cylno * ch->fdc_secptrack
32127c478bd9Sstevel@tonic-gate 		    * ch->fdc_nhead);
32137c478bd9Sstevel@tonic-gate 		blk = blk + start_part;
32147c478bd9Sstevel@tonic-gate 		last_part = start_part + dkm->dkl_nblk;
32157c478bd9Sstevel@tonic-gate 
32167c478bd9Sstevel@tonic-gate 		if ((blk + (bp->b_bcount / ch->fdc_sec_size)) > last_part)
32177c478bd9Sstevel@tonic-gate 			len = (last_part - blk) * ch->fdc_sec_size;
32187c478bd9Sstevel@tonic-gate 		else
32197c478bd9Sstevel@tonic-gate 			len = (uint_t)bp->b_bcount;
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate 		/*
32227c478bd9Sstevel@tonic-gate 		 * now we have the real start blk,
32237c478bd9Sstevel@tonic-gate 		 * addr and len for xfer op
32247c478bd9Sstevel@tonic-gate 		 * sectors per cylinder
32257c478bd9Sstevel@tonic-gate 		 */
32267c478bd9Sstevel@tonic-gate 		secpcyl = ch->fdc_nhead * ch->fdc_secptrack;
32277c478bd9Sstevel@tonic-gate 
32287c478bd9Sstevel@tonic-gate 		/*
32297c478bd9Sstevel@tonic-gate 		 * The controller can transfer up to a cylinder at a time.
32307c478bd9Sstevel@tonic-gate 		 * Early revs of the 82077 have a bug that causes the chip to
32317c478bd9Sstevel@tonic-gate 		 * fail to respond to the Terminal Count signal.  Due to this
32327c478bd9Sstevel@tonic-gate 		 * bug, controllers with type FDCTYPE_TCBUG, only transfer up
32337c478bd9Sstevel@tonic-gate 		 * to a track at a time.
32347c478bd9Sstevel@tonic-gate 		 * See earlier comment for bugID:4133425 for index pulse
32357c478bd9Sstevel@tonic-gate 		 * work around.
32367c478bd9Sstevel@tonic-gate 		 */
32377c478bd9Sstevel@tonic-gate 
32387c478bd9Sstevel@tonic-gate 		while (len != 0) {
32397c478bd9Sstevel@tonic-gate 
32407c478bd9Sstevel@tonic-gate 			cyl = blk / secpcyl;	/* cylinder of transfer */
32417c478bd9Sstevel@tonic-gate 			bincyl = blk % secpcyl;	/* blk within cylinder */
32427c478bd9Sstevel@tonic-gate 			head = bincyl / ch->fdc_secptrack;
32437c478bd9Sstevel@tonic-gate 			sect = (bincyl % ch->fdc_secptrack) + 1;
32447c478bd9Sstevel@tonic-gate 						/* sect w/in track */
32457c478bd9Sstevel@tonic-gate 
32467c478bd9Sstevel@tonic-gate 			/*
32477c478bd9Sstevel@tonic-gate 			 * If the desired block and length will go beyond the
32487c478bd9Sstevel@tonic-gate 			 * cylinder end, limit it to the cylinder end.
32497c478bd9Sstevel@tonic-gate 			 */
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 			if ((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
32527c478bd9Sstevel@tonic-gate 			    slavio_index_pulse_work_around &&
32537c478bd9Sstevel@tonic-gate 			    (fdc->c_csb.csb_read == CSB_READ)) {
32547c478bd9Sstevel@tonic-gate 
32557c478bd9Sstevel@tonic-gate 				tlen = (ch->fdc_secptrack - sect + 1) *
32567c478bd9Sstevel@tonic-gate 				    ch->fdc_sec_size;
32577c478bd9Sstevel@tonic-gate 				if (len < tlen) {
32587c478bd9Sstevel@tonic-gate 					partial_read = 1;
32597c478bd9Sstevel@tonic-gate 					temp_addr = (caddr_t)kmem_alloc(tlen,
32607c478bd9Sstevel@tonic-gate 					    KM_SLEEP);
32617c478bd9Sstevel@tonic-gate 				}
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate 			} else if (fdc->c_fdtype & FDCTYPE_TCBUG) {
32647c478bd9Sstevel@tonic-gate 				tlen = len;
32657c478bd9Sstevel@tonic-gate 				if (len > ((ch->fdc_secptrack - sect + 1) *
32667c478bd9Sstevel@tonic-gate 				    ch->fdc_sec_size))
32677c478bd9Sstevel@tonic-gate 					tlen = (ch->fdc_secptrack - sect + 1)
32687c478bd9Sstevel@tonic-gate 					    * ch->fdc_sec_size;
32697c478bd9Sstevel@tonic-gate 			} else {
32707c478bd9Sstevel@tonic-gate 				if (len > ((secpcyl - bincyl)
32717c478bd9Sstevel@tonic-gate 				    * ch->fdc_sec_size))
32727c478bd9Sstevel@tonic-gate 					tlen = (secpcyl - bincyl)
32737c478bd9Sstevel@tonic-gate 					    * ch->fdc_sec_size;
32747c478bd9Sstevel@tonic-gate 
32757c478bd9Sstevel@tonic-gate 				else
32767c478bd9Sstevel@tonic-gate 					tlen = len;
32777c478bd9Sstevel@tonic-gate 			}
32787c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB) {
32797c478bd9Sstevel@tonic-gate 				/*
32807c478bd9Sstevel@tonic-gate 				 * To avoid underrun errors during IFB activity.
32817c478bd9Sstevel@tonic-gate 				 */
32827c478bd9Sstevel@tonic-gate 				if (tlen > max_fd_dma_len)
32837c478bd9Sstevel@tonic-gate 					tlen = max_fd_dma_len;
32847c478bd9Sstevel@tonic-gate 			}
32857c478bd9Sstevel@tonic-gate 
32867c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRT,
32877c478bd9Sstevel@tonic-gate 			    (C, "	blk 0x%x, addr 0x%p, len 0x%x\n",
32887c478bd9Sstevel@tonic-gate 			    blk, (void *)addr, len));
32897c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRT,
32907c478bd9Sstevel@tonic-gate 			    (C, "cyl:%x, head:%x, sec:%x\n",
32917c478bd9Sstevel@tonic-gate 			    cyl, head, sect));
32927c478bd9Sstevel@tonic-gate 
32937c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_STRT,
32947c478bd9Sstevel@tonic-gate 			    (C, "	resid 0x%lx, tlen %d\n",
32957c478bd9Sstevel@tonic-gate 			    bp->b_resid, tlen));
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate 			/*
32987c478bd9Sstevel@tonic-gate 			 * Finish programming the command
32997c478bd9Sstevel@tonic-gate 			 */
33007c478bd9Sstevel@tonic-gate 			csb->csb_cmds[1] = (head << 2) | unit;
33017c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB)
33027c478bd9Sstevel@tonic-gate 				csb->csb_cmds[1] |= IPS;
33037c478bd9Sstevel@tonic-gate 
33047c478bd9Sstevel@tonic-gate 			csb->csb_cmds[2] = cyl;	/* C - cylinder address */
33057c478bd9Sstevel@tonic-gate 			csb->csb_cmds[3] = head;	/* H - head number */
33067c478bd9Sstevel@tonic-gate 			csb->csb_cmds[4] = sect;	/* R - sector number */
33077c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_TCBUG)
33087c478bd9Sstevel@tonic-gate 				csb->csb_cmds[6] = sect +
33097c478bd9Sstevel@tonic-gate 				    (tlen / ch->fdc_sec_size) - 1;
33107c478bd9Sstevel@tonic-gate 
33117c478bd9Sstevel@tonic-gate 			csb->csb_len = tlen;
33127c478bd9Sstevel@tonic-gate 			if (partial_read)
33137c478bd9Sstevel@tonic-gate 				csb->csb_addr = temp_addr;
33147c478bd9Sstevel@tonic-gate 			else
33157c478bd9Sstevel@tonic-gate 				csb->csb_addr = addr;
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 			/* retry this many times max */
33187c478bd9Sstevel@tonic-gate 			csb->csb_maxretry = rwretry;
33197c478bd9Sstevel@tonic-gate 			csb->csb_retrys = 0;
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate 			/* If platform supports DMA, set up DMA resources */
33227c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_DMA) {
33237c478bd9Sstevel@tonic-gate 				if ((fdc->c_fdtype & FDCTYPE_SB) &&
332429df58e5Spc157239 				    (((uint32_t)(uintptr_t)addr & 0xFFFF0000) !=
332529df58e5Spc157239 				    (((uint32_t)(uintptr_t)addr + tlen) &
332629df58e5Spc157239 				    0xFFFF0000))) {
33277c478bd9Sstevel@tonic-gate 					csb->csb_addr = fdc->dma_buf;
33287c478bd9Sstevel@tonic-gate 					sb_temp_buf_used = 1;
33297c478bd9Sstevel@tonic-gate 					if (csb->csb_read != CSB_READ) {
33307c478bd9Sstevel@tonic-gate 						bcopy(addr, fdc->dma_buf, tlen);
33317c478bd9Sstevel@tonic-gate 				}
33327c478bd9Sstevel@tonic-gate 			}
33337c478bd9Sstevel@tonic-gate 				mutex_enter(&fdc->c_hilock);
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate 				if (fdstart_dma(fdc, csb->csb_addr,
33367c478bd9Sstevel@tonic-gate 				    tlen) != 0) {
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate 					bp->b_flags |= B_ERROR;
33397c478bd9Sstevel@tonic-gate 					bp->b_error = EAGAIN;
33407c478bd9Sstevel@tonic-gate 
33417c478bd9Sstevel@tonic-gate 					mutex_exit(&fdc->c_hilock);
33427c478bd9Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_STRT,
33437c478bd9Sstevel@tonic-gate 					    (C, "fdstart: no dma resources\n"));
33447c478bd9Sstevel@tonic-gate 
33457c478bd9Sstevel@tonic-gate 					break;
33467c478bd9Sstevel@tonic-gate 				}
33477c478bd9Sstevel@tonic-gate 				mutex_exit(&fdc->c_hilock);
33487c478bd9Sstevel@tonic-gate 
33497c478bd9Sstevel@tonic-gate 			}
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate 			bp->b_error = fdexec(fdc, FDXC_SLEEP|FDXC_CHECKCHG);
33527c478bd9Sstevel@tonic-gate 			if (bp->b_error != 0) {
33537c478bd9Sstevel@tonic-gate 				/*
33547c478bd9Sstevel@tonic-gate 				 * error in fdexec
33557c478bd9Sstevel@tonic-gate 				 */
33567c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_STRT, (C,
33577c478bd9Sstevel@tonic-gate 				    "fdstart: bad exec of bp: 0x%p, err %d\n",
33587c478bd9Sstevel@tonic-gate 				    (void *)bp, bp->b_error));
33597c478bd9Sstevel@tonic-gate 
33607c478bd9Sstevel@tonic-gate 				bp->b_flags |= B_ERROR;
33617c478bd9Sstevel@tonic-gate 				if (partial_read) {
33627c478bd9Sstevel@tonic-gate 					partial_read = 0;
33637c478bd9Sstevel@tonic-gate 					kmem_free(temp_addr, tlen);
33647c478bd9Sstevel@tonic-gate 				}
33657c478bd9Sstevel@tonic-gate 				break;
33667c478bd9Sstevel@tonic-gate 			}
33677c478bd9Sstevel@tonic-gate 
33687c478bd9Sstevel@tonic-gate 			/*
33697c478bd9Sstevel@tonic-gate 			 * If it was a partial read, copy the useful
33707c478bd9Sstevel@tonic-gate 			 * portion of data to 'addr'.
33717c478bd9Sstevel@tonic-gate 			 */
33727c478bd9Sstevel@tonic-gate 			if (partial_read) {
33737c478bd9Sstevel@tonic-gate 				partial_read = 0;
33747c478bd9Sstevel@tonic-gate 				bcopy(temp_addr, addr, len);
33757c478bd9Sstevel@tonic-gate 				kmem_free(temp_addr, tlen);
33767c478bd9Sstevel@tonic-gate 				tlen = len;
33777c478bd9Sstevel@tonic-gate 			}
33787c478bd9Sstevel@tonic-gate 			if ((fdc->c_fdtype & FDCTYPE_SB) &&
33797c478bd9Sstevel@tonic-gate 			    (csb->csb_read == CSB_READ)) {
33807c478bd9Sstevel@tonic-gate 				if (sb_temp_buf_used) {
33817c478bd9Sstevel@tonic-gate 					bcopy(fdc->dma_buf, addr, tlen);
33827c478bd9Sstevel@tonic-gate 					sb_temp_buf_used = 0;
33837c478bd9Sstevel@tonic-gate 				}
33847c478bd9Sstevel@tonic-gate 			}
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 			blk += tlen / ch->fdc_sec_size;
33877c478bd9Sstevel@tonic-gate 			len -= tlen;
33887c478bd9Sstevel@tonic-gate 			addr += tlen;
33897c478bd9Sstevel@tonic-gate 			bp->b_resid -= tlen;
33907c478bd9Sstevel@tonic-gate 
33917c478bd9Sstevel@tonic-gate 		}
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_STRT,
33947c478bd9Sstevel@tonic-gate 		    (C, "fdstart done: b_resid %lu, b_count %lu, csb_rlen %d\n",
33957c478bd9Sstevel@tonic-gate 		    bp->b_resid, bp->b_bcount, fdc->c_csb.csb_rlen));
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate 		fdc->c_current = 0;
33987c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
33997c478bd9Sstevel@tonic-gate 		if (un->un_iostat) {
34007c478bd9Sstevel@tonic-gate 			if (bp->b_flags & B_READ) {
34017c478bd9Sstevel@tonic-gate 				KIOSP->reads++;
34027c478bd9Sstevel@tonic-gate 				KIOSP->nread +=
34037c478bd9Sstevel@tonic-gate 				    (bp->b_bcount - bp->b_resid);
34047c478bd9Sstevel@tonic-gate 			} else {
34057c478bd9Sstevel@tonic-gate 				KIOSP->writes++;
34067c478bd9Sstevel@tonic-gate 				KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
34077c478bd9Sstevel@tonic-gate 			}
34087c478bd9Sstevel@tonic-gate 			kstat_runq_exit(KIOSP);
34097c478bd9Sstevel@tonic-gate 		}
34107c478bd9Sstevel@tonic-gate 		biodone(bp);
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate 		/*
34137c478bd9Sstevel@tonic-gate 		 * Look at the next buffer
34147c478bd9Sstevel@tonic-gate 		 */
34157c478bd9Sstevel@tonic-gate 		bp = fdc->c_actf;
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate 	}
34187c478bd9Sstevel@tonic-gate }
34197c478bd9Sstevel@tonic-gate 
34207c478bd9Sstevel@tonic-gate /*
34217c478bd9Sstevel@tonic-gate  * Set up DMA resources
34227c478bd9Sstevel@tonic-gate  * The DMA handle was initialized in fd_attach()
34237c478bd9Sstevel@tonic-gate  * Assumes the handle has already been allocated by fd_attach()
34247c478bd9Sstevel@tonic-gate  */
34257c478bd9Sstevel@tonic-gate static int
34267c478bd9Sstevel@tonic-gate fdstart_dma(struct fdctlr *fdc, caddr_t addr, uint_t len)
34277c478bd9Sstevel@tonic-gate {
34287c478bd9Sstevel@tonic-gate 	int		flags;		/* flags for setting up resources */
34297c478bd9Sstevel@tonic-gate 	int		res;
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: start\n"));
34327c478bd9Sstevel@tonic-gate 
34337c478bd9Sstevel@tonic-gate 	if (fdc->c_csb.csb_read == CSB_READ) {
34347c478bd9Sstevel@tonic-gate 		flags = DDI_DMA_READ;
34357c478bd9Sstevel@tonic-gate 	} else {
34367c478bd9Sstevel@tonic-gate 		flags = DDI_DMA_WRITE;
34377c478bd9Sstevel@tonic-gate 	}
34387c478bd9Sstevel@tonic-gate 
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate 	/* allow partial mapping to maximize the portability of the driver */
34417c478bd9Sstevel@tonic-gate 	flags = flags | DDI_DMA_PARTIAL;
34427c478bd9Sstevel@tonic-gate 
34437c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: amt. asked for %d\n",
34447c478bd9Sstevel@tonic-gate 	    len));
34457c478bd9Sstevel@tonic-gate 
34467c478bd9Sstevel@tonic-gate 	/*
34477c478bd9Sstevel@tonic-gate 	 * Zero out the current cookie.  This is done to ensure that
34487c478bd9Sstevel@tonic-gate 	 * the previous transfers cookie information can in no way be
34497c478bd9Sstevel@tonic-gate 	 * used.
34507c478bd9Sstevel@tonic-gate 	 */
34517c478bd9Sstevel@tonic-gate 	bzero((char *)&fdc->c_csb.csb_dmacookie,
34527c478bd9Sstevel@tonic-gate 	    sizeof (fdc->c_csb.csb_dmacookie));
34537c478bd9Sstevel@tonic-gate 	fdc->c_csb.csb_nwin = 0;
34547c478bd9Sstevel@tonic-gate 	fdc->c_csb.csb_windex = 0;
34557c478bd9Sstevel@tonic-gate 	fdc->c_csb.csb_ccount = 0;
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate 	res = ddi_dma_addr_bind_handle(fdc->c_dmahandle, NULL, addr, len,
34587c478bd9Sstevel@tonic-gate 	    flags, DDI_DMA_DONTWAIT, 0,  &fdc->c_csb.csb_dmacookie,
34597c478bd9Sstevel@tonic-gate 	    &fdc->c_csb.csb_ccount);
34607c478bd9Sstevel@tonic-gate 
34617c478bd9Sstevel@tonic-gate 	switch (res) {
34627c478bd9Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
34637c478bd9Sstevel@tonic-gate 			/*
34647c478bd9Sstevel@tonic-gate 			 * There is one window. csb_windex is the index
34657c478bd9Sstevel@tonic-gate 			 * into the array of windows. If there are n
34667c478bd9Sstevel@tonic-gate 			 * windows then, (0 <= windex <= n-1).  csb_windex
34677c478bd9Sstevel@tonic-gate 			 * represents the index of the next window
34687c478bd9Sstevel@tonic-gate 			 * to be processed.
34697c478bd9Sstevel@tonic-gate 			 */
34707c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_nwin = 1;
34717c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_windex = 1;
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate 
34747c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
34757c478bd9Sstevel@tonic-gate 			    (C, "fdstart_dma: DDI_DMA_MAPPED\n"));
34767c478bd9Sstevel@tonic-gate 
34777c478bd9Sstevel@tonic-gate 			break;
34787c478bd9Sstevel@tonic-gate 		case DDI_DMA_PARTIAL_MAP:
34797c478bd9Sstevel@tonic-gate 
34807c478bd9Sstevel@tonic-gate 			/*
34817c478bd9Sstevel@tonic-gate 			 * obtain the number of DMA windows
34827c478bd9Sstevel@tonic-gate 			 */
34837c478bd9Sstevel@tonic-gate 			if (ddi_dma_numwin(fdc->c_dmahandle,
34847c478bd9Sstevel@tonic-gate 			    &fdc->c_csb.csb_nwin) != DDI_SUCCESS) {
34857c478bd9Sstevel@tonic-gate 				return (-1);
34867c478bd9Sstevel@tonic-gate 			}
34877c478bd9Sstevel@tonic-gate 
34887c478bd9Sstevel@tonic-gate 
34897c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
34907c478bd9Sstevel@tonic-gate 			    (C, "fdstart_dma: partially mapped %d windows\n",
34917c478bd9Sstevel@tonic-gate 			    fdc->c_csb.csb_nwin));
34927c478bd9Sstevel@tonic-gate 
34937c478bd9Sstevel@tonic-gate 			/*
34947c478bd9Sstevel@tonic-gate 			 * The DMA window currently in use is window number
34957c478bd9Sstevel@tonic-gate 			 * one.
34967c478bd9Sstevel@tonic-gate 			 */
34977c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_windex = 1;
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 			break;
35007c478bd9Sstevel@tonic-gate 		case DDI_DMA_NORESOURCES:
35017c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35027c478bd9Sstevel@tonic-gate 			    (C, "fdstart_dma: no resources\n"));
35037c478bd9Sstevel@tonic-gate 			return (-1);
35047c478bd9Sstevel@tonic-gate 		case DDI_DMA_NOMAPPING:
35057c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35067c478bd9Sstevel@tonic-gate 			    (C, "fdstart_dma: no mapping\n"));
35077c478bd9Sstevel@tonic-gate 			return (-1);
35087c478bd9Sstevel@tonic-gate 		case DDI_DMA_TOOBIG:
35097c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35107c478bd9Sstevel@tonic-gate 			    (C, "fdstart_dma: too big\n"));
35117c478bd9Sstevel@tonic-gate 			return (-1);
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate 		case DDI_DMA_INUSE:
35147c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35157c478bd9Sstevel@tonic-gate 			    (C, "fdstart_dma: dma inuse\n"));
35167c478bd9Sstevel@tonic-gate 			return (-1);
35177c478bd9Sstevel@tonic-gate 		default:
35187c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
35197c478bd9Sstevel@tonic-gate 			    (C, "fdstart_dma: result is 0x%x\n", res));
35207c478bd9Sstevel@tonic-gate 			return (-1);
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate 	};
35237c478bd9Sstevel@tonic-gate 
35247c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA,
35257c478bd9Sstevel@tonic-gate 	    (C, "fdstart_dma: bound the handle\n"));
35267c478bd9Sstevel@tonic-gate 
35277c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
35287c478bd9Sstevel@tonic-gate 
35297c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: done\n"));
35307c478bd9Sstevel@tonic-gate 	return (0);
35317c478bd9Sstevel@tonic-gate }
35327c478bd9Sstevel@tonic-gate 
35337c478bd9Sstevel@tonic-gate 
35347c478bd9Sstevel@tonic-gate /*
35357c478bd9Sstevel@tonic-gate  * fd_unbind_handle: unbind a dma handle if one exists
35367c478bd9Sstevel@tonic-gate  *		return EIO if unbind failes
35377c478bd9Sstevel@tonic-gate  */
35387c478bd9Sstevel@tonic-gate static int
35397c478bd9Sstevel@tonic-gate fd_unbind_handle(struct fdctlr *fdc)
35407c478bd9Sstevel@tonic-gate {
35417c478bd9Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_DMA) &&
35427c478bd9Sstevel@tonic-gate 	    ((fdc->c_csb.csb_read == CSB_READ) ||
35437c478bd9Sstevel@tonic-gate 	    (fdc->c_csb.csb_read == CSB_WRITE))) {
35447c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
35457c478bd9Sstevel@tonic-gate 
35467c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_SB) {
35477c478bd9Sstevel@tonic-gate 			if (fdc->sb_dma_lock) {
35487c478bd9Sstevel@tonic-gate 				release_sb_dma(fdc);
35497c478bd9Sstevel@tonic-gate 			}
35507c478bd9Sstevel@tonic-gate 		}
35517c478bd9Sstevel@tonic-gate 
35527c478bd9Sstevel@tonic-gate 		/*
35537c478bd9Sstevel@tonic-gate 		 * If the byte count isn't zero, then the DMA engine is
35547c478bd9Sstevel@tonic-gate 		 * still doing a transfer.  If the byte count is nonzero,
35557c478bd9Sstevel@tonic-gate 		 * reset the DMA engine to cause it to drain.
35567c478bd9Sstevel@tonic-gate 		 */
35577c478bd9Sstevel@tonic-gate 
35587c478bd9Sstevel@tonic-gate 		if (get_data_count_register(fdc) != 0) {
35597c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_EXEC,
35607c478bd9Sstevel@tonic-gate 			    (C, "unbind & byte count isn't zero\n"));
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate 			reset_dma_controller(fdc);
35637c478bd9Sstevel@tonic-gate 			set_dma_control_register(fdc, DCSR_INIT_BITS);
35647c478bd9Sstevel@tonic-gate 		}
35657c478bd9Sstevel@tonic-gate 
35667c478bd9Sstevel@tonic-gate 		if (ddi_dma_unbind_handle(fdc->c_dmahandle) != DDI_SUCCESS) {
35677c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_EXEC,
35687c478bd9Sstevel@tonic-gate 			    (C, "problem unbinding the handle\n"));
35697c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
35707c478bd9Sstevel@tonic-gate 			return (EIO);
35717c478bd9Sstevel@tonic-gate 		}
35727c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
35737c478bd9Sstevel@tonic-gate 	}
35747c478bd9Sstevel@tonic-gate 	return (0);
35757c478bd9Sstevel@tonic-gate }
35767c478bd9Sstevel@tonic-gate 
35777c478bd9Sstevel@tonic-gate /*
35787c478bd9Sstevel@tonic-gate  * fdexec
35797c478bd9Sstevel@tonic-gate  *	all commands go through here.  Assumes the command block
35807c478bd9Sstevel@tonic-gate  *	fdctlr.c_csb is filled in.  The bytes are sent to the
35817c478bd9Sstevel@tonic-gate  *	controller and then we do whatever else the csb says -
35827c478bd9Sstevel@tonic-gate  *	like wait for immediate results, etc.
35837c478bd9Sstevel@tonic-gate  *
35847c478bd9Sstevel@tonic-gate  *	All waiting for operations done is in here - to allow retrys
35857c478bd9Sstevel@tonic-gate  *	and checking for disk changed - so we don't have to worry
35867c478bd9Sstevel@tonic-gate  *	about sleeping at interrupt level.
35877c478bd9Sstevel@tonic-gate  *
35887c478bd9Sstevel@tonic-gate  * RETURNS: 0 if all ok,
35897c478bd9Sstevel@tonic-gate  *	ENXIO - diskette not in drive
35907c478bd9Sstevel@tonic-gate  *	EBUSY - if chip is locked or busy
35917c478bd9Sstevel@tonic-gate  *	EIO - for timeout during sending cmds to chip
35927c478bd9Sstevel@tonic-gate  *
35937c478bd9Sstevel@tonic-gate  * to sleep: set FDXC_SLEEP, to check for disk
35947c478bd9Sstevel@tonic-gate  * changed: set FDXC_CHECKCHG
35957c478bd9Sstevel@tonic-gate  *
35967c478bd9Sstevel@tonic-gate  *	- called with the lock held
35977c478bd9Sstevel@tonic-gate  */
35987c478bd9Sstevel@tonic-gate static int
35997c478bd9Sstevel@tonic-gate fdexec(struct fdctlr *fdc, int flags)
36007c478bd9Sstevel@tonic-gate {
36017c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
36027c478bd9Sstevel@tonic-gate 	int	i;
36037c478bd9Sstevel@tonic-gate 	int	to, unit;
36047c478bd9Sstevel@tonic-gate 	uchar_t	tmp;
36057c478bd9Sstevel@tonic-gate 	caddr_t a = (caddr_t)fdc;
36067c478bd9Sstevel@tonic-gate 
36077c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: flags:%x\n", flags));
36087c478bd9Sstevel@tonic-gate 
36097c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
36107c478bd9Sstevel@tonic-gate 
36117c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
36127c478bd9Sstevel@tonic-gate 	unit = csb->csb_unit;
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate 
36157c478bd9Sstevel@tonic-gate 	ASSERT(unit == fdc->c_un->un_unit_no);
36167c478bd9Sstevel@tonic-gate 
36177c478bd9Sstevel@tonic-gate retry:
36187c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: cmd is %s\n",
36197c478bd9Sstevel@tonic-gate 	    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
36207c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: transfer rate = %d\n",
36217c478bd9Sstevel@tonic-gate 	    fdc->c_un->un_chars->fdc_transfer_rate));
36227c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: sec size = %d\n",
36237c478bd9Sstevel@tonic-gate 	    fdc->c_un->un_chars->fdc_sec_size));
36247c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: nblocks (512) = %d\n",
36257c478bd9Sstevel@tonic-gate 	    fdc->c_un->un_label.dkl_map[2].dkl_nblk));
36267c478bd9Sstevel@tonic-gate 
36277c478bd9Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
36287c478bd9Sstevel@tonic-gate 		fdexec_turn_on_motor(fdc, flags, unit);
36297c478bd9Sstevel@tonic-gate 	}
36307c478bd9Sstevel@tonic-gate 
36317c478bd9Sstevel@tonic-gate 
36327c478bd9Sstevel@tonic-gate 	fdselect(fdc, unit, 1);	/* select drive */
36337c478bd9Sstevel@tonic-gate 
36347c478bd9Sstevel@tonic-gate 	/*
36357c478bd9Sstevel@tonic-gate 	 * select data rate for this unit/command
36367c478bd9Sstevel@tonic-gate 	 */
36377c478bd9Sstevel@tonic-gate 	switch (fdc->c_un->un_chars->fdc_transfer_rate) {
36387c478bd9Sstevel@tonic-gate 	case 500:
36397c478bd9Sstevel@tonic-gate 		Dsr(fdc, 0);
36407c478bd9Sstevel@tonic-gate 		break;
36417c478bd9Sstevel@tonic-gate 	case 300:
36427c478bd9Sstevel@tonic-gate 		Dsr(fdc, 1);
36437c478bd9Sstevel@tonic-gate 		break;
36447c478bd9Sstevel@tonic-gate 	case 250:
36457c478bd9Sstevel@tonic-gate 		Dsr(fdc, 2);
36467c478bd9Sstevel@tonic-gate 		break;
36477c478bd9Sstevel@tonic-gate 	}
36487c478bd9Sstevel@tonic-gate 	drv_usecwait(2);
36497c478bd9Sstevel@tonic-gate 
36507c478bd9Sstevel@tonic-gate 
36517c478bd9Sstevel@tonic-gate 	/*
36527c478bd9Sstevel@tonic-gate 	 * If checking for changed is enabled (i.e., not seeking in checkdisk),
36537c478bd9Sstevel@tonic-gate 	 * we sample the DSKCHG line to see if the diskette has wandered away.
36547c478bd9Sstevel@tonic-gate 	 */
36557c478bd9Sstevel@tonic-gate 	if ((flags & FDXC_CHECKCHG) && fdsense_chng(fdc, unit)) {
36567c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "diskette changed\n"));
36577c478bd9Sstevel@tonic-gate 		fdc->c_un->un_flags |= FDUNIT_CHANGED;
36587c478bd9Sstevel@tonic-gate 
36597c478bd9Sstevel@tonic-gate 		if (fdcheckdisk(fdc, unit)) {
36607c478bd9Sstevel@tonic-gate 
36617c478bd9Sstevel@tonic-gate 			(void) fd_unbind_handle(fdc);
36627c478bd9Sstevel@tonic-gate 			return (ENXIO);
36637c478bd9Sstevel@tonic-gate 
36647c478bd9Sstevel@tonic-gate 		}
36657c478bd9Sstevel@tonic-gate 	}
36667c478bd9Sstevel@tonic-gate 
36677c478bd9Sstevel@tonic-gate 	/*
36687c478bd9Sstevel@tonic-gate 	 * gather some statistics
36697c478bd9Sstevel@tonic-gate 	 */
36707c478bd9Sstevel@tonic-gate 	switch (csb->csb_cmds[0] & 0x1f) {
36717c478bd9Sstevel@tonic-gate 	case FDRAW_RDCMD:
36727c478bd9Sstevel@tonic-gate 		fdc->fdstats.rd++;
36737c478bd9Sstevel@tonic-gate 		break;
36747c478bd9Sstevel@tonic-gate 	case FDRAW_WRCMD:
36757c478bd9Sstevel@tonic-gate 		fdc->fdstats.wr++;
36767c478bd9Sstevel@tonic-gate 		break;
36777c478bd9Sstevel@tonic-gate 	case FDRAW_REZERO:
36787c478bd9Sstevel@tonic-gate 		fdc->fdstats.recal++;
36797c478bd9Sstevel@tonic-gate 		break;
36807c478bd9Sstevel@tonic-gate 	case FDRAW_FORMAT:
36817c478bd9Sstevel@tonic-gate 		fdc->fdstats.form++;
36827c478bd9Sstevel@tonic-gate 		break;
36837c478bd9Sstevel@tonic-gate 	default:
36847c478bd9Sstevel@tonic-gate 		fdc->fdstats.other++;
36857c478bd9Sstevel@tonic-gate 		break;
36867c478bd9Sstevel@tonic-gate 	}
36877c478bd9Sstevel@tonic-gate 
36887c478bd9Sstevel@tonic-gate 	/*
36897c478bd9Sstevel@tonic-gate 	 * Always set the opmode *prior* to poking the chip.
36907c478bd9Sstevel@tonic-gate 	 * This way we don't have to do any locking at high level.
36917c478bd9Sstevel@tonic-gate 	 */
36927c478bd9Sstevel@tonic-gate 	csb->csb_raddr = 0;
36937c478bd9Sstevel@tonic-gate 	csb->csb_rlen = 0;
36947c478bd9Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFSEEKOPS) {
36957c478bd9Sstevel@tonic-gate 		csb->csb_opmode = 2;
36967c478bd9Sstevel@tonic-gate 	} else if (csb->csb_opflags & CSB_OFIMMEDIATE) {
36977c478bd9Sstevel@tonic-gate 		csb->csb_opmode = 0;
36987c478bd9Sstevel@tonic-gate 	} else {
36997c478bd9Sstevel@tonic-gate 		csb->csb_opmode = 1;	/* normal data xfer commands */
37007c478bd9Sstevel@tonic-gate 		csb->csb_raddr = csb->csb_addr;
37017c478bd9Sstevel@tonic-gate 		csb->csb_rlen = csb->csb_len;
37027c478bd9Sstevel@tonic-gate 	}
37037c478bd9Sstevel@tonic-gate 
37047c478bd9Sstevel@tonic-gate 	bzero((caddr_t)csb->csb_rslt, 10);
37057c478bd9Sstevel@tonic-gate 	csb->csb_status = 0;
37067c478bd9Sstevel@tonic-gate 	csb->csb_cmdstat = 0;
37077c478bd9Sstevel@tonic-gate 
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate 	/*
37107c478bd9Sstevel@tonic-gate 	 * Program the DMA engine with the length and address of the transfer
37117c478bd9Sstevel@tonic-gate 	 * (DMA is only used on a read or a write)
37127c478bd9Sstevel@tonic-gate 	 */
37137c478bd9Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_DMA) &&
37147c478bd9Sstevel@tonic-gate 	    ((fdc->c_csb.csb_read == CSB_READ) ||
37157c478bd9Sstevel@tonic-gate 	    (fdc->c_csb.csb_read == CSB_WRITE)))  {
37167c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 		/* Reset the dcsr to clear it of all errors */
37197c478bd9Sstevel@tonic-gate 
37207c478bd9Sstevel@tonic-gate 		reset_dma_controller(fdc);
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie addr 0x%p\n",
37237c478bd9Sstevel@tonic-gate 		    (void *)fdc->c_csb.csb_dmacookie.dmac_laddress));
37247c478bd9Sstevel@tonic-gate 
37257c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie length %ld\n",
37267c478bd9Sstevel@tonic-gate 		    fdc->c_csb.csb_dmacookie.dmac_size));
37277c478bd9Sstevel@tonic-gate 		ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
37287c478bd9Sstevel@tonic-gate 
37297c478bd9Sstevel@tonic-gate 		set_data_count_register(fdc,
37307c478bd9Sstevel@tonic-gate 		    fdc->c_csb.csb_dmacookie.dmac_size);
37317c478bd9Sstevel@tonic-gate 		set_data_address_register(fdc,
37327c478bd9Sstevel@tonic-gate 		    fdc->c_csb.csb_dmacookie.dmac_laddress);
37337c478bd9Sstevel@tonic-gate 
37347c478bd9Sstevel@tonic-gate 		/* Program the DCSR */
37357c478bd9Sstevel@tonic-gate 
37367c478bd9Sstevel@tonic-gate 		if (fdc->c_csb.csb_read == CSB_READ)
37377c478bd9Sstevel@tonic-gate 			set_dma_mode(fdc, CSB_READ);
37387c478bd9Sstevel@tonic-gate 		else
37397c478bd9Sstevel@tonic-gate 			set_dma_mode(fdc, CSB_WRITE);
37407c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
37417c478bd9Sstevel@tonic-gate 	}
37427c478bd9Sstevel@tonic-gate 
37437c478bd9Sstevel@tonic-gate 	/*
37447c478bd9Sstevel@tonic-gate 	 * I saw this (chip unexpectedly busy) happen when i shoved the
37457c478bd9Sstevel@tonic-gate 	 * floppy into the drive while
37467c478bd9Sstevel@tonic-gate 	 * running a dd if= /dev/rfd0c.	so it *is* possible for this to happen.
37477c478bd9Sstevel@tonic-gate 	 * we need to do a ctlr reset ...
37487c478bd9Sstevel@tonic-gate 	 */
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate 	if (Msr(fdc) & CB) {
37517c478bd9Sstevel@tonic-gate 		/* tried to give command to chip when it is busy! */
37527c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_EXEC,
37537c478bd9Sstevel@tonic-gate 		    (C, "fdc: unexpectedly busy-stat 0x%x\n", Msr(fdc)));
37547c478bd9Sstevel@tonic-gate 		csb->csb_cmdstat = 1;	/* XXX TBD ERRS NYD for now */
37557c478bd9Sstevel@tonic-gate 
37567c478bd9Sstevel@tonic-gate 		(void) fd_unbind_handle(fdc);
37577c478bd9Sstevel@tonic-gate 		return (EBUSY);
37587c478bd9Sstevel@tonic-gate 	}
37597c478bd9Sstevel@tonic-gate 
37607c478bd9Sstevel@tonic-gate 	/* Give command to the controller */
37617c478bd9Sstevel@tonic-gate 	for (i = 0; i < (int)csb->csb_ncmds; i++) {
37627c478bd9Sstevel@tonic-gate 
37637c478bd9Sstevel@tonic-gate 		/* Test the readiness of the controller to receive the cmd */
37647c478bd9Sstevel@tonic-gate 		for (to = FD_CRETRY; to; to--) {
37657c478bd9Sstevel@tonic-gate 			if ((Msr(fdc) & (DIO|RQM)) == RQM)
37667c478bd9Sstevel@tonic-gate 				break;
37677c478bd9Sstevel@tonic-gate 		}
37687c478bd9Sstevel@tonic-gate 		if (to == 0) {
37697c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L2, FDEM_EXEC,
37707c478bd9Sstevel@tonic-gate 			    (C, "fdc: no RQM - stat 0x%x\n", Msr(fdc)));
37717c478bd9Sstevel@tonic-gate 			csb->csb_cmdstat = 1;
37727c478bd9Sstevel@tonic-gate 
37737c478bd9Sstevel@tonic-gate 			(void) fd_unbind_handle(fdc);
37747c478bd9Sstevel@tonic-gate 			return (EIO);
37757c478bd9Sstevel@tonic-gate 		}
37767c478bd9Sstevel@tonic-gate 
37777c478bd9Sstevel@tonic-gate 		Set_Fifo(fdc, csb->csb_cmds[i]);
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC,
37807c478bd9Sstevel@tonic-gate 		    (C, "fdexec: sent 0x%x, Msr 0x%x\n", csb->csb_cmds[i],
37817c478bd9Sstevel@tonic-gate 		    Msr(fdc)));
37827c478bd9Sstevel@tonic-gate 
37837c478bd9Sstevel@tonic-gate 	}
37847c478bd9Sstevel@tonic-gate 
37857c478bd9Sstevel@tonic-gate 
37867c478bd9Sstevel@tonic-gate 	/*
37877c478bd9Sstevel@tonic-gate 	 * Start watchdog timer on data transfer type commands - required
37887c478bd9Sstevel@tonic-gate 	 * in case a diskette is not present or is unformatted
37897c478bd9Sstevel@tonic-gate 	 */
37907c478bd9Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFTIMEIT) {
37917c478bd9Sstevel@tonic-gate 		fdc->c_timeid = timeout(fdwatch, a,
37927c478bd9Sstevel@tonic-gate 		    tosec * drv_usectohz(1000000));
37937c478bd9Sstevel@tonic-gate 	}
37947c478bd9Sstevel@tonic-gate 
37957c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC,
37967c478bd9Sstevel@tonic-gate 	    (C, "fdexec: cmd sent, Msr 0x%x\n", Msr(fdc)));
37977c478bd9Sstevel@tonic-gate 
37987c478bd9Sstevel@tonic-gate 	/* If the operation has no results - then just return */
37997c478bd9Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFNORESULTS) {
38007c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_82077) {
38017c478bd9Sstevel@tonic-gate 			if (fdc->c_mtimeid == 0) {
38027c478bd9Sstevel@tonic-gate 				fdc->c_mtimeid = timeout(fdmotoff, a,
38037c478bd9Sstevel@tonic-gate 				    Motoff_delay);
38047c478bd9Sstevel@tonic-gate 			}
38057c478bd9Sstevel@tonic-gate 		}
38067c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..\n"));
38077c478bd9Sstevel@tonic-gate 
38087c478bd9Sstevel@tonic-gate 		/*
38097c478bd9Sstevel@tonic-gate 		 * Make sure the last byte is received well by the
38107c478bd9Sstevel@tonic-gate 		 * controller. On faster CPU, it may still be busy
38117c478bd9Sstevel@tonic-gate 		 * by the time another command comes here.
38127c478bd9Sstevel@tonic-gate 		 */
38137c478bd9Sstevel@tonic-gate 		for (to = FD_CRETRY; to; to--) {
38147c478bd9Sstevel@tonic-gate 			if ((Msr(fdc) & (DIO|RQM)) == RQM)
38157c478bd9Sstevel@tonic-gate 				break;
38167c478bd9Sstevel@tonic-gate 			}
38177c478bd9Sstevel@tonic-gate 		if (to == 0) {
38187c478bd9Sstevel@tonic-gate 			csb->csb_cmdstat = 1;
38197c478bd9Sstevel@tonic-gate 			return (EIO);
38207c478bd9Sstevel@tonic-gate 		}
38217c478bd9Sstevel@tonic-gate 
38227c478bd9Sstevel@tonic-gate 		/*
38237c478bd9Sstevel@tonic-gate 		 * An operation that has no results isn't doing DMA so,
38247c478bd9Sstevel@tonic-gate 		 * there is no reason to try to unbind a handle
38257c478bd9Sstevel@tonic-gate 		 */
38267c478bd9Sstevel@tonic-gate 		return (0);
38277c478bd9Sstevel@tonic-gate 	}
38287c478bd9Sstevel@tonic-gate 
38297c478bd9Sstevel@tonic-gate 	/*
38307c478bd9Sstevel@tonic-gate 	 * If this operation has no interrupt AND an immediate result
38317c478bd9Sstevel@tonic-gate 	 * then we just busy wait for the results and stuff them into
38327c478bd9Sstevel@tonic-gate 	 * the csb
38337c478bd9Sstevel@tonic-gate 	 */
38347c478bd9Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFIMMEDIATE) {
38357c478bd9Sstevel@tonic-gate 		to = FD_RRETRY;
38367c478bd9Sstevel@tonic-gate 		csb->csb_nrslts = 0;
38377c478bd9Sstevel@tonic-gate 		/*
38387c478bd9Sstevel@tonic-gate 		 * Wait while this command is still going on.
38397c478bd9Sstevel@tonic-gate 		 */
38407c478bd9Sstevel@tonic-gate 		while ((tmp = Msr(fdc)) & CB) {
38417c478bd9Sstevel@tonic-gate 			/*
38427c478bd9Sstevel@tonic-gate 			 * If RQM + DIO, then a result byte is at hand.
38437c478bd9Sstevel@tonic-gate 			 */
38447c478bd9Sstevel@tonic-gate 			if ((tmp & (RQM|DIO|CB)) == (RQM|DIO|CB)) {
38457c478bd9Sstevel@tonic-gate 				csb->csb_rslt[csb->csb_nrslts++] =
38467c478bd9Sstevel@tonic-gate 				    Fifo(fdc);
38477c478bd9Sstevel@tonic-gate 				/*
38487c478bd9Sstevel@tonic-gate 				 * FDERRPRINT(FDEP_L4, FDEM_EXEC,
38497c478bd9Sstevel@tonic-gate 				 *    (C, "fdexec: got result 0x%x\n",
38507c478bd9Sstevel@tonic-gate 				 *    csb->csb_nrslts));
38517c478bd9Sstevel@tonic-gate 				 */
38527c478bd9Sstevel@tonic-gate 			} else if (--to == 0) {
38537c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L4, FDEM_EXEC,
38547c478bd9Sstevel@tonic-gate 				    (C, "fdexec: timeout, Msr%x, nr%x\n",
38557c478bd9Sstevel@tonic-gate 				    Msr(fdc), csb->csb_nrslts));
38567c478bd9Sstevel@tonic-gate 
38577c478bd9Sstevel@tonic-gate 				csb->csb_status = 2;
38587c478bd9Sstevel@tonic-gate 				if (fdc->c_fdtype & FDCTYPE_82077) {
38597c478bd9Sstevel@tonic-gate 					if (fdc->c_mtimeid == 0) {
38607c478bd9Sstevel@tonic-gate 						fdc->c_mtimeid = timeout(
38617c478bd9Sstevel@tonic-gate 						    fdmotoff, a, Motoff_delay);
38627c478bd9Sstevel@tonic-gate 					}
38637c478bd9Sstevel@tonic-gate 				}
38647c478bd9Sstevel@tonic-gate 				/*
38657c478bd9Sstevel@tonic-gate 				 * There is no DMA happening.  No need to
38667c478bd9Sstevel@tonic-gate 				 * try freeing a handle.
38677c478bd9Sstevel@tonic-gate 				 */
38687c478bd9Sstevel@tonic-gate 
38697c478bd9Sstevel@tonic-gate 				return (EIO);
38707c478bd9Sstevel@tonic-gate 			}
38717c478bd9Sstevel@tonic-gate 		}
38727c478bd9Sstevel@tonic-gate 	}
38737c478bd9Sstevel@tonic-gate 
38747c478bd9Sstevel@tonic-gate 	/*
38757c478bd9Sstevel@tonic-gate 	 * If told to sleep here, well then sleep!
38767c478bd9Sstevel@tonic-gate 	 */
38777c478bd9Sstevel@tonic-gate 
38787c478bd9Sstevel@tonic-gate 	if (flags & FDXC_SLEEP) {
38797c478bd9Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WAITING;
38807c478bd9Sstevel@tonic-gate 		while (fdc->c_flags & FDCFLG_WAITING) {
38817c478bd9Sstevel@tonic-gate 			cv_wait(&fdc->c_iocv, &fdc->c_lolock);
38827c478bd9Sstevel@tonic-gate 		}
38837c478bd9Sstevel@tonic-gate 	}
38847c478bd9Sstevel@tonic-gate 
38857c478bd9Sstevel@tonic-gate 	/*
38867c478bd9Sstevel@tonic-gate 	 * kludge for end-of-cylinder error which must be ignored!!!
38877c478bd9Sstevel@tonic-gate 	 */
38887c478bd9Sstevel@tonic-gate 
38897c478bd9Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
38907c478bd9Sstevel@tonic-gate 	    ((csb->csb_rslt[0] & IC_SR0) == 0x40) &&
38917c478bd9Sstevel@tonic-gate 	    (csb->csb_rslt[1] & EN_SR1))
38927c478bd9Sstevel@tonic-gate 		csb->csb_rslt[0] &= ~IC_SR0;
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	/*
38957c478bd9Sstevel@tonic-gate 	 * See if there was an error detected, if so, fdrecover()
38967c478bd9Sstevel@tonic-gate 	 * will check it out and say what to do.
38977c478bd9Sstevel@tonic-gate 	 *
38987c478bd9Sstevel@tonic-gate 	 * Don't do this, though, if this was the Sense Drive Status
38997c478bd9Sstevel@tonic-gate 	 * or the Dump Registers command.
39007c478bd9Sstevel@tonic-gate 	 */
39017c478bd9Sstevel@tonic-gate 	if (((csb->csb_rslt[0] & IC_SR0) || (fdc->c_csb.csb_dcsr_rslt) ||
39027c478bd9Sstevel@tonic-gate 	    (csb->csb_status)) &&
39037c478bd9Sstevel@tonic-gate 	    ((csb->csb_cmds[0] != FDRAW_SENSE_DRV) &&
39047c478bd9Sstevel@tonic-gate 	    (csb->csb_cmds[0] != DUMPREG))) {
39057c478bd9Sstevel@tonic-gate 		/* if it can restarted OK, then do so, else return error */
39067c478bd9Sstevel@tonic-gate 		if (fdrecover(fdc) != 0) {
39077c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_82077) {
39087c478bd9Sstevel@tonic-gate 				if (fdc->c_mtimeid == 0) {
39097c478bd9Sstevel@tonic-gate 					fdc->c_mtimeid = timeout(fdmotoff,
39107c478bd9Sstevel@tonic-gate 					    a, Motoff_delay);
39117c478bd9Sstevel@tonic-gate 				}
39127c478bd9Sstevel@tonic-gate 			}
39137c478bd9Sstevel@tonic-gate 
39147c478bd9Sstevel@tonic-gate 			/*
39157c478bd9Sstevel@tonic-gate 			 * If this was a dma transfer, unbind the handle so
39167c478bd9Sstevel@tonic-gate 			 * that other transfers may use it.
39177c478bd9Sstevel@tonic-gate 			 */
39187c478bd9Sstevel@tonic-gate 
39197c478bd9Sstevel@tonic-gate 			(void) fd_unbind_handle(fdc);
39207c478bd9Sstevel@tonic-gate 			return (EIO);
39217c478bd9Sstevel@tonic-gate 		} else {
39227c478bd9Sstevel@tonic-gate 			/* ASSUMES that cmd is still intact in csb */
39237c478bd9Sstevel@tonic-gate 			goto retry;
39247c478bd9Sstevel@tonic-gate 		}
39257c478bd9Sstevel@tonic-gate 	}
39267c478bd9Sstevel@tonic-gate 
39277c478bd9Sstevel@tonic-gate 	/* things went ok */
39287c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_82077) {
39297c478bd9Sstevel@tonic-gate 		if (fdc->c_mtimeid == 0) {
39307c478bd9Sstevel@tonic-gate 			fdc->c_mtimeid = timeout(fdmotoff, a, Motoff_delay);
39317c478bd9Sstevel@tonic-gate 		}
39327c478bd9Sstevel@tonic-gate 	}
39337c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..........\n"));
39347c478bd9Sstevel@tonic-gate 
39357c478bd9Sstevel@tonic-gate 	if (fd_unbind_handle(fdc))
39367c478bd9Sstevel@tonic-gate 		return (EIO);
39377c478bd9Sstevel@tonic-gate 
39387c478bd9Sstevel@tonic-gate 	return (0);
39397c478bd9Sstevel@tonic-gate }
39407c478bd9Sstevel@tonic-gate 
39417c478bd9Sstevel@tonic-gate /*
39427c478bd9Sstevel@tonic-gate  * Turn on the drive's motor
39437c478bd9Sstevel@tonic-gate  *
39447c478bd9Sstevel@tonic-gate  *	- called with the low level lock held
39457c478bd9Sstevel@tonic-gate  */
39467c478bd9Sstevel@tonic-gate static void
39477c478bd9Sstevel@tonic-gate fdexec_turn_on_motor(struct fdctlr *fdc, int flags,  uint_t unit)
39487c478bd9Sstevel@tonic-gate {
39497c478bd9Sstevel@tonic-gate 	clock_t local_lbolt;
39507c478bd9Sstevel@tonic-gate 	timeout_id_t timeid;
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate 	/*
39537c478bd9Sstevel@tonic-gate 	 * The low level mutex may not be held over the call to
39547c478bd9Sstevel@tonic-gate 	 * untimeout().  See the manpage for details.
39557c478bd9Sstevel@tonic-gate 	 */
39567c478bd9Sstevel@tonic-gate 	timeid = fdc->c_mtimeid;
39577c478bd9Sstevel@tonic-gate 	fdc->c_mtimeid = 0;
39587c478bd9Sstevel@tonic-gate 	if (timeid) {
39597c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
39607c478bd9Sstevel@tonic-gate 		(void) untimeout(timeid);
39617c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
39627c478bd9Sstevel@tonic-gate 	}
39637c478bd9Sstevel@tonic-gate 
39647c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
39657c478bd9Sstevel@tonic-gate 
39667c478bd9Sstevel@tonic-gate 
39677c478bd9Sstevel@tonic-gate 	set_rotational_speed(fdc, unit);
39687c478bd9Sstevel@tonic-gate 
39697c478bd9Sstevel@tonic-gate 	if (!(Dor(fdc) & (MOTEN(unit)))) {
39707c478bd9Sstevel@tonic-gate 		/*
39717c478bd9Sstevel@tonic-gate 		 * Turn on the motor
39727c478bd9Sstevel@tonic-gate 		 */
39737c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC,
39747c478bd9Sstevel@tonic-gate 		    (C, "fdexec: turning on motor\n"));
39757c478bd9Sstevel@tonic-gate 
39767c478bd9Sstevel@tonic-gate 		/* LINTED */
39777c478bd9Sstevel@tonic-gate 		Set_dor(fdc, (MOTEN(unit)), 1);
39787c478bd9Sstevel@tonic-gate 
39797c478bd9Sstevel@tonic-gate 		if (flags & FDXC_SLEEP) {
39807c478bd9Sstevel@tonic-gate 			local_lbolt = ddi_get_lbolt();
39817c478bd9Sstevel@tonic-gate 			(void) cv_timedwait(&fdc->c_motoncv,
39827c478bd9Sstevel@tonic-gate 			    &fdc->c_lolock, local_lbolt + Moton_delay);
39837c478bd9Sstevel@tonic-gate 		} else {
39847c478bd9Sstevel@tonic-gate 			drv_usecwait(1000000);
39857c478bd9Sstevel@tonic-gate 		}
39867c478bd9Sstevel@tonic-gate 	}
39877c478bd9Sstevel@tonic-gate 
39887c478bd9Sstevel@tonic-gate }
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate /*
39917c478bd9Sstevel@tonic-gate  * fdrecover
39927c478bd9Sstevel@tonic-gate  *	see if possible to retry an operation.
39937c478bd9Sstevel@tonic-gate  *	All we can do is restart the operation.	 If we are out of allowed
39947c478bd9Sstevel@tonic-gate  *	retries - return non-zero so that the higher levels will be notified.
39957c478bd9Sstevel@tonic-gate  *
39967c478bd9Sstevel@tonic-gate  * RETURNS: 0 if ok to restart, !0 if can't or out of retries
39977c478bd9Sstevel@tonic-gate  *	- called with the low level lock held
39987c478bd9Sstevel@tonic-gate  */
39997c478bd9Sstevel@tonic-gate static int
40007c478bd9Sstevel@tonic-gate fdrecover(struct fdctlr *fdc)
40017c478bd9Sstevel@tonic-gate {
40027c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
40037c478bd9Sstevel@tonic-gate 
40047c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdrecover\n"));
40057c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
40067c478bd9Sstevel@tonic-gate 
40077c478bd9Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_TIMEDOUT) {
40087c478bd9Sstevel@tonic-gate 		struct fdcsb savecsb;
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate 		fdc->c_flags ^= FDCFLG_TIMEDOUT;
40117c478bd9Sstevel@tonic-gate 		csb->csb_rslt[1] |= TO_SR1;
40127c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RECO,
40137c478bd9Sstevel@tonic-gate 		    (C, "fd%d: %s timed out\n", csb->csb_unit,
40147c478bd9Sstevel@tonic-gate 		    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
40157c478bd9Sstevel@tonic-gate 
40167c478bd9Sstevel@tonic-gate 		/* use private csb */
40177c478bd9Sstevel@tonic-gate 		savecsb = fdc->c_csb;
40187c478bd9Sstevel@tonic-gate 		bzero(&fdc->c_csb, sizeof (struct fdcsb));
40197c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdc: resetting\n"));
40207c478bd9Sstevel@tonic-gate 
40217c478bd9Sstevel@tonic-gate 		(void) fdreset(fdc);
40227c478bd9Sstevel@tonic-gate 
40237c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_DMA) {
40247c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_hilock);
40257c478bd9Sstevel@tonic-gate 			/* Reset the DMA engine as well */
40267c478bd9Sstevel@tonic-gate 			reset_dma_controller(fdc);
40277c478bd9Sstevel@tonic-gate 			set_dma_control_register(fdc, DCSR_INIT_BITS);
40287c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
40297c478bd9Sstevel@tonic-gate 		}
40307c478bd9Sstevel@tonic-gate 
40317c478bd9Sstevel@tonic-gate 
40327c478bd9Sstevel@tonic-gate 		/* check change first?? */
40337c478bd9Sstevel@tonic-gate 		/* don't ckchg in fdexec, too convoluted */
40347c478bd9Sstevel@tonic-gate 		(void) fdrecalseek(fdc, savecsb.csb_unit, -1, 0);
40357c478bd9Sstevel@tonic-gate 		fdc->c_csb = savecsb; /* restore original csb */
40367c478bd9Sstevel@tonic-gate 	}
40377c478bd9Sstevel@tonic-gate 
40387c478bd9Sstevel@tonic-gate 	/*
40397c478bd9Sstevel@tonic-gate 	 * gather statistics on errors
40407c478bd9Sstevel@tonic-gate 	 */
40417c478bd9Sstevel@tonic-gate 	if (csb->csb_rslt[1] & DE_SR1) {
40427c478bd9Sstevel@tonic-gate 		fdc->fdstats.de++;
40437c478bd9Sstevel@tonic-gate 	}
40447c478bd9Sstevel@tonic-gate 	if (csb->csb_rslt[1] & OR_SR1) {
40457c478bd9Sstevel@tonic-gate 		fdc->fdstats.run++;
40467c478bd9Sstevel@tonic-gate 	}
40477c478bd9Sstevel@tonic-gate 	if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
40487c478bd9Sstevel@tonic-gate 		fdc->fdstats.bfmt++;
40497c478bd9Sstevel@tonic-gate 	}
40507c478bd9Sstevel@tonic-gate 	if (csb->csb_rslt[1] & TO_SR1) {
40517c478bd9Sstevel@tonic-gate 		fdc->fdstats.to++;
40527c478bd9Sstevel@tonic-gate 	}
40537c478bd9Sstevel@tonic-gate 
40547c478bd9Sstevel@tonic-gate 	/*
40557c478bd9Sstevel@tonic-gate 	 * If raw ioctl don't examine results just pass status
40567c478bd9Sstevel@tonic-gate 	 * back via fdraw. Raw commands are timed too, so put this
40577c478bd9Sstevel@tonic-gate 	 * after the above check.
40587c478bd9Sstevel@tonic-gate 	 */
40597c478bd9Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFRAWIOCTL) {
40607c478bd9Sstevel@tonic-gate 		return (1);
40617c478bd9Sstevel@tonic-gate 	}
40627c478bd9Sstevel@tonic-gate 
40637c478bd9Sstevel@tonic-gate 
40647c478bd9Sstevel@tonic-gate 	/*
40657c478bd9Sstevel@tonic-gate 	 * if there was a pci bus error, do not retry
40667c478bd9Sstevel@tonic-gate 	 */
40677c478bd9Sstevel@tonic-gate 
40687c478bd9Sstevel@tonic-gate 		if (csb->csb_dcsr_rslt == 1) {
40697c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
40707c478bd9Sstevel@tonic-gate 			    (C, "fd%d: host bus error\n", 0));
40717c478bd9Sstevel@tonic-gate 		return (1);
40727c478bd9Sstevel@tonic-gate 		}
40737c478bd9Sstevel@tonic-gate 
40747c478bd9Sstevel@tonic-gate 	/*
40757c478bd9Sstevel@tonic-gate 	 * If there was an error with the DMA functions, do not retry
40767c478bd9Sstevel@tonic-gate 	 */
40777c478bd9Sstevel@tonic-gate 	if (csb->csb_dma_rslt == 1) {
40787c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RECO,
40797c478bd9Sstevel@tonic-gate 			    (C, "fd%d: DMA interface error\n", csb->csb_unit));
40807c478bd9Sstevel@tonic-gate 		return (1);
40817c478bd9Sstevel@tonic-gate 	}
40827c478bd9Sstevel@tonic-gate 
40837c478bd9Sstevel@tonic-gate 
40847c478bd9Sstevel@tonic-gate 	/*
40857c478bd9Sstevel@tonic-gate 	 * if we have run out of retries, return an error
40867c478bd9Sstevel@tonic-gate 	 * XXX need better status interp
40877c478bd9Sstevel@tonic-gate 	 */
40887c478bd9Sstevel@tonic-gate 
40897c478bd9Sstevel@tonic-gate 	csb->csb_retrys++;
40907c478bd9Sstevel@tonic-gate 	if (csb->csb_retrys > csb->csb_maxretry) {
40917c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_RECO,
40927c478bd9Sstevel@tonic-gate 		    (C, "fd%d: %s failed (%x %x %x)\n",
40937c478bd9Sstevel@tonic-gate 		    0, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
40947c478bd9Sstevel@tonic-gate 		    csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
40957c478bd9Sstevel@tonic-gate 		if (csb->csb_rslt[1] & NW_SR1) {
40967c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
40977c478bd9Sstevel@tonic-gate 			    (C, "fd%d: not writable\n", 0));
40987c478bd9Sstevel@tonic-gate 		}
40997c478bd9Sstevel@tonic-gate 		if (csb->csb_rslt[1] & DE_SR1) {
41007c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41017c478bd9Sstevel@tonic-gate 			    (C, "fd%d: crc error blk %d\n", 0,
41027c478bd9Sstevel@tonic-gate 			    (int)fdc->c_current->b_blkno));
41037c478bd9Sstevel@tonic-gate 		}
41047c478bd9Sstevel@tonic-gate 		if (csb->csb_rslt[1] & OR_SR1) {
41057c478bd9Sstevel@tonic-gate 			if (fdc->c_fdtype & FDCTYPE_SB) {
41067c478bd9Sstevel@tonic-gate 				/*
41077c478bd9Sstevel@tonic-gate 				 * When using southbridge chip we need to
41087c478bd9Sstevel@tonic-gate 				 * retry atleast 10 times to shake off the
41097c478bd9Sstevel@tonic-gate 				 * underrun err.
41107c478bd9Sstevel@tonic-gate 				 */
41117c478bd9Sstevel@tonic-gate 				if (csb->csb_retrys <= rwretry)
41127c478bd9Sstevel@tonic-gate 					return (0);
41137c478bd9Sstevel@tonic-gate 			}
41147c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41157c478bd9Sstevel@tonic-gate 			    (C, "fd%d: over/underrun\n", 0));
41167c478bd9Sstevel@tonic-gate 		}
41177c478bd9Sstevel@tonic-gate 
41187c478bd9Sstevel@tonic-gate 		if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
41197c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41207c478bd9Sstevel@tonic-gate 			    (C, "fd%d: bad format\n", 0));
41217c478bd9Sstevel@tonic-gate 		}
41227c478bd9Sstevel@tonic-gate 
41237c478bd9Sstevel@tonic-gate 		if (csb->csb_rslt[1] & TO_SR1) {
41247c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_RECO,
41257c478bd9Sstevel@tonic-gate 			    (C, "fd%d: timeout\n", 0));
41267c478bd9Sstevel@tonic-gate 		}
41277c478bd9Sstevel@tonic-gate 
41287c478bd9Sstevel@tonic-gate 		csb->csb_cmdstat = 1; /* failed - give up */
41297c478bd9Sstevel@tonic-gate 		return (1);
41307c478bd9Sstevel@tonic-gate 	}
41317c478bd9Sstevel@tonic-gate 
41327c478bd9Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFSEEKOPS) {
41337c478bd9Sstevel@tonic-gate 		/* seek, recal type commands - just look at st0 */
41347c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_RECO,
41357c478bd9Sstevel@tonic-gate 		    (C, "fd%d: %s error : st0 0x%x\n", csb->csb_unit,
41367c478bd9Sstevel@tonic-gate 		    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
41377c478bd9Sstevel@tonic-gate 		    csb->csb_rslt[0]));
41387c478bd9Sstevel@tonic-gate 	}
41397c478bd9Sstevel@tonic-gate 	if (csb->csb_opflags & CSB_OFXFEROPS) {
41407c478bd9Sstevel@tonic-gate 		/* rd, wr, fmt type commands - look at st0, st1, st2 */
41417c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_RECO,
41427c478bd9Sstevel@tonic-gate 		    (C, "fd%d: %s error : st0=0x%x st1=0x%x st2=0x%x\n",
41437c478bd9Sstevel@tonic-gate 		    csb->csb_unit, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
41447c478bd9Sstevel@tonic-gate 		    csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
41457c478bd9Sstevel@tonic-gate 	}
41467c478bd9Sstevel@tonic-gate 
41477c478bd9Sstevel@tonic-gate 	return (0);	/* tell fdexec to retry */
41487c478bd9Sstevel@tonic-gate }
41497c478bd9Sstevel@tonic-gate 
41507c478bd9Sstevel@tonic-gate /*
41517c478bd9Sstevel@tonic-gate  * Interrupt handle for DMA
41527c478bd9Sstevel@tonic-gate  */
41537c478bd9Sstevel@tonic-gate 
41547c478bd9Sstevel@tonic-gate static uint_t
41557c478bd9Sstevel@tonic-gate fdintr_dma()
41567c478bd9Sstevel@tonic-gate {
41577c478bd9Sstevel@tonic-gate 	struct fdctlr   *fdc;
41587c478bd9Sstevel@tonic-gate 	off_t		off;
41597c478bd9Sstevel@tonic-gate 	size_t		len;
41607c478bd9Sstevel@tonic-gate 	uint_t		ccount;
41617c478bd9Sstevel@tonic-gate 	uint_t		windex;
41627c478bd9Sstevel@tonic-gate 	uint_t		done = 0;
41637c478bd9Sstevel@tonic-gate 	int		tmp_dcsr;
41647c478bd9Sstevel@tonic-gate 	int		to;
41657c478bd9Sstevel@tonic-gate 	uchar_t		tmp;
41667c478bd9Sstevel@tonic-gate 	int		i = 0;
41677c478bd9Sstevel@tonic-gate 	int		res = DDI_INTR_UNCLAIMED;
41687c478bd9Sstevel@tonic-gate 	int		not_cheerio = 1;
41697c478bd9Sstevel@tonic-gate 
41707c478bd9Sstevel@tonic-gate 	/* search for a controller that's expecting an interrupt */
41717c478bd9Sstevel@tonic-gate 	fdc = fdctlrs;
41727c478bd9Sstevel@tonic-gate 
41737c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
41747c478bd9Sstevel@tonic-gate 		tmp_dcsr = get_dma_control_register(fdc);
41757c478bd9Sstevel@tonic-gate 		if (!(tmp_dcsr & DCSR_INT_PEND) && !(DCSR_ERR_PEND & tmp_dcsr))
41767c478bd9Sstevel@tonic-gate 			return (res);
41777c478bd9Sstevel@tonic-gate 		not_cheerio = 0;
41787c478bd9Sstevel@tonic-gate 	}
41797c478bd9Sstevel@tonic-gate 
41807c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_hilock);
41817c478bd9Sstevel@tonic-gate 
41827c478bd9Sstevel@tonic-gate 	if (fdc->c_csb.csb_opmode == 0x0) {
41837c478bd9Sstevel@tonic-gate 		fdc->c_csb.csb_opmode = 2;
41847c478bd9Sstevel@tonic-gate 	}
41857c478bd9Sstevel@tonic-gate 	if (fdc->sb_dma_lock) {
41867c478bd9Sstevel@tonic-gate 		release_sb_dma(fdc);
41877c478bd9Sstevel@tonic-gate 	}
41887c478bd9Sstevel@tonic-gate 
41897c478bd9Sstevel@tonic-gate 	/*
41907c478bd9Sstevel@tonic-gate 	 * An interrupt can come from either the floppy controller or
41917c478bd9Sstevel@tonic-gate 	 * or the DMA engine.  The DMA engine will only issue an
41927c478bd9Sstevel@tonic-gate 	 * interrupt if there was an error.
41937c478bd9Sstevel@tonic-gate 	 */
41947c478bd9Sstevel@tonic-gate 
41957c478bd9Sstevel@tonic-gate 	switch (fdc->c_csb.csb_opmode) {
41967c478bd9Sstevel@tonic-gate 		case 0x1:
41977c478bd9Sstevel@tonic-gate 			/* read/write/format data-xfer case */
41987c478bd9Sstevel@tonic-gate 
41997c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
42007c478bd9Sstevel@tonic-gate 			    (C, "fdintr_dma: opmode 1\n"));
42017c478bd9Sstevel@tonic-gate 
42027c478bd9Sstevel@tonic-gate 			/*
42037c478bd9Sstevel@tonic-gate 			 * See if the interrupt is from the floppy
42047c478bd9Sstevel@tonic-gate 			 * controller.  If there is, take out the status bytes.
42057c478bd9Sstevel@tonic-gate 			 */
42067c478bd9Sstevel@tonic-gate 
42077c478bd9Sstevel@tonic-gate 			if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
42087c478bd9Sstevel@tonic-gate 
42097c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
42107c478bd9Sstevel@tonic-gate 				    (C, "fdintr_dma: INT_PEND \n"));
42117c478bd9Sstevel@tonic-gate 
42127c478bd9Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
42137c478bd9Sstevel@tonic-gate 
42147c478bd9Sstevel@tonic-gate 				to = FD_RRETRY;
42157c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_nrslts = 0;
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate 				/* check status */
42187c478bd9Sstevel@tonic-gate 				i = 0;
42197c478bd9Sstevel@tonic-gate 
42207c478bd9Sstevel@tonic-gate 				/*
42217c478bd9Sstevel@tonic-gate 				 * CB turns off once all the result bytes are
42227c478bd9Sstevel@tonic-gate 				 *  read.
42237c478bd9Sstevel@tonic-gate 				 *
42247c478bd9Sstevel@tonic-gate 				 * NOTE: the counters are there so that the
42257c478bd9Sstevel@tonic-gate 				 * handler will never get stuck in a loop.
42267c478bd9Sstevel@tonic-gate 				 * If the counters do reach their maximum
42277c478bd9Sstevel@tonic-gate 				 * values, then a catastrophic error has
42287c478bd9Sstevel@tonic-gate 				 * occurred.  This should never be the case.
42297c478bd9Sstevel@tonic-gate 				 * The counters only came into play during
42307c478bd9Sstevel@tonic-gate 				 * development.
42317c478bd9Sstevel@tonic-gate 				 */
42327c478bd9Sstevel@tonic-gate 				while (((tmp = Msr(fdc)) & CB) &&
42337c478bd9Sstevel@tonic-gate 				    (i < 1000001)) {
42347c478bd9Sstevel@tonic-gate 
42357c478bd9Sstevel@tonic-gate 					/*
42367c478bd9Sstevel@tonic-gate 					 * If RQM + DIO, then a result byte
42377c478bd9Sstevel@tonic-gate 					 * is at hand.
42387c478bd9Sstevel@tonic-gate 					 */
42397c478bd9Sstevel@tonic-gate 					if ((tmp & (RQM|DIO|CB)) ==
42407c478bd9Sstevel@tonic-gate 					    (RQM|DIO|CB)) {
42417c478bd9Sstevel@tonic-gate 						fdc->c_csb.csb_rslt
42427c478bd9Sstevel@tonic-gate 						    [fdc->c_csb.csb_nrslts++]
42437c478bd9Sstevel@tonic-gate 						    = Fifo(fdc);
42447c478bd9Sstevel@tonic-gate 
42457c478bd9Sstevel@tonic-gate 						FDERRPRINT(FDEP_L1, FDEM_INTR,
424619397407SSherry Moore 						    (C,
424719397407SSherry Moore 						    "fdintr_dma: res 0x%x\n",
42487c478bd9Sstevel@tonic-gate 						    fdc->c_csb.csb_rslt
42497c478bd9Sstevel@tonic-gate 						    [fdc->c_csb.csb_nrslts
42507c478bd9Sstevel@tonic-gate 						    - 1]));
42517c478bd9Sstevel@tonic-gate 
42527c478bd9Sstevel@tonic-gate 					} else if (--to == 0) {
42537c478bd9Sstevel@tonic-gate 						/*
42547c478bd9Sstevel@tonic-gate 						 * controller was never
42557c478bd9Sstevel@tonic-gate 						 * ready to give results
42567c478bd9Sstevel@tonic-gate 						 */
42577c478bd9Sstevel@tonic-gate 						fdc->c_csb.csb_status = 2;
42587c478bd9Sstevel@tonic-gate 						break;
42597c478bd9Sstevel@tonic-gate 					}
42607c478bd9Sstevel@tonic-gate 					i++;
42617c478bd9Sstevel@tonic-gate 				}
42627c478bd9Sstevel@tonic-gate 				if (i == 10000) {
42637c478bd9Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
42647c478bd9Sstevel@tonic-gate 					    (C, "First loop overran\n"));
42657c478bd9Sstevel@tonic-gate 				}
42667c478bd9Sstevel@tonic-gate 			}
42677c478bd9Sstevel@tonic-gate 
42687c478bd9Sstevel@tonic-gate 			/*
42697c478bd9Sstevel@tonic-gate 			 * See if the interrupt is from the DMA engine,
42707c478bd9Sstevel@tonic-gate 			 * which will only interrupt on an error
42717c478bd9Sstevel@tonic-gate 			 */
42727c478bd9Sstevel@tonic-gate 			if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
42737c478bd9Sstevel@tonic-gate 
42747c478bd9Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
42757c478bd9Sstevel@tonic-gate 
42767c478bd9Sstevel@tonic-gate 				done = 1;
42777c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_dcsr_rslt = 1;
42787c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
42797c478bd9Sstevel@tonic-gate 				    (C, "fdintr_dma: Error pending\n"));
42807c478bd9Sstevel@tonic-gate 				reset_dma_controller(fdc);
42817c478bd9Sstevel@tonic-gate 				set_dma_control_register(fdc, DCSR_INIT_BITS);
42827c478bd9Sstevel@tonic-gate 				break;
42837c478bd9Sstevel@tonic-gate 			}
42847c478bd9Sstevel@tonic-gate 
42857c478bd9Sstevel@tonic-gate 			/* TCBUG kludge */
42867c478bd9Sstevel@tonic-gate 			if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
42877c478bd9Sstevel@tonic-gate 			    ((fdc->c_csb.csb_rslt[0] & IC_SR0) == 0x40) &&
42887c478bd9Sstevel@tonic-gate 			    (fdc->c_csb.csb_rslt[1] & EN_SR1)) {
42897c478bd9Sstevel@tonic-gate 
42907c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[0] &= ~IC_SR0;
42917c478bd9Sstevel@tonic-gate 
42927c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[1] &= ~EN_SR1;
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate 
42957c478bd9Sstevel@tonic-gate 			}
42967c478bd9Sstevel@tonic-gate 
42977c478bd9Sstevel@tonic-gate 
42987c478bd9Sstevel@tonic-gate 			/* Exit if there were errors in the DMA */
42997c478bd9Sstevel@tonic-gate 			if (((fdc->c_csb.csb_rslt[0] & IC_SR0) != 0) ||
43007c478bd9Sstevel@tonic-gate 			    (fdc->c_csb.csb_rslt[1] != 0) ||
43017c478bd9Sstevel@tonic-gate 			    (fdc->c_csb.csb_rslt[2] != 0)) {
43027c478bd9Sstevel@tonic-gate 				done = 1;
43037c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43047c478bd9Sstevel@tonic-gate 				    (C, "fdintr_dma: errors in command\n"));
43057c478bd9Sstevel@tonic-gate 
43067c478bd9Sstevel@tonic-gate 
43077c478bd9Sstevel@tonic-gate 				break;
43087c478bd9Sstevel@tonic-gate 			}
43097c478bd9Sstevel@tonic-gate 
43107c478bd9Sstevel@tonic-gate 
43117c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
43127c478bd9Sstevel@tonic-gate 			    (C, "fdintr_dma: dbcr 0x%x\n",
43137c478bd9Sstevel@tonic-gate 			    get_data_count_register(fdc)));
43147c478bd9Sstevel@tonic-gate 			/*
43157c478bd9Sstevel@tonic-gate 			 * The csb_ccount is the number of cookies that still
43167c478bd9Sstevel@tonic-gate 			 * need to be processed.  A cookie was just processed
43177c478bd9Sstevel@tonic-gate 			 * so decrement the cookie counter.
43187c478bd9Sstevel@tonic-gate 			 */
43197c478bd9Sstevel@tonic-gate 			if (fdc->c_csb.csb_ccount == 0) {
43207c478bd9Sstevel@tonic-gate 				done = 1;
43217c478bd9Sstevel@tonic-gate 				break;
43227c478bd9Sstevel@tonic-gate 			}
43237c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_ccount--;
43247c478bd9Sstevel@tonic-gate 			ccount = fdc->c_csb.csb_ccount;
43257c478bd9Sstevel@tonic-gate 
43267c478bd9Sstevel@tonic-gate 			windex = fdc->c_csb.csb_windex;
43277c478bd9Sstevel@tonic-gate 
43287c478bd9Sstevel@tonic-gate 			/*
43297c478bd9Sstevel@tonic-gate 			 * If there are no more cookies and all the windows
43307c478bd9Sstevel@tonic-gate 			 * have been DMA'd, then DMA is done.
43317c478bd9Sstevel@tonic-gate 			 *
43327c478bd9Sstevel@tonic-gate 			 */
43337c478bd9Sstevel@tonic-gate 			if ((ccount == 0) && (windex == fdc->c_csb.csb_nwin)) {
43347c478bd9Sstevel@tonic-gate 
43357c478bd9Sstevel@tonic-gate 				done = 1;
43367c478bd9Sstevel@tonic-gate 
43377c478bd9Sstevel@tonic-gate 				/*
43387c478bd9Sstevel@tonic-gate 				 * The handle is unbound in fdexec
43397c478bd9Sstevel@tonic-gate 				 */
43407c478bd9Sstevel@tonic-gate 
43417c478bd9Sstevel@tonic-gate 				break;
43427c478bd9Sstevel@tonic-gate 			}
43437c478bd9Sstevel@tonic-gate 
43447c478bd9Sstevel@tonic-gate 			if (ccount != 0) {
43457c478bd9Sstevel@tonic-gate 				/* process the next cookie */
43467c478bd9Sstevel@tonic-gate 				ddi_dma_nextcookie(fdc->c_dmahandle,
43477c478bd9Sstevel@tonic-gate 				    &fdc->c_csb.csb_dmacookie);
43487c478bd9Sstevel@tonic-gate 
43497c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43507c478bd9Sstevel@tonic-gate 				    (C, "cookie addr 0x%" PRIx64 "\n",
43517c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_laddress));
43527c478bd9Sstevel@tonic-gate 
43537c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43547c478bd9Sstevel@tonic-gate 				    (C, "cookie length %lu\n",
43557c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_size));
43567c478bd9Sstevel@tonic-gate 
43577c478bd9Sstevel@tonic-gate 			} else {
43587c478bd9Sstevel@tonic-gate 
43597c478bd9Sstevel@tonic-gate 				(void) ddi_dma_getwin(fdc->c_dmahandle,
43607c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_windex,
43617c478bd9Sstevel@tonic-gate 				    &off, &len,
43627c478bd9Sstevel@tonic-gate 				    &fdc->c_csb.csb_dmacookie,
43637c478bd9Sstevel@tonic-gate 				    &fdc->c_csb.csb_ccount);
43647c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_windex++;
43657c478bd9Sstevel@tonic-gate 
43667c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43677c478bd9Sstevel@tonic-gate 				    (C, "fdintr_dma: process %d window\n",
43687c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_windex));
43697c478bd9Sstevel@tonic-gate 
43707c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43717c478bd9Sstevel@tonic-gate 				    (C, "fdintr_dma: process no. cookies %d\n",
43727c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_ccount));
43737c478bd9Sstevel@tonic-gate 
43747c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43757c478bd9Sstevel@tonic-gate 				    (C, "cookie addr 0x%" PRIx64 "\n",
43767c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_laddress));
43777c478bd9Sstevel@tonic-gate 
43787c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
43797c478bd9Sstevel@tonic-gate 				    (C, "cookie length %lu\n",
43807c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_dmacookie.dmac_size));
43817c478bd9Sstevel@tonic-gate 			}
43827c478bd9Sstevel@tonic-gate 
43837c478bd9Sstevel@tonic-gate 			/*
43847c478bd9Sstevel@tonic-gate 			 * Program the DMA engine with the length and
43857c478bd9Sstevel@tonic-gate 			 * the address of the transfer
43867c478bd9Sstevel@tonic-gate 			 */
43877c478bd9Sstevel@tonic-gate 
43887c478bd9Sstevel@tonic-gate 			ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
43897c478bd9Sstevel@tonic-gate 
43907c478bd9Sstevel@tonic-gate 			set_data_count_register(fdc,
43917c478bd9Sstevel@tonic-gate 			    fdc->c_csb.csb_dmacookie.dmac_size);
43927c478bd9Sstevel@tonic-gate 			set_data_address_register(fdc,
43937c478bd9Sstevel@tonic-gate 			    fdc->c_csb.csb_dmacookie.dmac_laddress);
43947c478bd9Sstevel@tonic-gate 
43957c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR, (C,
43967c478bd9Sstevel@tonic-gate 			    "fdintr_dma: size 0x%lx\n",
43977c478bd9Sstevel@tonic-gate 			    fdc->c_csb.csb_dmacookie.dmac_size));
43987c478bd9Sstevel@tonic-gate 
43997c478bd9Sstevel@tonic-gate 
44007c478bd9Sstevel@tonic-gate 			/* reprogram the controller */
44017c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[2] = fdc->c_csb.csb_rslt[3];
44027c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[3] = fdc->c_csb.csb_rslt[4];
44037c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[4] = fdc->c_csb.csb_rslt[5];
44047c478bd9Sstevel@tonic-gate 			fdc->c_csb.csb_cmds[1] = (fdc->c_csb.csb_cmds[1]
44057c478bd9Sstevel@tonic-gate 			    & ~0x04) | (fdc->c_csb.csb_rslt[4] << 2);
44067c478bd9Sstevel@tonic-gate 
44077c478bd9Sstevel@tonic-gate 			for (i = 0; i < (int)fdc->c_csb.csb_ncmds; i++) {
44087c478bd9Sstevel@tonic-gate 
44097c478bd9Sstevel@tonic-gate 				/*
44107c478bd9Sstevel@tonic-gate 				 * Test the readiness of the controller
44117c478bd9Sstevel@tonic-gate 				 * to receive the cmd
44127c478bd9Sstevel@tonic-gate 				 */
44137c478bd9Sstevel@tonic-gate 				for (to = FD_CRETRY; to; to--) {
44147c478bd9Sstevel@tonic-gate 					if ((Msr(fdc) & (DIO|RQM)) == RQM)
44157c478bd9Sstevel@tonic-gate 						break;
44167c478bd9Sstevel@tonic-gate 				}
44177c478bd9Sstevel@tonic-gate 				if (to == 0) {
44187c478bd9Sstevel@tonic-gate 					FDERRPRINT(FDEP_L2, FDEM_EXEC,
44197c478bd9Sstevel@tonic-gate 					    (C,
442019397407SSherry Moore 					    "fdc: no RQM - stat 0x%x\n",
442119397407SSherry Moore 					    Msr(fdc)));
44227c478bd9Sstevel@tonic-gate 					/* stop the DMA from happening */
44237c478bd9Sstevel@tonic-gate 					fdc->c_csb.csb_status = 2;
44247c478bd9Sstevel@tonic-gate 					done = 1;
44257c478bd9Sstevel@tonic-gate 					break;
44267c478bd9Sstevel@tonic-gate 				}
44277c478bd9Sstevel@tonic-gate 
44287c478bd9Sstevel@tonic-gate 				Set_Fifo(fdc, fdc->c_csb.csb_cmds[i]);
44297c478bd9Sstevel@tonic-gate 
44307c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
44317c478bd9Sstevel@tonic-gate 				    (C,
44327c478bd9Sstevel@tonic-gate 				    "fdintr_dma: sent 0x%x, Msr 0x%x\n",
44337c478bd9Sstevel@tonic-gate 				    fdc->c_csb.csb_cmds[i], Msr(fdc)));
44347c478bd9Sstevel@tonic-gate 			}
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate 			/* reenable DMA */
44377c478bd9Sstevel@tonic-gate 			if ((!not_cheerio) && (!done))
44387c478bd9Sstevel@tonic-gate 				set_dma_control_register(fdc, tmp_dcsr |
44397c478bd9Sstevel@tonic-gate 				    DCSR_EN_DMA);
44407c478bd9Sstevel@tonic-gate 			break;
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 		case 0x2:
44437c478bd9Sstevel@tonic-gate 		/* seek/recal type cmd */
44447c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
44457c478bd9Sstevel@tonic-gate 			    (C, "fintr_dma: opmode 2\n"));
44467c478bd9Sstevel@tonic-gate 
44477c478bd9Sstevel@tonic-gate 			/*
44487c478bd9Sstevel@tonic-gate 			 *  See if the interrupt is from the DMA engine,
44497c478bd9Sstevel@tonic-gate 			 *  which will only interrupt if there was an error.
44507c478bd9Sstevel@tonic-gate 			 */
44517c478bd9Sstevel@tonic-gate 			if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
44527c478bd9Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
44537c478bd9Sstevel@tonic-gate 				done = 1;
44547c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_dcsr_rslt = 1;
44557c478bd9Sstevel@tonic-gate 				reset_dma_controller(fdc);
44567c478bd9Sstevel@tonic-gate 				set_dma_control_register(fdc, DCSR_INIT_BITS);
44577c478bd9Sstevel@tonic-gate 
44587c478bd9Sstevel@tonic-gate 				break;
44597c478bd9Sstevel@tonic-gate 			}
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate 
44627c478bd9Sstevel@tonic-gate 			/* See if the interrupt is from the floppy controller */
44637c478bd9Sstevel@tonic-gate 			if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
44647c478bd9Sstevel@tonic-gate 
44657c478bd9Sstevel@tonic-gate 				res = DDI_INTR_CLAIMED;
44667c478bd9Sstevel@tonic-gate 
44677c478bd9Sstevel@tonic-gate 
44687c478bd9Sstevel@tonic-gate 				/*
44697c478bd9Sstevel@tonic-gate 				 * Wait until there's no longer a command
44707c478bd9Sstevel@tonic-gate 				 * in progress
44717c478bd9Sstevel@tonic-gate 				 */
44727c478bd9Sstevel@tonic-gate 
44737c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L1, FDEM_INTR,
44747c478bd9Sstevel@tonic-gate 				    (C, "fdintr_dma: interrupt pending\n"));
44757c478bd9Sstevel@tonic-gate 				i = 0;
44767c478bd9Sstevel@tonic-gate 				while (((Msr(fdc) & CB)) && (i < 10000)) {
44777c478bd9Sstevel@tonic-gate 					i++;
44787c478bd9Sstevel@tonic-gate 				}
44797c478bd9Sstevel@tonic-gate 
44807c478bd9Sstevel@tonic-gate 				if (i == 10000)
44817c478bd9Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
44827c478bd9Sstevel@tonic-gate 					    (C, "2nd loop overran !!!\n"));
44837c478bd9Sstevel@tonic-gate 
44847c478bd9Sstevel@tonic-gate 				/*
44857c478bd9Sstevel@tonic-gate 				 * Check the RQM bit to see if the controller is
44867c478bd9Sstevel@tonic-gate 				 * ready to transfer status of the command.
44877c478bd9Sstevel@tonic-gate 				 */
44887c478bd9Sstevel@tonic-gate 				i = 0;
44897c478bd9Sstevel@tonic-gate 				while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
44907c478bd9Sstevel@tonic-gate 					i++;
44917c478bd9Sstevel@tonic-gate 				}
44927c478bd9Sstevel@tonic-gate 
44937c478bd9Sstevel@tonic-gate 				if (i == 10000)
44947c478bd9Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
44957c478bd9Sstevel@tonic-gate 					    (C, "3rd loop overran !!!\n"));
44967c478bd9Sstevel@tonic-gate 
44977c478bd9Sstevel@tonic-gate 				/*
44987c478bd9Sstevel@tonic-gate 				 * Issue the Sense Interrupt Status Command
44997c478bd9Sstevel@tonic-gate 				 */
45007c478bd9Sstevel@tonic-gate 				Set_Fifo(fdc, SNSISTAT);
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 				i = 0;
45037c478bd9Sstevel@tonic-gate 				while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
45047c478bd9Sstevel@tonic-gate 					i++;
45057c478bd9Sstevel@tonic-gate 				}
45067c478bd9Sstevel@tonic-gate 				if (i == 10000)
45077c478bd9Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
45087c478bd9Sstevel@tonic-gate 					    (C, "4th loop overran !!!\n"));
45097c478bd9Sstevel@tonic-gate 
45107c478bd9Sstevel@tonic-gate 				/* Store the first result byte */
45117c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[0] = Fifo(fdc);
45127c478bd9Sstevel@tonic-gate 
45137c478bd9Sstevel@tonic-gate 				i = 0;
45147c478bd9Sstevel@tonic-gate 				while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
45157c478bd9Sstevel@tonic-gate 					i++;
45167c478bd9Sstevel@tonic-gate 				}
45177c478bd9Sstevel@tonic-gate 				if (i == 10000)
45187c478bd9Sstevel@tonic-gate 					FDERRPRINT(FDEP_L1, FDEM_INTR,
45197c478bd9Sstevel@tonic-gate 					    (C, "5th loop overran !!!\n"));
45207c478bd9Sstevel@tonic-gate 
45217c478bd9Sstevel@tonic-gate 				/* Store the second  result byte */
45227c478bd9Sstevel@tonic-gate 				fdc->c_csb.csb_rslt[1] = Fifo(fdc);
45237c478bd9Sstevel@tonic-gate 
45247c478bd9Sstevel@tonic-gate 				done = 1;
45257c478bd9Sstevel@tonic-gate 			}
45267c478bd9Sstevel@tonic-gate 
45277c478bd9Sstevel@tonic-gate 		}
45287c478bd9Sstevel@tonic-gate 
45297c478bd9Sstevel@tonic-gate 	/*
45307c478bd9Sstevel@tonic-gate 	 * We are done with the actual interrupt handling here.
45317c478bd9Sstevel@tonic-gate 	 * The portion below should be actually be done by fd_lointr().
45327c478bd9Sstevel@tonic-gate 	 * We should be triggering the fd_lointr here and exiting.
45337c478bd9Sstevel@tonic-gate 	 * However for want of time this will be done in the next FIX.
45347c478bd9Sstevel@tonic-gate 	 *
45357c478bd9Sstevel@tonic-gate 	 * Hence for now we will release hilock only and keep the remaining
45367c478bd9Sstevel@tonic-gate 	 * code as it is.
45377c478bd9Sstevel@tonic-gate 	 * Releasing of hilock ensures that we don't hold on to the
45387c478bd9Sstevel@tonic-gate 	 * lolock and hilock at the same time.
45397c478bd9Sstevel@tonic-gate 	 * hilock is acquired each time dma related  registers are accessed.
45407c478bd9Sstevel@tonic-gate 	 */
45417c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_hilock);
45427c478bd9Sstevel@tonic-gate 	/* Make signal and get out of interrupt handler */
45437c478bd9Sstevel@tonic-gate 	if (done) {
45447c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
45457c478bd9Sstevel@tonic-gate 
45467c478bd9Sstevel@tonic-gate 		fdc->c_csb.csb_opmode = 0;
45477c478bd9Sstevel@tonic-gate 
45487c478bd9Sstevel@tonic-gate 		/*  reset watchdog timer if armed and not already triggered */
45497c478bd9Sstevel@tonic-gate 
45507c478bd9Sstevel@tonic-gate 
45517c478bd9Sstevel@tonic-gate 		if (fdc->c_timeid) {
45527c478bd9Sstevel@tonic-gate 			timeout_id_t timeid = fdc->c_timeid;
45537c478bd9Sstevel@tonic-gate 			fdc->c_timeid = 0;
45547c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
45557c478bd9Sstevel@tonic-gate 			(void) untimeout(timeid);
45567c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
45577c478bd9Sstevel@tonic-gate 		}
45587c478bd9Sstevel@tonic-gate 
45597c478bd9Sstevel@tonic-gate 
45607c478bd9Sstevel@tonic-gate 		if (fdc->c_flags & FDCFLG_WAITING) {
45617c478bd9Sstevel@tonic-gate 			/*
45627c478bd9Sstevel@tonic-gate 			 * somebody's waiting on finish of fdctlr/csb,
45637c478bd9Sstevel@tonic-gate 			 * wake them
45647c478bd9Sstevel@tonic-gate 			 */
45657c478bd9Sstevel@tonic-gate 
45667c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
45677c478bd9Sstevel@tonic-gate 			    (C, "fdintr_dma: signal the waiter\n"));
45687c478bd9Sstevel@tonic-gate 
45697c478bd9Sstevel@tonic-gate 			fdc->c_flags ^= FDCFLG_WAITING;
45707c478bd9Sstevel@tonic-gate 			cv_signal(&fdc->c_iocv);
45717c478bd9Sstevel@tonic-gate 
45727c478bd9Sstevel@tonic-gate 			/*
45737c478bd9Sstevel@tonic-gate 			 * FDCFLG_BUSY is NOT cleared, NOR is the csb given
45747c478bd9Sstevel@tonic-gate 			 * back; the operation just finished can look at the csb
45757c478bd9Sstevel@tonic-gate 			 */
45767c478bd9Sstevel@tonic-gate 		} else {
45777c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_INTR,
45787c478bd9Sstevel@tonic-gate 			    (C, "fdintr_dma: nobody sleeping (%x %x %x)\n",
45797c478bd9Sstevel@tonic-gate 			    fdc->c_csb.csb_rslt[0], fdc->c_csb.csb_rslt[1],
45807c478bd9Sstevel@tonic-gate 			    fdc->c_csb.csb_rslt[2]));
45817c478bd9Sstevel@tonic-gate 		}
45827c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
45837c478bd9Sstevel@tonic-gate 	}
45847c478bd9Sstevel@tonic-gate 	/* update high level interrupt counter */
45857c478bd9Sstevel@tonic-gate 	if (fdc->c_intrstat)
45867c478bd9Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_HARD]++;
45877c478bd9Sstevel@tonic-gate 
45887c478bd9Sstevel@tonic-gate 
45897c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr_dma: done\n"));
45907c478bd9Sstevel@tonic-gate 	return (res);
45917c478bd9Sstevel@tonic-gate }
45927c478bd9Sstevel@tonic-gate 
45937c478bd9Sstevel@tonic-gate /*
45947c478bd9Sstevel@tonic-gate  * fd_lointr
45957c478bd9Sstevel@tonic-gate  *	This is the low level SW interrupt handler triggered by the high
45967c478bd9Sstevel@tonic-gate  *	level interrupt handler (or by fdwatch).
45977c478bd9Sstevel@tonic-gate  */
45987c478bd9Sstevel@tonic-gate static uint_t
45997c478bd9Sstevel@tonic-gate fd_lointr(caddr_t arg)
46007c478bd9Sstevel@tonic-gate {
46017c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc = (struct fdctlr *)arg;
46027c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
46037c478bd9Sstevel@tonic-gate 
46047c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
46057c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr: opmode %d\n",
46067c478bd9Sstevel@tonic-gate 	    csb->csb_opmode));
46077c478bd9Sstevel@tonic-gate 	/*
46087c478bd9Sstevel@tonic-gate 	 * Check that lowlevel interrupt really meant to trigger us.
46097c478bd9Sstevel@tonic-gate 	 */
46107c478bd9Sstevel@tonic-gate 	if (csb->csb_opmode != 4) {
46117c478bd9Sstevel@tonic-gate 		/*
46127c478bd9Sstevel@tonic-gate 		 * This should probably be protected, but, what the
46137c478bd9Sstevel@tonic-gate 		 * heck...the cost isn't worth the accuracy for this
46147c478bd9Sstevel@tonic-gate 		 * statistic.
46157c478bd9Sstevel@tonic-gate 		 */
46167c478bd9Sstevel@tonic-gate 		if (fdc->c_intrstat)
46177c478bd9Sstevel@tonic-gate 			KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
46187c478bd9Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
46197c478bd9Sstevel@tonic-gate 	}
46207c478bd9Sstevel@tonic-gate 
46217c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
46227c478bd9Sstevel@tonic-gate 	csb->csb_opmode = 0;
46237c478bd9Sstevel@tonic-gate 
46247c478bd9Sstevel@tonic-gate 	/*  reset watchdog timer if armed and not already triggered */
46257c478bd9Sstevel@tonic-gate 	if (fdc->c_timeid) {
46267c478bd9Sstevel@tonic-gate 		timeout_id_t timeid = fdc->c_timeid;
46277c478bd9Sstevel@tonic-gate 		fdc->c_timeid = 0;
46287c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
46297c478bd9Sstevel@tonic-gate 		(void) untimeout(timeid);
46307c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
46317c478bd9Sstevel@tonic-gate 
46327c478bd9Sstevel@tonic-gate 	}
46337c478bd9Sstevel@tonic-gate 
46347c478bd9Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_WAITING) {
46357c478bd9Sstevel@tonic-gate 		/*
46367c478bd9Sstevel@tonic-gate 		 * somebody's waiting on finish of fdctlr/csb, wake them
46377c478bd9Sstevel@tonic-gate 		 */
46387c478bd9Sstevel@tonic-gate 		fdc->c_flags ^= FDCFLG_WAITING;
46397c478bd9Sstevel@tonic-gate 		cv_signal(&fdc->c_iocv);
46407c478bd9Sstevel@tonic-gate 
46417c478bd9Sstevel@tonic-gate 		/*
46427c478bd9Sstevel@tonic-gate 		 * FDCFLG_BUSY is NOT cleared, NOR is the csb given back; so
46437c478bd9Sstevel@tonic-gate 		 * the operation just finished can look at the csb
46447c478bd9Sstevel@tonic-gate 		 */
46457c478bd9Sstevel@tonic-gate 	} else {
46467c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_INTR,
46477c478bd9Sstevel@tonic-gate 		    (C, "fdintr: nobody sleeping (%x %x %x)\n",
46487c478bd9Sstevel@tonic-gate 		    csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
46497c478bd9Sstevel@tonic-gate 	}
46507c478bd9Sstevel@tonic-gate 	if (fdc->c_intrstat)
46517c478bd9Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_SOFT]++;
46527c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
46537c478bd9Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
46547c478bd9Sstevel@tonic-gate }
46557c478bd9Sstevel@tonic-gate 
46567c478bd9Sstevel@tonic-gate /*
46577c478bd9Sstevel@tonic-gate  * fdwatch
46587c478bd9Sstevel@tonic-gate  *	is called from timein() when a floppy operation has expired.
46597c478bd9Sstevel@tonic-gate  */
46607c478bd9Sstevel@tonic-gate static void
46617c478bd9Sstevel@tonic-gate fdwatch(void *arg)
46627c478bd9Sstevel@tonic-gate {
46637c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc = arg;
46647c478bd9Sstevel@tonic-gate 	int old_opmode;
46657c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
46667c478bd9Sstevel@tonic-gate 
46677c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch\n"));
46687c478bd9Sstevel@tonic-gate 
46697c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
46707c478bd9Sstevel@tonic-gate 	if (fdc->c_timeid == 0) {
46717c478bd9Sstevel@tonic-gate 		/*
46727c478bd9Sstevel@tonic-gate 		 * fdintr got here first, ergo, no timeout condition..
46737c478bd9Sstevel@tonic-gate 		 */
46747c478bd9Sstevel@tonic-gate 
46757c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_WATC,
46767c478bd9Sstevel@tonic-gate 		    (C, "fdwatch: no timeout\n"));
46777c478bd9Sstevel@tonic-gate 
46787c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
46797c478bd9Sstevel@tonic-gate 		return;
46807c478bd9Sstevel@tonic-gate 	}
46817c478bd9Sstevel@tonic-gate 	fdc->c_timeid = 0;
46827c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
46837c478bd9Sstevel@tonic-gate 
46847c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_hilock);
46857c478bd9Sstevel@tonic-gate 	/*
46867c478bd9Sstevel@tonic-gate 	 * XXXX: We should probably reset the bloody chip
46877c478bd9Sstevel@tonic-gate 	 */
46887c478bd9Sstevel@tonic-gate 	old_opmode = csb->csb_opmode;
46897c478bd9Sstevel@tonic-gate 
46907c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_WATC,
46917c478bd9Sstevel@tonic-gate 	    (C, "fd%d: timeout, opmode:%d\n", csb->csb_unit, old_opmode));
46927c478bd9Sstevel@tonic-gate 
46937c478bd9Sstevel@tonic-gate 	csb->csb_opmode = 4;
46947c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_hilock);
46957c478bd9Sstevel@tonic-gate 
46967c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch: cmd %s timed out\n",
46977c478bd9Sstevel@tonic-gate 	    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
46987c478bd9Sstevel@tonic-gate 	fdc->c_flags |= FDCFLG_TIMEDOUT;
46997c478bd9Sstevel@tonic-gate 	csb->csb_status = CSB_CMDTO;
47007c478bd9Sstevel@tonic-gate 
47017c478bd9Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_DMA) == 0) {
47027c478bd9Sstevel@tonic-gate 		ddi_trigger_softintr(fdc->c_softid);
47037c478bd9Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_WATCHDOG]++;
47047c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
47057c478bd9Sstevel@tonic-gate 	} else {
47067c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
47077c478bd9Sstevel@tonic-gate 		(void) fd_lointr((caddr_t)fdctlrs);
47087c478bd9Sstevel@tonic-gate 	}
47097c478bd9Sstevel@tonic-gate }
47107c478bd9Sstevel@tonic-gate 
47117c478bd9Sstevel@tonic-gate /*
47127c478bd9Sstevel@tonic-gate  * fdgetcsb
47137c478bd9Sstevel@tonic-gate  *	wait until the csb is free
47147c478bd9Sstevel@tonic-gate  */
47157c478bd9Sstevel@tonic-gate static void
47167c478bd9Sstevel@tonic-gate fdgetcsb(struct fdctlr *fdc)
47177c478bd9Sstevel@tonic-gate {
47187c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETC, (C, "fdgetcsb\n"));
47197c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
47207c478bd9Sstevel@tonic-gate 	while (fdc->c_flags & FDCFLG_BUSY) {
47217c478bd9Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WANT;
47227c478bd9Sstevel@tonic-gate 		cv_wait(&fdc->c_csbcv, &fdc->c_lolock);
47237c478bd9Sstevel@tonic-gate 	}
47247c478bd9Sstevel@tonic-gate 	fdc->c_flags |= FDCFLG_BUSY; /* got it! */
47257c478bd9Sstevel@tonic-gate }
47267c478bd9Sstevel@tonic-gate 
47277c478bd9Sstevel@tonic-gate /*
47287c478bd9Sstevel@tonic-gate  * fdretcsb
47297c478bd9Sstevel@tonic-gate  *	return csb
47307c478bd9Sstevel@tonic-gate  */
47317c478bd9Sstevel@tonic-gate static void
47327c478bd9Sstevel@tonic-gate fdretcsb(struct fdctlr *fdc)
47337c478bd9Sstevel@tonic-gate {
47347c478bd9Sstevel@tonic-gate 
47357c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
47367c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RETC, (C, "fdretcsb\n"));
47377c478bd9Sstevel@tonic-gate 	fdc->c_flags &= ~FDCFLG_BUSY; /* let go */
47387c478bd9Sstevel@tonic-gate 
47397c478bd9Sstevel@tonic-gate 	fdc->c_csb.csb_read = 0;
47407c478bd9Sstevel@tonic-gate 
47417c478bd9Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_WANT) {
47427c478bd9Sstevel@tonic-gate 		fdc->c_flags ^= FDCFLG_WANT;
47437c478bd9Sstevel@tonic-gate 		/*
47447c478bd9Sstevel@tonic-gate 		 * broadcast the signal.  One thread will wake up and
47457c478bd9Sstevel@tonic-gate 		 * set the flags to FDCFLG_BUSY.  If more than one thread is
47467c478bd9Sstevel@tonic-gate 		 * waiting then each thread will wake up in turn.  The first
47477c478bd9Sstevel@tonic-gate 		 * thread to wake-up will set the FDCFLG_BUSY flag and the
47487c478bd9Sstevel@tonic-gate 		 * subsequent threads will will wake-up, but reset the
47497c478bd9Sstevel@tonic-gate 		 * flag to FDCFLG_WANT because the FDCFLG_BUSY bit is set.
47507c478bd9Sstevel@tonic-gate 		 */
47517c478bd9Sstevel@tonic-gate 		cv_broadcast(&fdc->c_csbcv);
47527c478bd9Sstevel@tonic-gate 	}
47537c478bd9Sstevel@tonic-gate }
47547c478bd9Sstevel@tonic-gate 
47557c478bd9Sstevel@tonic-gate 
47567c478bd9Sstevel@tonic-gate /*
47577c478bd9Sstevel@tonic-gate  * fdreset
47587c478bd9Sstevel@tonic-gate  *	reset THE controller, and configure it to be
47597c478bd9Sstevel@tonic-gate  *	the way it ought to be
47607c478bd9Sstevel@tonic-gate  * ASSUMES: that it already owns the csb/fdctlr!
47617c478bd9Sstevel@tonic-gate  *
47627c478bd9Sstevel@tonic-gate  *	- called with the low level lock held
47637c478bd9Sstevel@tonic-gate  */
47647c478bd9Sstevel@tonic-gate static int
47657c478bd9Sstevel@tonic-gate fdreset(struct fdctlr *fdc)
47667c478bd9Sstevel@tonic-gate {
47677c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
47687c478bd9Sstevel@tonic-gate 	clock_t local_lbolt = 0;
47697c478bd9Sstevel@tonic-gate 	timeout_id_t timeid;
47707c478bd9Sstevel@tonic-gate 
47717c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset\n"));
47727c478bd9Sstevel@tonic-gate 
47737c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&fdc->c_lolock));
47747c478bd9Sstevel@tonic-gate 
47757c478bd9Sstevel@tonic-gate 	/* count resets */
47767c478bd9Sstevel@tonic-gate 	fdc->fdstats.reset++;
47777c478bd9Sstevel@tonic-gate 
47787c478bd9Sstevel@tonic-gate 	/*
47797c478bd9Sstevel@tonic-gate 	 * On the 82077, the DSR will clear itself after a reset.  Upon exiting
47807c478bd9Sstevel@tonic-gate 	 * the reset, a polling interrupt will be generated.  If the floppy
47817c478bd9Sstevel@tonic-gate 	 * interrupt is enabled, it's possible for cv_signal() to be called
47827c478bd9Sstevel@tonic-gate 	 * before cv_wait().  This will cause the system to hang.  Turn off
47837c478bd9Sstevel@tonic-gate 	 * the floppy interrupt to avoid this race condition
47847c478bd9Sstevel@tonic-gate 	 */
47857c478bd9Sstevel@tonic-gate 	if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
47867c478bd9Sstevel@tonic-gate 		/*
47877c478bd9Sstevel@tonic-gate 		 * We need to perform any timeouts before we Reset the
47887c478bd9Sstevel@tonic-gate 		 * controller. We cannot afford to drop the c_lolock mutex after
47897c478bd9Sstevel@tonic-gate 		 * Resetting the controller. The reason is that we get a spate
47907c478bd9Sstevel@tonic-gate 		 * of interrupts until we take the controller out of reset.
47917c478bd9Sstevel@tonic-gate 		 * The way we avoid this spate of continuous interrupts is by
47927c478bd9Sstevel@tonic-gate 		 * holding on to the c_lolock and forcing the fdintr_dma routine
47937c478bd9Sstevel@tonic-gate 		 * to go to sleep waiting for this mutex.
47947c478bd9Sstevel@tonic-gate 		 */
47957c478bd9Sstevel@tonic-gate 		/* Do not hold the mutex across the untimeout call */
47967c478bd9Sstevel@tonic-gate 		timeid = fdc->c_mtimeid;
47977c478bd9Sstevel@tonic-gate 		fdc->c_mtimeid = 0;
47987c478bd9Sstevel@tonic-gate 		if (timeid) {
47997c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
48007c478bd9Sstevel@tonic-gate 			(void) untimeout(timeid);
48017c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
48027c478bd9Sstevel@tonic-gate 		}
48037c478bd9Sstevel@tonic-gate 		/* LINTED */
48047c478bd9Sstevel@tonic-gate 		Set_dor(fdc, DMAGATE, 0);
48057c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset: set dor\n"));
48067c478bd9Sstevel@tonic-gate 	}
48077c478bd9Sstevel@tonic-gate 
48087c478bd9Sstevel@tonic-gate 	/* toggle software reset */
48097c478bd9Sstevel@tonic-gate 	Dsr(fdc, SWR);
48107c478bd9Sstevel@tonic-gate 
48117c478bd9Sstevel@tonic-gate 	drv_usecwait(5);
48127c478bd9Sstevel@tonic-gate 
48137c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RESE,
48147c478bd9Sstevel@tonic-gate 	    (C, "fdreset: toggled software reset\n"));
48157c478bd9Sstevel@tonic-gate 
48167c478bd9Sstevel@tonic-gate 	/*
48177c478bd9Sstevel@tonic-gate 	 * This sets the data rate to 500Kbps (for high density)
48187c478bd9Sstevel@tonic-gate 	 * XXX should use current characteristics instead XXX
48197c478bd9Sstevel@tonic-gate 	 */
48207c478bd9Sstevel@tonic-gate 	Dsr(fdc, 0);
48217c478bd9Sstevel@tonic-gate 	drv_usecwait(5);
48227c478bd9Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
48237c478bd9Sstevel@tonic-gate 	case FDCTYPE_82077:
48247c478bd9Sstevel@tonic-gate 		/*
48257c478bd9Sstevel@tonic-gate 		 * when we bring the controller out of reset it will generate
48267c478bd9Sstevel@tonic-gate 		 * a polling interrupt. fdintr() will field it and schedule
48277c478bd9Sstevel@tonic-gate 		 * fd_lointr(). There will be no one sleeping but we are
48287c478bd9Sstevel@tonic-gate 		 * expecting an interrupt so....
48297c478bd9Sstevel@tonic-gate 		 */
48307c478bd9Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WAITING;
48317c478bd9Sstevel@tonic-gate 
48327c478bd9Sstevel@tonic-gate 		/*
48337c478bd9Sstevel@tonic-gate 		 * The reset bit must be cleared to take the 077 out of
48347c478bd9Sstevel@tonic-gate 		 * reset state and the DMAGATE bit must be high to enable
48357c478bd9Sstevel@tonic-gate 		 * interrupts.
48367c478bd9Sstevel@tonic-gate 		 */
48377c478bd9Sstevel@tonic-gate 		/* LINTED */
48387c478bd9Sstevel@tonic-gate 		Set_dor(fdc, DMAGATE|RESET, 1);
48397c478bd9Sstevel@tonic-gate 
48407c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
48417c478bd9Sstevel@tonic-gate 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
48427c478bd9Sstevel@tonic-gate 
48437c478bd9Sstevel@tonic-gate 		local_lbolt = ddi_get_lbolt();
48447c478bd9Sstevel@tonic-gate 		if (cv_timedwait(&fdc->c_iocv, &fdc->c_lolock,
48457c478bd9Sstevel@tonic-gate 		    local_lbolt + drv_usectohz(1000000)) == -1) {
48467c478bd9Sstevel@tonic-gate 			return (-1);
48477c478bd9Sstevel@tonic-gate 		}
48487c478bd9Sstevel@tonic-gate 		break;
48497c478bd9Sstevel@tonic-gate 
48507c478bd9Sstevel@tonic-gate 	default:
48517c478bd9Sstevel@tonic-gate 		fdc->c_flags |= FDCFLG_WAITING;
48527c478bd9Sstevel@tonic-gate 
48537c478bd9Sstevel@tonic-gate 		/*
48547c478bd9Sstevel@tonic-gate 		 * A timed wait is not used because it's possible for the timer
48557c478bd9Sstevel@tonic-gate 		 * to go off before the controller has a chance to interrupt.
48567c478bd9Sstevel@tonic-gate 		 */
48577c478bd9Sstevel@tonic-gate 		cv_wait(&fdc->c_iocv, &fdc->c_lolock);
48587c478bd9Sstevel@tonic-gate 		break;
48597c478bd9Sstevel@tonic-gate 	}
48607c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate 	/* setup common things in csb */
48637c478bd9Sstevel@tonic-gate 	csb->csb_unit = fdc->c_un->un_unit_no;
48647c478bd9Sstevel@tonic-gate 	csb->csb_nrslts = 0;
48657c478bd9Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFNORESULTS;
48667c478bd9Sstevel@tonic-gate 	csb->csb_maxretry = 0;
48677c478bd9Sstevel@tonic-gate 	csb->csb_retrys = 0;
48687c478bd9Sstevel@tonic-gate 
48697c478bd9Sstevel@tonic-gate 	csb->csb_read = CSB_NULL;
48707c478bd9Sstevel@tonic-gate 
48717c478bd9Sstevel@tonic-gate 	/* send SPECIFY command to fdc */
48727c478bd9Sstevel@tonic-gate 	/* csb->unit is don't care */
48737c478bd9Sstevel@tonic-gate 	csb->csb_cmds[0] = FDRAW_SPECIFY;
48747c478bd9Sstevel@tonic-gate 	csb->csb_cmds[1] = fdspec[0]; /* step rate, head unload time */
48757c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA)
48767c478bd9Sstevel@tonic-gate 		csb->csb_cmds[2] =  SPEC_DMA_MODE;
48777c478bd9Sstevel@tonic-gate 	else
48787c478bd9Sstevel@tonic-gate 		csb->csb_cmds[2] = fdspec[1];  /* head load time, DMA mode */
48797c478bd9Sstevel@tonic-gate 
48807c478bd9Sstevel@tonic-gate 	csb->csb_ncmds = 3;
48817c478bd9Sstevel@tonic-gate 
48827c478bd9Sstevel@tonic-gate 	/* XXX for now ignore errors, they "CAN'T HAPPEN" */
48837c478bd9Sstevel@tonic-gate 	(void) fdexec(fdc, 0);	/* no FDXC_CHECKCHG, ... */
48847c478bd9Sstevel@tonic-gate 	/* no results */
48857c478bd9Sstevel@tonic-gate 
48867c478bd9Sstevel@tonic-gate 	/* send CONFIGURE command to fdc */
48877c478bd9Sstevel@tonic-gate 	/* csb->unit is don't care */
48887c478bd9Sstevel@tonic-gate 	csb->csb_cmds[0] = CONFIGURE;
48897c478bd9Sstevel@tonic-gate 	csb->csb_cmds[1] = fdconf[0]; /* motor info, motor delays */
48907c478bd9Sstevel@tonic-gate 	csb->csb_cmds[2] = fdconf[1]; /* enaimplsk, disapoll, fifothru */
48917c478bd9Sstevel@tonic-gate 	csb->csb_cmds[3] = fdconf[2]; /* track precomp */
48927c478bd9Sstevel@tonic-gate 	csb->csb_ncmds = 4;
48937c478bd9Sstevel@tonic-gate 
48947c478bd9Sstevel@tonic-gate 	csb->csb_read = CSB_NULL;
48957c478bd9Sstevel@tonic-gate 
48967c478bd9Sstevel@tonic-gate 	csb->csb_retrys = 0;
48977c478bd9Sstevel@tonic-gate 
48987c478bd9Sstevel@tonic-gate 	/* XXX for now ignore errors, they "CAN'T HAPPEN" */
48997c478bd9Sstevel@tonic-gate 	(void) fdexec(fdc, 0); /* no FDXC_CHECKCHG, ... */
49007c478bd9Sstevel@tonic-gate 	return (0);
49017c478bd9Sstevel@tonic-gate }
49027c478bd9Sstevel@tonic-gate 
49037c478bd9Sstevel@tonic-gate /*
49047c478bd9Sstevel@tonic-gate  * fdrecalseek
49057c478bd9Sstevel@tonic-gate  *	performs recalibrates or seeks if the "arg" is -1 does a
49067c478bd9Sstevel@tonic-gate  *	recalibrate on a drive, else it seeks to the cylinder of
49077c478bd9Sstevel@tonic-gate  *	the drive.  The recalibrate is also used to find a drive,
49087c478bd9Sstevel@tonic-gate  *	ie if the drive is not there, the controller says "error"
49097c478bd9Sstevel@tonic-gate  *	on the operation
49107c478bd9Sstevel@tonic-gate  * NOTE: that there is special handling of this operation in the hardware
49117c478bd9Sstevel@tonic-gate  * interrupt routine - it causes the operation to appear to have results;
49127c478bd9Sstevel@tonic-gate  * ie the results of the SENSE INTERRUPT STATUS that the hardware interrupt
49137c478bd9Sstevel@tonic-gate  * function did for us.
49147c478bd9Sstevel@tonic-gate  * NOTE: because it uses sleep/wakeup it must be protected in a critical
49157c478bd9Sstevel@tonic-gate  * section so create one before calling it!
49167c478bd9Sstevel@tonic-gate  *
49177c478bd9Sstevel@tonic-gate  * RETURNS: 0 for ok,
49187c478bd9Sstevel@tonic-gate  *	else	errno from fdexec,
49197c478bd9Sstevel@tonic-gate  *	or	ENODEV if error (infers hardware type error)
49207c478bd9Sstevel@tonic-gate  *
49217c478bd9Sstevel@tonic-gate  *	- called with the low level lock held
49227c478bd9Sstevel@tonic-gate  */
49237c478bd9Sstevel@tonic-gate static int
49247c478bd9Sstevel@tonic-gate fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg)
49257c478bd9Sstevel@tonic-gate {
49267c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
49277c478bd9Sstevel@tonic-gate 	int result;
49287c478bd9Sstevel@tonic-gate 
49297c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
49307c478bd9Sstevel@tonic-gate 
49317c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RECA, (C, "fdrecalseek to %d\n", arg));
49327c478bd9Sstevel@tonic-gate 
49337c478bd9Sstevel@tonic-gate 	/* XXX TODO: check see argument for <= num cyls OR < 256 */
49347c478bd9Sstevel@tonic-gate 
49357c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
49367c478bd9Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
49377c478bd9Sstevel@tonic-gate 	csb->csb_cmds[1] = unit & 0x03;
49387c478bd9Sstevel@tonic-gate 
49397c478bd9Sstevel@tonic-gate 	if (arg == -1) {			/* is recal... */
49407c478bd9Sstevel@tonic-gate 		csb->csb_cmds[0] = FDRAW_REZERO;
49417c478bd9Sstevel@tonic-gate 		csb->csb_ncmds = 2;
49427c478bd9Sstevel@tonic-gate 	} else {
49437c478bd9Sstevel@tonic-gate 		csb->csb_cmds[0] = FDRAW_SEEK;
49447c478bd9Sstevel@tonic-gate 		csb->csb_cmds[2] = (uchar_t)arg;
49457c478bd9Sstevel@tonic-gate 		csb->csb_ncmds = 3;
49467c478bd9Sstevel@tonic-gate 	}
49477c478bd9Sstevel@tonic-gate 	csb->csb_nrslts = 2;	/* 2 for SENSE INTERRUPTS */
49487c478bd9Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFSEEKOPS | CSB_OFTIMEIT;
49497c478bd9Sstevel@tonic-gate 	/*
49507c478bd9Sstevel@tonic-gate 	 * MAYBE NYD need to set retries to different values? - depending on
49517c478bd9Sstevel@tonic-gate 	 * drive characteristics - if we get to high capacity drives
49527c478bd9Sstevel@tonic-gate 	 */
49537c478bd9Sstevel@tonic-gate 	csb->csb_maxretry = skretry;
49547c478bd9Sstevel@tonic-gate 	csb->csb_retrys = 0;
49557c478bd9Sstevel@tonic-gate 
49567c478bd9Sstevel@tonic-gate 	/* send cmd off to fdexec */
49577c478bd9Sstevel@tonic-gate 	if (result = fdexec(fdc, FDXC_SLEEP | execflg)) {
49587c478bd9Sstevel@tonic-gate 		goto out;
49597c478bd9Sstevel@tonic-gate 	}
49607c478bd9Sstevel@tonic-gate 
49617c478bd9Sstevel@tonic-gate 	/*
49627c478bd9Sstevel@tonic-gate 	 * if recal, test for equipment check error
49637c478bd9Sstevel@tonic-gate 	 * ASSUMES result = 0 from above call
49647c478bd9Sstevel@tonic-gate 	 */
49657c478bd9Sstevel@tonic-gate 	if (arg == -1) {
49667c478bd9Sstevel@tonic-gate 		result = 0;
49677c478bd9Sstevel@tonic-gate 	} else {
49687c478bd9Sstevel@tonic-gate 		/* for seeks, any old error will do */
49697c478bd9Sstevel@tonic-gate 		if ((csb->csb_rslt[0] & IC_SR0) || csb->csb_cmdstat)
49707c478bd9Sstevel@tonic-gate 			result = ENODEV;
49717c478bd9Sstevel@tonic-gate 	}
49727c478bd9Sstevel@tonic-gate 
49737c478bd9Sstevel@tonic-gate out:
49747c478bd9Sstevel@tonic-gate 	return (result);
49757c478bd9Sstevel@tonic-gate }
49767c478bd9Sstevel@tonic-gate 
49777c478bd9Sstevel@tonic-gate /*
49787c478bd9Sstevel@tonic-gate  * fdsensedrv
49797c478bd9Sstevel@tonic-gate  *	do a sense_drive command.  used by fdopen and fdcheckdisk.
49807c478bd9Sstevel@tonic-gate  *
49817c478bd9Sstevel@tonic-gate  *	- called with the lock held
49827c478bd9Sstevel@tonic-gate  */
49837c478bd9Sstevel@tonic-gate static int
49847c478bd9Sstevel@tonic-gate fdsensedrv(struct fdctlr *fdc, int unit)
49857c478bd9Sstevel@tonic-gate {
49867c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
49877c478bd9Sstevel@tonic-gate 
49887c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
49897c478bd9Sstevel@tonic-gate 
49907c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
49917c478bd9Sstevel@tonic-gate 
49927c478bd9Sstevel@tonic-gate 	/* setup common things in csb */
49937c478bd9Sstevel@tonic-gate 	csb->csb_unit = (uchar_t)unit;
49947c478bd9Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFIMMEDIATE;
49957c478bd9Sstevel@tonic-gate 	csb->csb_cmds[0] = FDRAW_SENSE_DRV;
49967c478bd9Sstevel@tonic-gate 	/* MOT bit set means don't delay */
49977c478bd9Sstevel@tonic-gate 	csb->csb_cmds[1] = MOT | (unit & 0x03);
49987c478bd9Sstevel@tonic-gate 	csb->csb_ncmds = 2;
49997c478bd9Sstevel@tonic-gate 	csb->csb_nrslts = 1;
50007c478bd9Sstevel@tonic-gate 	csb->csb_maxretry = skretry;
50017c478bd9Sstevel@tonic-gate 	csb->csb_retrys = 0;
50027c478bd9Sstevel@tonic-gate 
50037c478bd9Sstevel@tonic-gate 	/* XXX for now ignore errors, they "CAN'T HAPPEN" */
50047c478bd9Sstevel@tonic-gate 	(void) fdexec(fdc, 0);	/* DON't check changed!, no sleep */
50057c478bd9Sstevel@tonic-gate 
50067c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CHEK,
50077c478bd9Sstevel@tonic-gate 	    (C, "fdsensedrv: result 0x%x", csb->csb_rslt[0]));
50087c478bd9Sstevel@tonic-gate 
50097c478bd9Sstevel@tonic-gate 	return (csb->csb_rslt[0]); /* return status byte 3 */
50107c478bd9Sstevel@tonic-gate }
50117c478bd9Sstevel@tonic-gate 
50127c478bd9Sstevel@tonic-gate /*
50137c478bd9Sstevel@tonic-gate  * fdcheckdisk
50147c478bd9Sstevel@tonic-gate  *	check to see if the disk is still there - do a recalibrate,
50157c478bd9Sstevel@tonic-gate  *	then see if DSKCHG line went away, if so, diskette is in; else
50167c478bd9Sstevel@tonic-gate  *	it's (still) out.
50177c478bd9Sstevel@tonic-gate  */
50187c478bd9Sstevel@tonic-gate 
50197c478bd9Sstevel@tonic-gate static int
50207c478bd9Sstevel@tonic-gate fdcheckdisk(struct fdctlr *fdc, int unit)
50217c478bd9Sstevel@tonic-gate {
50227c478bd9Sstevel@tonic-gate 	auto struct fdcsb savecsb;
50237c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
50247c478bd9Sstevel@tonic-gate 	int	err, st3;
50257c478bd9Sstevel@tonic-gate 	int	seekto;			/* where to seek for reset of DSKCHG */
50267c478bd9Sstevel@tonic-gate 
50277c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CHEK,
50287c478bd9Sstevel@tonic-gate 	    (C, "fdcheckdisk, unit %d\n", unit));
50297c478bd9Sstevel@tonic-gate 
50307c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
50317c478bd9Sstevel@tonic-gate 
50327c478bd9Sstevel@tonic-gate 	/*
50337c478bd9Sstevel@tonic-gate 	 * save old csb
50347c478bd9Sstevel@tonic-gate 	 */
50357c478bd9Sstevel@tonic-gate 
50367c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
50377c478bd9Sstevel@tonic-gate 	savecsb = fdc->c_csb;
50387c478bd9Sstevel@tonic-gate 	bzero((caddr_t)csb, sizeof (*csb));
50397c478bd9Sstevel@tonic-gate 
50407c478bd9Sstevel@tonic-gate 	/*
50417c478bd9Sstevel@tonic-gate 	 * Read drive status to see if at TRK0, if so, seek to cyl 1,
50427c478bd9Sstevel@tonic-gate 	 * else seek to cyl 0.	We do this because the controller is
50437c478bd9Sstevel@tonic-gate 	 * "smart" enough to not send any step pulses (which are how
50447c478bd9Sstevel@tonic-gate 	 * the DSKCHG line gets reset) if it sees TRK0 'cause it
50457c478bd9Sstevel@tonic-gate 	 * knows the drive is already recalibrated.
50467c478bd9Sstevel@tonic-gate 	 */
50477c478bd9Sstevel@tonic-gate 	st3 = fdsensedrv(fdc, unit);
50487c478bd9Sstevel@tonic-gate 
50497c478bd9Sstevel@tonic-gate 	/* check TRK0 bit in status */
50507c478bd9Sstevel@tonic-gate 	if (st3 & T0_SR3)
50517c478bd9Sstevel@tonic-gate 		seekto = 1;	/* at TRK0, seek out */
50527c478bd9Sstevel@tonic-gate 	else
50537c478bd9Sstevel@tonic-gate 		seekto = 0;
50547c478bd9Sstevel@tonic-gate 
50557c478bd9Sstevel@tonic-gate 	/*
50567c478bd9Sstevel@tonic-gate 	 * DON'T recurse check changed
50577c478bd9Sstevel@tonic-gate 	 */
50587c478bd9Sstevel@tonic-gate 	err = fdrecalseek(fdc, unit, seekto, 0);
50597c478bd9Sstevel@tonic-gate 
50607c478bd9Sstevel@tonic-gate 	/* "restore" old csb, check change state */
50617c478bd9Sstevel@tonic-gate 	fdc->c_csb = savecsb;
50627c478bd9Sstevel@tonic-gate 
50637c478bd9Sstevel@tonic-gate 	/* any recal/seek errors are too serious to attend to */
50647c478bd9Sstevel@tonic-gate 	if (err) {
50657c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_CHEK,
50667c478bd9Sstevel@tonic-gate 		    (C, "fdcheckdisk err %d\n", err));
50677c478bd9Sstevel@tonic-gate 		return (err);
50687c478bd9Sstevel@tonic-gate 	}
50697c478bd9Sstevel@tonic-gate 
50707c478bd9Sstevel@tonic-gate 	/*
50717c478bd9Sstevel@tonic-gate 	 * if disk change still asserted, no diskette in drive!
50727c478bd9Sstevel@tonic-gate 	 */
50737c478bd9Sstevel@tonic-gate 	if (fdsense_chng(fdc, csb->csb_unit)) {
50747c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_CHEK,
50757c478bd9Sstevel@tonic-gate 		    (C, "fdcheckdisk no disk\n"));
50767c478bd9Sstevel@tonic-gate 		return (1);
50777c478bd9Sstevel@tonic-gate 	}
50787c478bd9Sstevel@tonic-gate 	return (0);
50797c478bd9Sstevel@tonic-gate }
50807c478bd9Sstevel@tonic-gate 
50817c478bd9Sstevel@tonic-gate /*
50827c478bd9Sstevel@tonic-gate  *	fdselect() - select drive, needed for external to chip select logic
50837c478bd9Sstevel@tonic-gate  *	fdeject() - ejects drive, must be previously selected
50847c478bd9Sstevel@tonic-gate  *	fdsense_chng() - sense disk changed line from previously selected drive
50857c478bd9Sstevel@tonic-gate  *		return s 1 is signal asserted, else 0
50867c478bd9Sstevel@tonic-gate  */
50877c478bd9Sstevel@tonic-gate /* ARGSUSED */
50887c478bd9Sstevel@tonic-gate static void
50897c478bd9Sstevel@tonic-gate fdselect(struct fdctlr *fdc, int unit, int on)
50907c478bd9Sstevel@tonic-gate {
50917c478bd9Sstevel@tonic-gate 
50927c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
50937c478bd9Sstevel@tonic-gate 
50947c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_DSEL,
50957c478bd9Sstevel@tonic-gate 	    (C, "fdselect, unit %d, on = %d\n", unit, on));
50967c478bd9Sstevel@tonic-gate 
50977c478bd9Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
50987c478bd9Sstevel@tonic-gate 	case FDCTYPE_MACHIO:
50997c478bd9Sstevel@tonic-gate 		set_auxioreg(AUX_DRVSELECT, on);
51007c478bd9Sstevel@tonic-gate 		break;
51017c478bd9Sstevel@tonic-gate 
51027c478bd9Sstevel@tonic-gate 	case FDCTYPE_SLAVIO:
51037c478bd9Sstevel@tonic-gate 	case FDCTYPE_CHEERIO:
51047c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
51057c478bd9Sstevel@tonic-gate 		    (C, "fdselect: (before) Dor 0x%x\n", Dor(fdc)));
51067c478bd9Sstevel@tonic-gate 
51077c478bd9Sstevel@tonic-gate 		if (unit == 0) {
51087c478bd9Sstevel@tonic-gate 			Set_dor(fdc, DRVSEL, !on);
51097c478bd9Sstevel@tonic-gate 		} else {
51107c478bd9Sstevel@tonic-gate 			Set_dor(fdc, DRVSEL, on);
51117c478bd9Sstevel@tonic-gate 		}
51127c478bd9Sstevel@tonic-gate 
51137c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
51147c478bd9Sstevel@tonic-gate 		    (C, "fdselect: Dor 0x%x\n", Dor(fdc)));
51157c478bd9Sstevel@tonic-gate 
51167c478bd9Sstevel@tonic-gate 		break;
51177c478bd9Sstevel@tonic-gate 
51187c478bd9Sstevel@tonic-gate 	default:
51197c478bd9Sstevel@tonic-gate 		break;
51207c478bd9Sstevel@tonic-gate 	}
51217c478bd9Sstevel@tonic-gate }
51227c478bd9Sstevel@tonic-gate 
51237c478bd9Sstevel@tonic-gate /* ARGSUSED */
51247c478bd9Sstevel@tonic-gate static void
51257c478bd9Sstevel@tonic-gate fdeject(struct fdctlr *fdc, int unit)
51267c478bd9Sstevel@tonic-gate {
51277c478bd9Sstevel@tonic-gate 	struct fdunit *un;
51287c478bd9Sstevel@tonic-gate 
51297c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
51307c478bd9Sstevel@tonic-gate 
51317c478bd9Sstevel@tonic-gate 	un = fdc->c_un;
51327c478bd9Sstevel@tonic-gate 
51337c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_EJEC, (C, "fdeject\n"));
51347c478bd9Sstevel@tonic-gate 	/*
51357c478bd9Sstevel@tonic-gate 	 * assume delay of function calling sufficient settling time
51367c478bd9Sstevel@tonic-gate 	 * eject line is NOT driven by inverter so it is true low
51377c478bd9Sstevel@tonic-gate 	 */
51387c478bd9Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
51397c478bd9Sstevel@tonic-gate 	case FDCTYPE_MACHIO:
51407c478bd9Sstevel@tonic-gate 		set_auxioreg(AUX_EJECT, 0);
51417c478bd9Sstevel@tonic-gate 		drv_usecwait(2);
51427c478bd9Sstevel@tonic-gate 		set_auxioreg(AUX_EJECT, 1);
51437c478bd9Sstevel@tonic-gate 		break;
51447c478bd9Sstevel@tonic-gate 
51457c478bd9Sstevel@tonic-gate 	case FDCTYPE_SLAVIO:
51467c478bd9Sstevel@tonic-gate 		if (!(Dor(fdc) & MOTEN(unit))) {
51477c478bd9Sstevel@tonic-gate 			/* LINTED */
51487c478bd9Sstevel@tonic-gate 			Set_dor(fdc, MOTEN(unit), 1);
51497c478bd9Sstevel@tonic-gate 		}
51507c478bd9Sstevel@tonic-gate 		drv_usecwait(2);	/* just to settle */
51517c478bd9Sstevel@tonic-gate 		/* LINTED */
51527c478bd9Sstevel@tonic-gate 		Set_dor(fdc, EJECT, 1);
51537c478bd9Sstevel@tonic-gate 		drv_usecwait(2);
51547c478bd9Sstevel@tonic-gate 		/* LINTED */
51557c478bd9Sstevel@tonic-gate 		Set_dor(fdc, EJECT, 0);
51567c478bd9Sstevel@tonic-gate 		break;
51577c478bd9Sstevel@tonic-gate 	case FDCTYPE_CHEERIO:
51587c478bd9Sstevel@tonic-gate 		if (!(Dor(fdc) & MOTEN(unit))) {
51597c478bd9Sstevel@tonic-gate 			/* LINTED */
51607c478bd9Sstevel@tonic-gate 			Set_dor(fdc, MOTEN(unit), 1);
51617c478bd9Sstevel@tonic-gate 		}
51627c478bd9Sstevel@tonic-gate 		drv_usecwait(2);	/* just to settle */
51637c478bd9Sstevel@tonic-gate 		/* LINTED */
51647c478bd9Sstevel@tonic-gate 		Set_dor(fdc, EJECT_DMA, 1);
51657c478bd9Sstevel@tonic-gate 		drv_usecwait(2);
51667c478bd9Sstevel@tonic-gate 		/* LINTED */
51677c478bd9Sstevel@tonic-gate 		Set_dor(fdc, EJECT_DMA, 0);
51687c478bd9Sstevel@tonic-gate 		break;
51697c478bd9Sstevel@tonic-gate 	}
51707c478bd9Sstevel@tonic-gate 	/*
51717c478bd9Sstevel@tonic-gate 	 * XXX set ejected state?
51727c478bd9Sstevel@tonic-gate 	 */
51737c478bd9Sstevel@tonic-gate 	un->un_ejected = 1;
51747c478bd9Sstevel@tonic-gate }
51757c478bd9Sstevel@tonic-gate 
51767c478bd9Sstevel@tonic-gate /* ARGSUSED */
51777c478bd9Sstevel@tonic-gate static int
51787c478bd9Sstevel@tonic-gate fdsense_chng(struct fdctlr *fdc, int unit)
51797c478bd9Sstevel@tonic-gate {
51807c478bd9Sstevel@tonic-gate 	int changed = 0;
51817c478bd9Sstevel@tonic-gate 
51827c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:start\n"));
51837c478bd9Sstevel@tonic-gate 
51847c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
51857c478bd9Sstevel@tonic-gate 
51867c478bd9Sstevel@tonic-gate 	/*
51877c478bd9Sstevel@tonic-gate 	 * Do not turn on the motor of a pollable drive
51887c478bd9Sstevel@tonic-gate 	 */
51897c478bd9Sstevel@tonic-gate 	if (fd_pollable) {
51907c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "pollable: don't turn on motor\n"));
51917c478bd9Sstevel@tonic-gate 		/*
51927c478bd9Sstevel@tonic-gate 		 * Invert the sense of the DSKCHG for pollable drives
51937c478bd9Sstevel@tonic-gate 		 */
51947c478bd9Sstevel@tonic-gate 		if (Dir(fdc) & DSKCHG)
51957c478bd9Sstevel@tonic-gate 			changed = 0;
51967c478bd9Sstevel@tonic-gate 		else
51977c478bd9Sstevel@tonic-gate 			changed = 1;
51987c478bd9Sstevel@tonic-gate 
51997c478bd9Sstevel@tonic-gate 		return (changed);
52007c478bd9Sstevel@tonic-gate 	}
52017c478bd9Sstevel@tonic-gate 
52027c478bd9Sstevel@tonic-gate 	switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
52037c478bd9Sstevel@tonic-gate 	case FDCTYPE_MACHIO:
52047c478bd9Sstevel@tonic-gate 		if (*fdc->c_auxiova & AUX_DISKCHG)
52057c478bd9Sstevel@tonic-gate 			changed = 1;
52067c478bd9Sstevel@tonic-gate 		break;
52077c478bd9Sstevel@tonic-gate 
52087c478bd9Sstevel@tonic-gate 	case FDCTYPE_SB:
52097c478bd9Sstevel@tonic-gate 	case FDCTYPE_SLAVIO:
52107c478bd9Sstevel@tonic-gate 	case FDCTYPE_CHEERIO:
52117c478bd9Sstevel@tonic-gate 		if (!(Dor(fdc) & MOTEN(unit))) {
52127c478bd9Sstevel@tonic-gate 			/* LINTED */
52137c478bd9Sstevel@tonic-gate 			Set_dor(fdc, MOTEN(unit), 1);
52147c478bd9Sstevel@tonic-gate 		}
52157c478bd9Sstevel@tonic-gate 		drv_usecwait(2);	/* just to settle */
52167c478bd9Sstevel@tonic-gate 		if (Dir(fdc) & DSKCHG)
52177c478bd9Sstevel@tonic-gate 			changed = 1;
52187c478bd9Sstevel@tonic-gate 		break;
52197c478bd9Sstevel@tonic-gate 	}
52207c478bd9Sstevel@tonic-gate 
52217c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:end\n"));
52227c478bd9Sstevel@tonic-gate 
52237c478bd9Sstevel@tonic-gate 	return (changed);
52247c478bd9Sstevel@tonic-gate }
52257c478bd9Sstevel@tonic-gate 
52267c478bd9Sstevel@tonic-gate /*
52277c478bd9Sstevel@tonic-gate  *	if it can read a valid label it does so, else it will use a
52287c478bd9Sstevel@tonic-gate  *	default.  If it can`t read the diskette - that is an error.
52297c478bd9Sstevel@tonic-gate  *
52307c478bd9Sstevel@tonic-gate  * RETURNS: 0 for ok - meaning that it could at least read the device,
52317c478bd9Sstevel@tonic-gate  *	!0 for error XXX TBD NYD error codes
52327c478bd9Sstevel@tonic-gate  *
52337c478bd9Sstevel@tonic-gate  *	- called with the low level lock held
52347c478bd9Sstevel@tonic-gate  */
52357c478bd9Sstevel@tonic-gate static int
52367c478bd9Sstevel@tonic-gate fdgetlabel(struct fdctlr *fdc, int unit)
52377c478bd9Sstevel@tonic-gate {
52387c478bd9Sstevel@tonic-gate 	struct dk_label *label = NULL;
52397c478bd9Sstevel@tonic-gate 	struct fdunit *un;
52407c478bd9Sstevel@tonic-gate 	short *sp;
52417c478bd9Sstevel@tonic-gate 	short count;
52427c478bd9Sstevel@tonic-gate 	short xsum;			/* checksum */
52437c478bd9Sstevel@tonic-gate 	int	i, tries;
52447c478bd9Sstevel@tonic-gate 	int	err = 0;
52457c478bd9Sstevel@tonic-gate 	short	oldlvl;
52467c478bd9Sstevel@tonic-gate 
52477c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
52487c478bd9Sstevel@tonic-gate 	    (C, "fdgetlabel: unit %d\n", unit));
52497c478bd9Sstevel@tonic-gate 
52507c478bd9Sstevel@tonic-gate 	un = fdc->c_un;
52517c478bd9Sstevel@tonic-gate 	un->un_flags &= ~(FDUNIT_UNLABELED);
52527c478bd9Sstevel@tonic-gate 
52537c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
52547c478bd9Sstevel@tonic-gate 
52557c478bd9Sstevel@tonic-gate 	/* Do not print errors since this is a private cmd */
52567c478bd9Sstevel@tonic-gate 
52577c478bd9Sstevel@tonic-gate 	oldlvl = fderrlevel;
52587c478bd9Sstevel@tonic-gate 
52597c478bd9Sstevel@tonic-gate 
52607c478bd9Sstevel@tonic-gate 	fderrlevel = FDEP_L4;
52617c478bd9Sstevel@tonic-gate 
52627c478bd9Sstevel@tonic-gate 	label = (struct dk_label *)
52637c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
52647c478bd9Sstevel@tonic-gate 
52657c478bd9Sstevel@tonic-gate 	/*
52667c478bd9Sstevel@tonic-gate 	 * try different characteristics (ie densities) by attempting to read
52677c478bd9Sstevel@tonic-gate 	 * from the diskette.  The diskette may not be present or
52687c478bd9Sstevel@tonic-gate 	 * is unformatted.
52697c478bd9Sstevel@tonic-gate 	 *
52707c478bd9Sstevel@tonic-gate 	 * First, the last sector of the first track is read.  If this
52717c478bd9Sstevel@tonic-gate 	 * passes, attempt to read the last sector + 1 of the first track.
52727c478bd9Sstevel@tonic-gate 	 * For example, for a high density diskette, sector 18 is read.  If
52737c478bd9Sstevel@tonic-gate 	 * the diskette is high density, this will pass.  Next, try to
52747c478bd9Sstevel@tonic-gate 	 * read sector 19 of the first track.  This should fail.  If it
52757c478bd9Sstevel@tonic-gate 	 * passes, this is not a high density diskette.  Finally, read
52767c478bd9Sstevel@tonic-gate 	 * the first sector which should contain a label.
52777c478bd9Sstevel@tonic-gate 	 *
52787c478bd9Sstevel@tonic-gate 	 * if un->un_curfdtype is -1 then the current characteristics
52797c478bd9Sstevel@tonic-gate 	 * were set by FDIOSCHAR and need to try it as well as everything
52807c478bd9Sstevel@tonic-gate 	 * in the table
52817c478bd9Sstevel@tonic-gate 	 */
52827c478bd9Sstevel@tonic-gate 	if (un->un_curfdtype == -1) {
52837c478bd9Sstevel@tonic-gate 		tries = nfdtypes+1;
52847c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
52857c478bd9Sstevel@tonic-gate 		    (C, "fdgetl: un_curfdtype is -1\n"));
52867c478bd9Sstevel@tonic-gate 
52877c478bd9Sstevel@tonic-gate 	} else {
52887c478bd9Sstevel@tonic-gate 		tries = nfdtypes;
52897c478bd9Sstevel@tonic-gate 
52907c478bd9Sstevel@tonic-gate 		/* Always start with the highest density (1.7MB) */
52917c478bd9Sstevel@tonic-gate 		un->un_curfdtype = 0;
52927c478bd9Sstevel@tonic-gate 		*(un->un_chars) = fdtypes[un->un_curfdtype];
52937c478bd9Sstevel@tonic-gate 	}
52947c478bd9Sstevel@tonic-gate 
52957c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
52967c478bd9Sstevel@tonic-gate 	    (C, "fdgetl: no. of tries %d\n", tries));
52977c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
52987c478bd9Sstevel@tonic-gate 	    (C, "fdgetl: no. of curfdtype %d\n", un->un_curfdtype));
52997c478bd9Sstevel@tonic-gate 
53007c478bd9Sstevel@tonic-gate 	for (i = 0; i < tries; i++) {
53017c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53027c478bd9Sstevel@tonic-gate 		    (C, "fdgetl: trying %d\n", i));
53037c478bd9Sstevel@tonic-gate 
53047c478bd9Sstevel@tonic-gate 		if (!(err = fdrw(fdc, unit, FDREAD, 0, 0,
53057c478bd9Sstevel@tonic-gate 		    un->un_chars->fdc_secptrack, (caddr_t)label,
53067c478bd9Sstevel@tonic-gate 		    sizeof (struct dk_label))) &&
53077c478bd9Sstevel@tonic-gate 
53087c478bd9Sstevel@tonic-gate 		    fdrw(fdc, unit, FDREAD, 0, 0,
53097c478bd9Sstevel@tonic-gate 		    un->un_chars->fdc_secptrack + 1,
53107c478bd9Sstevel@tonic-gate 		    (caddr_t)label, sizeof (struct dk_label)) &&
53117c478bd9Sstevel@tonic-gate 
53127c478bd9Sstevel@tonic-gate 		    !(err = fdrw(fdc, unit, FDREAD, 0, 0, 1, (caddr_t)label,
53137c478bd9Sstevel@tonic-gate 		    sizeof (struct dk_label)))) {
53147c478bd9Sstevel@tonic-gate 
53157c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_GETL,
53167c478bd9Sstevel@tonic-gate 				(C, "fdgetl: succeeded\n"));
53177c478bd9Sstevel@tonic-gate 
53187c478bd9Sstevel@tonic-gate 			break;
53197c478bd9Sstevel@tonic-gate 		}
53207c478bd9Sstevel@tonic-gate 
53217c478bd9Sstevel@tonic-gate 		/*
53227c478bd9Sstevel@tonic-gate 		 * try the next entry in the characteristics tbl
53237c478bd9Sstevel@tonic-gate 		 * If curfdtype is -1, the nxt entry in tbl is 0 (the first).
53247c478bd9Sstevel@tonic-gate 		 */
53257c478bd9Sstevel@tonic-gate 
53267c478bd9Sstevel@tonic-gate 		un->un_curfdtype = (un->un_curfdtype + 1) % nfdtypes;
53277c478bd9Sstevel@tonic-gate 		*(un->un_chars) = fdtypes[un->un_curfdtype];
53287c478bd9Sstevel@tonic-gate 
53297c478bd9Sstevel@tonic-gate 
53307c478bd9Sstevel@tonic-gate 	}
53317c478bd9Sstevel@tonic-gate 
53327c478bd9Sstevel@tonic-gate 	/* print errors again */
53337c478bd9Sstevel@tonic-gate 	fderrlevel = oldlvl;
53347c478bd9Sstevel@tonic-gate 
53357c478bd9Sstevel@tonic-gate 	/* Couldn't read anything */
53367c478bd9Sstevel@tonic-gate 	if (err) {
53377c478bd9Sstevel@tonic-gate 
53387c478bd9Sstevel@tonic-gate 		/* The default characteristics are high density (1.4MB) */
53397c478bd9Sstevel@tonic-gate 		un->un_curfdtype = 1;
53407c478bd9Sstevel@tonic-gate 		*(un->un_chars) = fdtypes[un->un_curfdtype];
53417c478bd9Sstevel@tonic-gate 
53427c478bd9Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_80, &un->un_label);
53437c478bd9Sstevel@tonic-gate 
53447c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53457c478bd9Sstevel@tonic-gate 		    (C, "fdgetl: Can't autosense diskette\n"));
53467c478bd9Sstevel@tonic-gate 
53477c478bd9Sstevel@tonic-gate 		goto out;
53487c478bd9Sstevel@tonic-gate 	}
53497c478bd9Sstevel@tonic-gate 
53507c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
53517c478bd9Sstevel@tonic-gate 	    (C, "fdgetl: fdtype=%d !!!\n", un->un_curfdtype));
53527c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
53537c478bd9Sstevel@tonic-gate 	    (C, "fdgetl: rate=%d ssize=%d !!!\n",
53547c478bd9Sstevel@tonic-gate 	    un->un_chars->fdc_transfer_rate, un->un_chars->fdc_sec_size));
53557c478bd9Sstevel@tonic-gate 
53567c478bd9Sstevel@tonic-gate 	/*
53577c478bd9Sstevel@tonic-gate 	 * _something_ was read	 -  look for unixtype label
53587c478bd9Sstevel@tonic-gate 	 */
53597c478bd9Sstevel@tonic-gate 	if (label->dkl_magic != DKL_MAGIC) {
53607c478bd9Sstevel@tonic-gate 
53617c478bd9Sstevel@tonic-gate 		/*
53627c478bd9Sstevel@tonic-gate 		 * The label isn't a unix label.  However, the diskette
53637c478bd9Sstevel@tonic-gate 		 * is formatted because we were able to read the first
53647c478bd9Sstevel@tonic-gate 		 * cylinder.
53657c478bd9Sstevel@tonic-gate 		 */
53667c478bd9Sstevel@tonic-gate 
53677c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53687c478bd9Sstevel@tonic-gate 		    (C, "fdgetl: not unix label\n"));
53697c478bd9Sstevel@tonic-gate 
53707c478bd9Sstevel@tonic-gate 		goto nolabel;
53717c478bd9Sstevel@tonic-gate 	}
53727c478bd9Sstevel@tonic-gate 
53737c478bd9Sstevel@tonic-gate 	/*
53747c478bd9Sstevel@tonic-gate 	 * Checksum the label
53757c478bd9Sstevel@tonic-gate 	 */
53767c478bd9Sstevel@tonic-gate 	count = sizeof (struct dk_label)/sizeof (short);
53777c478bd9Sstevel@tonic-gate 	sp = (short *)label;
53787c478bd9Sstevel@tonic-gate 	xsum = 0;
53797c478bd9Sstevel@tonic-gate 	while (count--)
53807c478bd9Sstevel@tonic-gate 		xsum ^= *sp++;	/* should add up to 0 */
53817c478bd9Sstevel@tonic-gate 	if (xsum) {
53827c478bd9Sstevel@tonic-gate 
53837c478bd9Sstevel@tonic-gate 		/*
53847c478bd9Sstevel@tonic-gate 		 * The checksum fails.  However, the diskette is formatted
53857c478bd9Sstevel@tonic-gate 		 * because we were able to read the first cylinder
53867c478bd9Sstevel@tonic-gate 		 */
53877c478bd9Sstevel@tonic-gate 
53887c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_GETL,
53897c478bd9Sstevel@tonic-gate 		    (C, "fdgetl: bad cksum\n"));
53907c478bd9Sstevel@tonic-gate 
53917c478bd9Sstevel@tonic-gate 		goto nolabel;
53927c478bd9Sstevel@tonic-gate 	}
53937c478bd9Sstevel@tonic-gate 
53947c478bd9Sstevel@tonic-gate 	/*
53957c478bd9Sstevel@tonic-gate 	 * The diskette has a unix label with a correct checksum.
53967c478bd9Sstevel@tonic-gate 	 * Copy the label into the unit structure
53977c478bd9Sstevel@tonic-gate 	 */
53987c478bd9Sstevel@tonic-gate 	un->un_label = *label;
53997c478bd9Sstevel@tonic-gate 
54007c478bd9Sstevel@tonic-gate 	goto out;
54017c478bd9Sstevel@tonic-gate 
54027c478bd9Sstevel@tonic-gate nolabel:
54037c478bd9Sstevel@tonic-gate 	/*
54047c478bd9Sstevel@tonic-gate 	 * The diskette doesn't have a correct unix label, but it is formatted.
54057c478bd9Sstevel@tonic-gate 	 * Use a default label according to the diskette's density
54067c478bd9Sstevel@tonic-gate 	 * (mark default used)
54077c478bd9Sstevel@tonic-gate 	 */
54087c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_GETL,
54097c478bd9Sstevel@tonic-gate 	    (C, "fdgetlabel: unit %d\n", unit));
54107c478bd9Sstevel@tonic-gate 	un->un_flags |= FDUNIT_UNLABELED;
54117c478bd9Sstevel@tonic-gate 	switch (un->un_chars->fdc_secptrack) {
54127c478bd9Sstevel@tonic-gate 	case 9:
54137c478bd9Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_low_80, &un->un_label);
54147c478bd9Sstevel@tonic-gate 		break;
54157c478bd9Sstevel@tonic-gate 	case 8:
54167c478bd9Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_medium_80, &un->un_label);
54177c478bd9Sstevel@tonic-gate 		break;
54187c478bd9Sstevel@tonic-gate 	case 18:
54197c478bd9Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_80, &un->un_label);
54207c478bd9Sstevel@tonic-gate 		break;
54217c478bd9Sstevel@tonic-gate 	case 21:
54227c478bd9Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_21, &un->un_label);
54237c478bd9Sstevel@tonic-gate 		break;
54247c478bd9Sstevel@tonic-gate 	default:
54257c478bd9Sstevel@tonic-gate 		fdunpacklabel(&fdlbl_high_80, &un->un_label);
54267c478bd9Sstevel@tonic-gate 		break;
54277c478bd9Sstevel@tonic-gate 	}
54287c478bd9Sstevel@tonic-gate 
54297c478bd9Sstevel@tonic-gate out:
54307c478bd9Sstevel@tonic-gate 	if (label != NULL)
54317c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)label, sizeof (struct dk_label));
54327c478bd9Sstevel@tonic-gate 	return (err);
54337c478bd9Sstevel@tonic-gate }
54347c478bd9Sstevel@tonic-gate 
54357c478bd9Sstevel@tonic-gate /*
54367c478bd9Sstevel@tonic-gate  * fdrw- used only for reading labels  and for DKIOCSVTOC ioctl
54377c478bd9Sstevel@tonic-gate  *	 which reads the 1 sector.
54387c478bd9Sstevel@tonic-gate  */
54397c478bd9Sstevel@tonic-gate static int
54407c478bd9Sstevel@tonic-gate fdrw(struct fdctlr *fdc, int unit, int rw, int cyl, int head,
54417c478bd9Sstevel@tonic-gate     int sector, caddr_t bufp, uint_t len)
54427c478bd9Sstevel@tonic-gate {
54437c478bd9Sstevel@tonic-gate 	struct fdcsb *csb;
54447c478bd9Sstevel@tonic-gate 	struct	fd_char *ch;
54457c478bd9Sstevel@tonic-gate 	int	cmdresult = 0;
54467c478bd9Sstevel@tonic-gate 	caddr_t dma_addr;
54477c478bd9Sstevel@tonic-gate 	size_t	real_length;
54487c478bd9Sstevel@tonic-gate 	int	res;
54497c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
54507c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	mem_handle = NULL;
54517c478bd9Sstevel@tonic-gate 
54527c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw\n"));
54537c478bd9Sstevel@tonic-gate 
54547c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
54557c478bd9Sstevel@tonic-gate 
54567c478bd9Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
54577c478bd9Sstevel@tonic-gate 
54587c478bd9Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
54597c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
54607c478bd9Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
54617c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
54627c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
54637c478bd9Sstevel@tonic-gate 			    failed. \n"));
54647c478bd9Sstevel@tonic-gate 			mutex_enter(&fdc->c_lolock);
54657c478bd9Sstevel@tonic-gate 			return (EIO);
54667c478bd9Sstevel@tonic-gate 		}
54677c478bd9Sstevel@tonic-gate 
54687c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
54697c478bd9Sstevel@tonic-gate 	}
54707c478bd9Sstevel@tonic-gate 
54717c478bd9Sstevel@tonic-gate 	fdgetcsb(fdc);
54727c478bd9Sstevel@tonic-gate 	csb = &fdc->c_csb;
54737c478bd9Sstevel@tonic-gate 	ch = fdc->c_un->un_chars;
54747c478bd9Sstevel@tonic-gate 	if (rw == FDREAD) {
54757c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_TCBUG) {
54767c478bd9Sstevel@tonic-gate 			/*
54777c478bd9Sstevel@tonic-gate 			 * kludge for lack of Multitrack functionality
54787c478bd9Sstevel@tonic-gate 			 */
54797c478bd9Sstevel@tonic-gate 			csb->csb_cmds[0] = SK + FDRAW_RDCMD;
54807c478bd9Sstevel@tonic-gate 		} else
54817c478bd9Sstevel@tonic-gate 			csb->csb_cmds[0] = MT + SK + FDRAW_RDCMD;
54827c478bd9Sstevel@tonic-gate 	} else { /* write */
54837c478bd9Sstevel@tonic-gate 		if (fdc->c_fdtype & FDCTYPE_TCBUG) {
54847c478bd9Sstevel@tonic-gate 			/*
54857c478bd9Sstevel@tonic-gate 			 * kludge for lack of Multitrack functionality
54867c478bd9Sstevel@tonic-gate 			 */
54877c478bd9Sstevel@tonic-gate 			csb->csb_cmds[0] = FDRAW_WRCMD;
54887c478bd9Sstevel@tonic-gate 		} else
54897c478bd9Sstevel@tonic-gate 			csb->csb_cmds[0] = MT + FDRAW_WRCMD;
54907c478bd9Sstevel@tonic-gate 	}
54917c478bd9Sstevel@tonic-gate 
54927c478bd9Sstevel@tonic-gate 	if (rw == FDREAD)
54937c478bd9Sstevel@tonic-gate 		fdc->c_csb.csb_read = CSB_READ;
54947c478bd9Sstevel@tonic-gate 	else
54957c478bd9Sstevel@tonic-gate 		fdc->c_csb.csb_read = CSB_WRITE;
54967c478bd9Sstevel@tonic-gate 
54977c478bd9Sstevel@tonic-gate 	/* always or in MFM bit */
54987c478bd9Sstevel@tonic-gate 	csb->csb_cmds[0] |= MFM;
54997c478bd9Sstevel@tonic-gate 	csb->csb_cmds[1] = (uchar_t)(unit | ((head & 0x1) << 2));
55007c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB)
55017c478bd9Sstevel@tonic-gate 		csb->csb_cmds[1] |= IPS;
55027c478bd9Sstevel@tonic-gate 	csb->csb_cmds[2] = (uchar_t)cyl;
55037c478bd9Sstevel@tonic-gate 	csb->csb_cmds[3] = (uchar_t)head;
55047c478bd9Sstevel@tonic-gate 	csb->csb_cmds[4] = (uchar_t)sector;
55057c478bd9Sstevel@tonic-gate 	csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size code */
55067c478bd9Sstevel@tonic-gate 	/*
55077c478bd9Sstevel@tonic-gate 	 * kludge for end-of-cylinder error.
55087c478bd9Sstevel@tonic-gate 	 */
55097c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_TCBUG)
55107c478bd9Sstevel@tonic-gate 		csb->csb_cmds[6] = sector + (len / ch->fdc_sec_size) - 1;
55117c478bd9Sstevel@tonic-gate 	else
55127c478bd9Sstevel@tonic-gate 		csb->csb_cmds[6] =
55137c478bd9Sstevel@tonic-gate 		    (uchar_t)max(fdc->c_un->un_chars->fdc_secptrack, sector);
55147c478bd9Sstevel@tonic-gate 	csb->csb_len = len;
55157c478bd9Sstevel@tonic-gate 	csb->csb_cmds[7] = GPLN;
55167c478bd9Sstevel@tonic-gate 	csb->csb_cmds[8] = SSSDTL;
55177c478bd9Sstevel@tonic-gate 	csb->csb_ncmds = NCBRW;
55187c478bd9Sstevel@tonic-gate 	csb->csb_len = len;
55197c478bd9Sstevel@tonic-gate 	csb->csb_maxretry = 2;
55207c478bd9Sstevel@tonic-gate 	csb->csb_retrys = 0;
55217c478bd9Sstevel@tonic-gate 	bzero(csb->csb_rslt, NRBRW);
55227c478bd9Sstevel@tonic-gate 	csb->csb_nrslts = NRBRW;
55237c478bd9Sstevel@tonic-gate 	csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
55247c478bd9Sstevel@tonic-gate 
55257c478bd9Sstevel@tonic-gate 	/* If platform supports DMA, set up DMA resources */
55267c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
55277c478bd9Sstevel@tonic-gate 
55287c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
55297c478bd9Sstevel@tonic-gate 
55307c478bd9Sstevel@tonic-gate 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
55317c478bd9Sstevel@tonic-gate 		attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
55327c478bd9Sstevel@tonic-gate 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
55337c478bd9Sstevel@tonic-gate 
55347c478bd9Sstevel@tonic-gate 		res = ddi_dma_mem_alloc(fdc->c_dmahandle, len,
55357c478bd9Sstevel@tonic-gate 		    &attr, DDI_DMA_STREAMING,
55367c478bd9Sstevel@tonic-gate 		    DDI_DMA_DONTWAIT, 0, &dma_addr, &real_length,
55377c478bd9Sstevel@tonic-gate 		    &mem_handle);
55387c478bd9Sstevel@tonic-gate 
55397c478bd9Sstevel@tonic-gate 		if (res != DDI_SUCCESS) {
55407c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_RW,
55417c478bd9Sstevel@tonic-gate 			    (C, "fdrw: dma mem alloc failed\n"));
55427c478bd9Sstevel@tonic-gate 
55437c478bd9Sstevel@tonic-gate 			fdretcsb(fdc);
55447c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
55457c478bd9Sstevel@tonic-gate 			return (EIO);
55467c478bd9Sstevel@tonic-gate 		}
55477c478bd9Sstevel@tonic-gate 
55487c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: allocated memory"));
55497c478bd9Sstevel@tonic-gate 
55507c478bd9Sstevel@tonic-gate 		if (fdstart_dma(fdc, dma_addr, len) != 0) {
55517c478bd9Sstevel@tonic-gate 			fdretcsb(fdc);
55527c478bd9Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
55537c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_hilock);
55547c478bd9Sstevel@tonic-gate 			return (-1);
55557c478bd9Sstevel@tonic-gate 
55567c478bd9Sstevel@tonic-gate 		}
55577c478bd9Sstevel@tonic-gate 
55587c478bd9Sstevel@tonic-gate 		/*
55597c478bd9Sstevel@tonic-gate 		 * If the command is a write, copy the data to be written to
55607c478bd9Sstevel@tonic-gate 		 * dma_addr.
55617c478bd9Sstevel@tonic-gate 		 */
55627c478bd9Sstevel@tonic-gate 
55637c478bd9Sstevel@tonic-gate 		if (fdc->c_csb.csb_read == CSB_WRITE) {
55647c478bd9Sstevel@tonic-gate 			bcopy((char *)bufp, (char *)dma_addr, len);
55657c478bd9Sstevel@tonic-gate 		}
55667c478bd9Sstevel@tonic-gate 
55677c478bd9Sstevel@tonic-gate 		csb->csb_addr = dma_addr;
55687c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
55697c478bd9Sstevel@tonic-gate 	} else {
55707c478bd9Sstevel@tonic-gate 		csb->csb_addr = bufp;
55717c478bd9Sstevel@tonic-gate 	}
55727c478bd9Sstevel@tonic-gate 
55737c478bd9Sstevel@tonic-gate 
55747c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: call fdexec\n"));
55757c478bd9Sstevel@tonic-gate 
55767c478bd9Sstevel@tonic-gate 	if (fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG) != 0) {
55777c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
55787c478bd9Sstevel@tonic-gate 
55797c478bd9Sstevel@tonic-gate 		if (mem_handle)
55807c478bd9Sstevel@tonic-gate 			ddi_dma_mem_free(&mem_handle);
55817c478bd9Sstevel@tonic-gate 
55827c478bd9Sstevel@tonic-gate 		return (EIO);
55837c478bd9Sstevel@tonic-gate 
55847c478bd9Sstevel@tonic-gate 	}
55857c478bd9Sstevel@tonic-gate 
55867c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: fdexec returned\n"));
55877c478bd9Sstevel@tonic-gate 
55887c478bd9Sstevel@tonic-gate 	/*
55897c478bd9Sstevel@tonic-gate 	 * if DMA was used and the command was a read
55907c478bd9Sstevel@tonic-gate 	 * copy the results into bufp
55917c478bd9Sstevel@tonic-gate 	 */
55927c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
55937c478bd9Sstevel@tonic-gate 		if (fdc->c_csb.csb_read == CSB_READ) {
55947c478bd9Sstevel@tonic-gate 			bcopy((char *)dma_addr, (char *)bufp, len);
55957c478bd9Sstevel@tonic-gate 		}
55967c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&mem_handle);
55977c478bd9Sstevel@tonic-gate 	}
55987c478bd9Sstevel@tonic-gate 
55997c478bd9Sstevel@tonic-gate 	if (csb->csb_cmdstat)
56007c478bd9Sstevel@tonic-gate 		cmdresult = EIO;	/* XXX TBD NYD for now */
56017c478bd9Sstevel@tonic-gate 
56027c478bd9Sstevel@tonic-gate 	fdretcsb(fdc);
56037c478bd9Sstevel@tonic-gate 	return (cmdresult);
56047c478bd9Sstevel@tonic-gate }
56057c478bd9Sstevel@tonic-gate 
56067c478bd9Sstevel@tonic-gate /*
56077c478bd9Sstevel@tonic-gate  * fdunpacklabel
56087c478bd9Sstevel@tonic-gate  *	this unpacks a (packed) struct dk_label into a standard dk_label.
56097c478bd9Sstevel@tonic-gate  */
56107c478bd9Sstevel@tonic-gate static void
56117c478bd9Sstevel@tonic-gate fdunpacklabel(struct packed_label *from, struct dk_label *to)
56127c478bd9Sstevel@tonic-gate {
56137c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PACK, (C, "fdpacklabel\n"));
56147c478bd9Sstevel@tonic-gate 	bzero((caddr_t)to, sizeof (*to));
56157c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)&from->dkl_vname, (caddr_t)to->dkl_asciilabel,
56167c478bd9Sstevel@tonic-gate 	    sizeof (to->dkl_asciilabel));
56177c478bd9Sstevel@tonic-gate 	to->dkl_rpm = from->dkl_rpm;	/* rotations per minute */
56187c478bd9Sstevel@tonic-gate 	to->dkl_pcyl = from->dkl_pcyl;	/* # physical cylinders */
56197c478bd9Sstevel@tonic-gate 	to->dkl_apc = from->dkl_apc;	/* alternates per cylinder */
56207c478bd9Sstevel@tonic-gate 	to->dkl_intrlv = from->dkl_intrlv;	/* interleave factor */
56217c478bd9Sstevel@tonic-gate 	to->dkl_ncyl = from->dkl_ncyl;	/* # of data cylinders */
56227c478bd9Sstevel@tonic-gate 	to->dkl_acyl = from->dkl_acyl;	/* # of alternate cylinders */
56237c478bd9Sstevel@tonic-gate 	to->dkl_nhead = from->dkl_nhead; /* # of heads in this partition */
56247c478bd9Sstevel@tonic-gate 	to->dkl_nsect = from->dkl_nsect; /* # of 512 byte sectors per track */
56257c478bd9Sstevel@tonic-gate 	/* logical partitions */
56267c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)from->dkl_map, (caddr_t)to->dkl_map,
56277c478bd9Sstevel@tonic-gate 	    sizeof (struct dk_map32) * NDKMAP);
56287c478bd9Sstevel@tonic-gate 	to->dkl_vtoc = from->dkl_vtoc;
56297c478bd9Sstevel@tonic-gate }
56307c478bd9Sstevel@tonic-gate 
56317c478bd9Sstevel@tonic-gate static struct fdctlr *
56327c478bd9Sstevel@tonic-gate fd_getctlr(dev_t dev)
56337c478bd9Sstevel@tonic-gate {
56347c478bd9Sstevel@tonic-gate 
56357c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc = fdctlrs;
56367c478bd9Sstevel@tonic-gate 	int ctlr = FDCTLR(dev);
56377c478bd9Sstevel@tonic-gate 
56387c478bd9Sstevel@tonic-gate 	while (fdc) {
56397c478bd9Sstevel@tonic-gate 		if (ddi_get_instance(fdc->c_dip) == ctlr)
56407c478bd9Sstevel@tonic-gate 			return (fdc);
56417c478bd9Sstevel@tonic-gate 		fdc = fdc->c_next;
56427c478bd9Sstevel@tonic-gate 	}
56437c478bd9Sstevel@tonic-gate 	return (fdc);
56447c478bd9Sstevel@tonic-gate }
56457c478bd9Sstevel@tonic-gate 
56467c478bd9Sstevel@tonic-gate static int
56477c478bd9Sstevel@tonic-gate fd_unit_is_open(struct fdunit *un)
56487c478bd9Sstevel@tonic-gate {
56497c478bd9Sstevel@tonic-gate 	int i;
56507c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++)
56517c478bd9Sstevel@tonic-gate 		if (un->un_lyropen[i])
56527c478bd9Sstevel@tonic-gate 			return (1);
56537c478bd9Sstevel@tonic-gate 	for (i = 0; i < OTYPCNT - 1; i++)
56547c478bd9Sstevel@tonic-gate 		if (un->un_regopen[i])
56557c478bd9Sstevel@tonic-gate 			return (1);
56567c478bd9Sstevel@tonic-gate 	return (0);
56577c478bd9Sstevel@tonic-gate }
56587c478bd9Sstevel@tonic-gate 
56597c478bd9Sstevel@tonic-gate /*
56607c478bd9Sstevel@tonic-gate  * Return the a vtoc structure in *vtoc.
56617c478bd9Sstevel@tonic-gate  * The vtoc is built from information in
56627c478bd9Sstevel@tonic-gate  * the diskette's label.
56637c478bd9Sstevel@tonic-gate  */
56647c478bd9Sstevel@tonic-gate static void
56657c478bd9Sstevel@tonic-gate fd_build_user_vtoc(struct fdunit *un, struct vtoc *vtoc)
56667c478bd9Sstevel@tonic-gate {
56677c478bd9Sstevel@tonic-gate 	int i;
56687c478bd9Sstevel@tonic-gate 	int nblks;			/* DEV_BSIZE sectors per cylinder */
56697c478bd9Sstevel@tonic-gate 	struct dk_map2 *lpart;
56707c478bd9Sstevel@tonic-gate 	struct dk_map32	*lmap;
56717c478bd9Sstevel@tonic-gate 	struct partition *vpart;
56727c478bd9Sstevel@tonic-gate 
56737c478bd9Sstevel@tonic-gate 	bzero(vtoc, sizeof (struct vtoc));
56747c478bd9Sstevel@tonic-gate 
56757c478bd9Sstevel@tonic-gate 	/* Initialize info. needed by mboot.  (unsupported) */
56767c478bd9Sstevel@tonic-gate 	vtoc->v_bootinfo[0] = un->un_label.dkl_vtoc.v_bootinfo[0];
56777c478bd9Sstevel@tonic-gate 	vtoc->v_bootinfo[1] = un->un_label.dkl_vtoc.v_bootinfo[1];
56787c478bd9Sstevel@tonic-gate 	vtoc->v_bootinfo[2] = un->un_label.dkl_vtoc.v_bootinfo[2];
56797c478bd9Sstevel@tonic-gate 
56807c478bd9Sstevel@tonic-gate 	/* Fill in vtoc sanity and version information */
56817c478bd9Sstevel@tonic-gate 	vtoc->v_sanity		= un->un_label.dkl_vtoc.v_sanity;
56827c478bd9Sstevel@tonic-gate 	vtoc->v_version		= un->un_label.dkl_vtoc.v_version;
56837c478bd9Sstevel@tonic-gate 
56847c478bd9Sstevel@tonic-gate 	/* Copy the volume name */
56857c478bd9Sstevel@tonic-gate 	bcopy(un->un_label.dkl_vtoc.v_volume,
56867c478bd9Sstevel@tonic-gate 	    vtoc->v_volume, LEN_DKL_VVOL);
56877c478bd9Sstevel@tonic-gate 
56887c478bd9Sstevel@tonic-gate 	/*
56897c478bd9Sstevel@tonic-gate 	 * The dk_map32 structure is based on DEV_BSIZE byte blocks.
56907c478bd9Sstevel@tonic-gate 	 * However, medium density diskettes have 1024 byte blocks.
56917c478bd9Sstevel@tonic-gate 	 * The number of sectors per partition listed in the dk_map32 structure
56927c478bd9Sstevel@tonic-gate 	 * accounts for this by multiplying the number of 1024 byte
56937c478bd9Sstevel@tonic-gate 	 * blocks by 2.  (See the packed_label initializations.)  The
56947c478bd9Sstevel@tonic-gate 	 * 1024 byte block size can not be listed for medium density
56957c478bd9Sstevel@tonic-gate 	 * diskettes because the kernel is hard coded for DEV_BSIZE
56967c478bd9Sstevel@tonic-gate 	 * blocks.
56977c478bd9Sstevel@tonic-gate 	 */
56987c478bd9Sstevel@tonic-gate 	vtoc->v_sectorsz = DEV_BSIZE;
56997c478bd9Sstevel@tonic-gate 	vtoc->v_nparts = un->un_label.dkl_vtoc.v_nparts;
57007c478bd9Sstevel@tonic-gate 
57017c478bd9Sstevel@tonic-gate 	/* Copy the reserved space */
57027c478bd9Sstevel@tonic-gate 	bcopy(un->un_label.dkl_vtoc.v_reserved,
57037c478bd9Sstevel@tonic-gate 	    vtoc->v_reserved, sizeof (un->un_label.dkl_vtoc.v_reserved));
57047c478bd9Sstevel@tonic-gate 	/*
57057c478bd9Sstevel@tonic-gate 	 * Convert partitioning information.
57067c478bd9Sstevel@tonic-gate 	 *
57077c478bd9Sstevel@tonic-gate 	 * Note the conversion from starting cylinder number
57087c478bd9Sstevel@tonic-gate 	 * to starting sector number.
57097c478bd9Sstevel@tonic-gate 	 */
57107c478bd9Sstevel@tonic-gate 	lmap = un->un_label.dkl_map;
57117c478bd9Sstevel@tonic-gate 	lpart = un->un_label.dkl_vtoc.v_part;
57127c478bd9Sstevel@tonic-gate 	vpart = vtoc->v_part;
57137c478bd9Sstevel@tonic-gate 
57147c478bd9Sstevel@tonic-gate 	nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
57157c478bd9Sstevel@tonic-gate 	    un->un_chars->fdc_sec_size) / DEV_BSIZE;
57167c478bd9Sstevel@tonic-gate 
57177c478bd9Sstevel@tonic-gate 	for (i = 0; i < V_NUMPAR; i++) {
57187c478bd9Sstevel@tonic-gate 		vpart->p_tag	= lpart->p_tag;
57197c478bd9Sstevel@tonic-gate 		vpart->p_flag	= lpart->p_flag;
57207c478bd9Sstevel@tonic-gate 		vpart->p_start	= lmap->dkl_cylno * nblks;
57217c478bd9Sstevel@tonic-gate 		vpart->p_size	= lmap->dkl_nblk;
57227c478bd9Sstevel@tonic-gate 
57237c478bd9Sstevel@tonic-gate 		lmap++;
57247c478bd9Sstevel@tonic-gate 		lpart++;
57257c478bd9Sstevel@tonic-gate 		vpart++;
57267c478bd9Sstevel@tonic-gate 	}
57277c478bd9Sstevel@tonic-gate 
57287c478bd9Sstevel@tonic-gate 	/* Initialize timestamp and label */
57297c478bd9Sstevel@tonic-gate 	bcopy(un->un_label.dkl_vtoc.v_timestamp,
57307c478bd9Sstevel@tonic-gate 	    vtoc->timestamp, sizeof (vtoc->timestamp));
57317c478bd9Sstevel@tonic-gate 
57327c478bd9Sstevel@tonic-gate 	bcopy(un->un_label.dkl_asciilabel,
57337c478bd9Sstevel@tonic-gate 	    vtoc->v_asciilabel, LEN_DKL_ASCII);
57347c478bd9Sstevel@tonic-gate }
57357c478bd9Sstevel@tonic-gate 
57367c478bd9Sstevel@tonic-gate /*
57377c478bd9Sstevel@tonic-gate  * Build a label out of a vtoc structure.
57387c478bd9Sstevel@tonic-gate  */
57397c478bd9Sstevel@tonic-gate static int
57407c478bd9Sstevel@tonic-gate fd_build_label_vtoc(struct fdunit *un, struct vtoc *vtoc)
57417c478bd9Sstevel@tonic-gate {
57427c478bd9Sstevel@tonic-gate 	struct dk_map32		*lmap;
57437c478bd9Sstevel@tonic-gate 	struct dk_map2		*lpart;
57447c478bd9Sstevel@tonic-gate 	struct partition	*vpart;
57457c478bd9Sstevel@tonic-gate 	int			nblks;	/* no. blocks per cylinder */
57467c478bd9Sstevel@tonic-gate 	int			ncyl;
57477c478bd9Sstevel@tonic-gate 	int			i;
57487c478bd9Sstevel@tonic-gate 	short	 sum, *sp;
57497c478bd9Sstevel@tonic-gate 
57507c478bd9Sstevel@tonic-gate 	/* Sanity-check the vtoc */
57517c478bd9Sstevel@tonic-gate 	if ((vtoc->v_sanity != VTOC_SANE) ||
57527c478bd9Sstevel@tonic-gate 	    (vtoc->v_nparts > NDKMAP) || (vtoc->v_nparts <= 0)) {
57537c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_IOCT,
57547c478bd9Sstevel@tonic-gate 		    (C, "fd_build_label:  sanity check on vtoc failed\n"));
57557c478bd9Sstevel@tonic-gate 		return (EINVAL);
57567c478bd9Sstevel@tonic-gate 	}
57577c478bd9Sstevel@tonic-gate 
57587c478bd9Sstevel@tonic-gate 	nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
57597c478bd9Sstevel@tonic-gate 	    un->un_chars->fdc_sec_size) / DEV_BSIZE;
57607c478bd9Sstevel@tonic-gate 
57617c478bd9Sstevel@tonic-gate 	vpart = vtoc->v_part;
57627c478bd9Sstevel@tonic-gate 
57637c478bd9Sstevel@tonic-gate 	/*
57647c478bd9Sstevel@tonic-gate 	 * Check the partition information in the vtoc.  The starting sectors
57657c478bd9Sstevel@tonic-gate 	 * must lie along partition boundaries. (NDKMAP entries are checked
57667c478bd9Sstevel@tonic-gate 	 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
57677c478bd9Sstevel@tonic-gate 	 * is less than NDKMAP)
57687c478bd9Sstevel@tonic-gate 	 */
57697c478bd9Sstevel@tonic-gate 
57707c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
57717c478bd9Sstevel@tonic-gate 		if ((vpart->p_start % nblks) != 0) {
57727c478bd9Sstevel@tonic-gate 			return (EINVAL);
57737c478bd9Sstevel@tonic-gate 		}
57747c478bd9Sstevel@tonic-gate 		ncyl = vpart->p_start % nblks;
57757c478bd9Sstevel@tonic-gate 		ncyl += vpart->p_size % nblks;
57767c478bd9Sstevel@tonic-gate 		if ((vpart->p_size % nblks) != 0)
57777c478bd9Sstevel@tonic-gate 			ncyl++;
57787c478bd9Sstevel@tonic-gate 		if (ncyl > un->un_chars->fdc_ncyl) {
57797c478bd9Sstevel@tonic-gate 			return (EINVAL);
57807c478bd9Sstevel@tonic-gate 		}
57817c478bd9Sstevel@tonic-gate 		vpart++;
57827c478bd9Sstevel@tonic-gate 	}
57837c478bd9Sstevel@tonic-gate 
57847c478bd9Sstevel@tonic-gate 	/*
57857c478bd9Sstevel@tonic-gate 	 * reinitialize the existing label
57867c478bd9Sstevel@tonic-gate 	 */
57877c478bd9Sstevel@tonic-gate 	bzero(&un->un_label, sizeof (un->un_label));
57887c478bd9Sstevel@tonic-gate 
57897c478bd9Sstevel@tonic-gate 	/* Put appropriate vtoc structure fields into the disk label */
57907c478bd9Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_bootinfo[0] = (uint32_t)vtoc->v_bootinfo[0];
57917c478bd9Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_bootinfo[1] = (uint32_t)vtoc->v_bootinfo[1];
57927c478bd9Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_bootinfo[2] = (uint32_t)vtoc->v_bootinfo[2];
57937c478bd9Sstevel@tonic-gate 
57947c478bd9Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_sanity = vtoc->v_sanity;
57957c478bd9Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_version = vtoc->v_version;
57967c478bd9Sstevel@tonic-gate 
57977c478bd9Sstevel@tonic-gate 	bcopy(vtoc->v_volume, un->un_label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
57987c478bd9Sstevel@tonic-gate 
57997c478bd9Sstevel@tonic-gate 	un->un_label.dkl_vtoc.v_nparts = vtoc->v_nparts;
58007c478bd9Sstevel@tonic-gate 
58017c478bd9Sstevel@tonic-gate 	bcopy(vtoc->v_reserved, un->un_label.dkl_vtoc.v_reserved,
58027c478bd9Sstevel@tonic-gate 	    sizeof (un->un_label.dkl_vtoc.v_reserved));
58037c478bd9Sstevel@tonic-gate 
58047c478bd9Sstevel@tonic-gate 	/*
58057c478bd9Sstevel@tonic-gate 	 * Initialize cylinder information in the label.
58067c478bd9Sstevel@tonic-gate 	 * Note the conversion from starting sector number
58077c478bd9Sstevel@tonic-gate 	 * to starting cylinder number.
58087c478bd9Sstevel@tonic-gate 	 * Return error if division results in a remainder.
58097c478bd9Sstevel@tonic-gate 	 */
58107c478bd9Sstevel@tonic-gate 	lmap = un->un_label.dkl_map;
58117c478bd9Sstevel@tonic-gate 	lpart = un->un_label.dkl_vtoc.v_part;
58127c478bd9Sstevel@tonic-gate 	vpart = vtoc->v_part;
58137c478bd9Sstevel@tonic-gate 
58147c478bd9Sstevel@tonic-gate 	for (i = 0; i < (int)vtoc->v_nparts; i++) {
58157c478bd9Sstevel@tonic-gate 		lpart->p_tag  = vtoc->v_part[i].p_tag;
58167c478bd9Sstevel@tonic-gate 		lpart->p_flag = vtoc->v_part[i].p_flag;
58177c478bd9Sstevel@tonic-gate 		lmap->dkl_cylno = vpart->p_start / nblks;
58187c478bd9Sstevel@tonic-gate 		lmap->dkl_nblk = vpart->p_size;
58197c478bd9Sstevel@tonic-gate 
58207c478bd9Sstevel@tonic-gate 		lmap++;
58217c478bd9Sstevel@tonic-gate 		lpart++;
58227c478bd9Sstevel@tonic-gate 		vpart++;
58237c478bd9Sstevel@tonic-gate 	}
58247c478bd9Sstevel@tonic-gate 
58257c478bd9Sstevel@tonic-gate 	/* Copy the timestamp and ascii label */
58267c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
58277c478bd9Sstevel@tonic-gate 		un->un_label.dkl_vtoc.v_timestamp[i] = vtoc->timestamp[i];
58287c478bd9Sstevel@tonic-gate 	}
58297c478bd9Sstevel@tonic-gate 
58307c478bd9Sstevel@tonic-gate 
58317c478bd9Sstevel@tonic-gate 	bcopy(vtoc->v_asciilabel, un->un_label.dkl_asciilabel, LEN_DKL_ASCII);
58327c478bd9Sstevel@tonic-gate 
58337c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
58347c478bd9Sstevel@tonic-gate 	    (C, "fd_build_label: asciilabel %s\n",
58357c478bd9Sstevel@tonic-gate 	    un->un_label.dkl_asciilabel));
58367c478bd9Sstevel@tonic-gate 
58377c478bd9Sstevel@tonic-gate 	/* Initialize the magic number */
58387c478bd9Sstevel@tonic-gate 	un->un_label.dkl_magic = DKL_MAGIC;
58397c478bd9Sstevel@tonic-gate 
58407c478bd9Sstevel@tonic-gate 	un->un_label.dkl_pcyl = un->un_chars->fdc_ncyl;
58417c478bd9Sstevel@tonic-gate 
58427c478bd9Sstevel@tonic-gate 	/*
58437c478bd9Sstevel@tonic-gate 	 * The fdc_secptrack filed of the fd_char structure is the number
58447c478bd9Sstevel@tonic-gate 	 * of sectors per track where the sectors are fdc_sec_size.  The
58457c478bd9Sstevel@tonic-gate 	 * dkl_nsect field of the dk_label structure is the number of
58467c478bd9Sstevel@tonic-gate 	 * 512 (DEVBSIZE) byte sectors per track.
58477c478bd9Sstevel@tonic-gate 	 */
58487c478bd9Sstevel@tonic-gate 	un->un_label.dkl_nsect = (un->un_chars->fdc_secptrack *
58497c478bd9Sstevel@tonic-gate 	    un->un_chars->fdc_sec_size) / DEV_BSIZE;
58507c478bd9Sstevel@tonic-gate 
58517c478bd9Sstevel@tonic-gate 
58527c478bd9Sstevel@tonic-gate 	un->un_label.dkl_ncyl = un->un_label.dkl_pcyl;
58537c478bd9Sstevel@tonic-gate 	un->un_label.dkl_nhead = un->un_chars->fdc_nhead;
58547c478bd9Sstevel@tonic-gate 	un->un_label.dkl_rpm = un->un_chars->fdc_medium ? 360 : 300;
58557c478bd9Sstevel@tonic-gate 	un->un_label.dkl_intrlv = 1;
58567c478bd9Sstevel@tonic-gate 
58577c478bd9Sstevel@tonic-gate 	/* Create the checksum */
58587c478bd9Sstevel@tonic-gate 	sum = 0;
58597c478bd9Sstevel@tonic-gate 	un->un_label.dkl_cksum = 0;
58607c478bd9Sstevel@tonic-gate 	sp = (short *)&un->un_label;
58617c478bd9Sstevel@tonic-gate 	i = sizeof (struct dk_label)/sizeof (short);
58627c478bd9Sstevel@tonic-gate 	while (i--) {
58637c478bd9Sstevel@tonic-gate 		sum ^= *sp++;
58647c478bd9Sstevel@tonic-gate 	}
58657c478bd9Sstevel@tonic-gate 	un->un_label.dkl_cksum = sum;
58667c478bd9Sstevel@tonic-gate 
58677c478bd9Sstevel@tonic-gate 	return (0);
58687c478bd9Sstevel@tonic-gate }
58697c478bd9Sstevel@tonic-gate 
58707c478bd9Sstevel@tonic-gate /*
58717c478bd9Sstevel@tonic-gate  * Check for auxio register node
58727c478bd9Sstevel@tonic-gate  */
58737c478bd9Sstevel@tonic-gate 
58747c478bd9Sstevel@tonic-gate int
58757c478bd9Sstevel@tonic-gate fd_isauxiodip(dev_info_t *dip)
58767c478bd9Sstevel@tonic-gate {
58777c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_get_name(dip), "auxio") == 0 ||
58787c478bd9Sstevel@tonic-gate 	    strcmp(ddi_get_name(dip), "auxiliary-io") == 0) {
58797c478bd9Sstevel@tonic-gate 		return (1);
58807c478bd9Sstevel@tonic-gate 	}
58817c478bd9Sstevel@tonic-gate 	return (0);
58827c478bd9Sstevel@tonic-gate }
58837c478bd9Sstevel@tonic-gate 
58847c478bd9Sstevel@tonic-gate /*
58857c478bd9Sstevel@tonic-gate  * Search for auxio register node, then for address property
58867c478bd9Sstevel@tonic-gate  */
58877c478bd9Sstevel@tonic-gate 
58887c478bd9Sstevel@tonic-gate caddr_t
58897c478bd9Sstevel@tonic-gate fd_getauxiova(dev_info_t *dip)
58907c478bd9Sstevel@tonic-gate {
58917c478bd9Sstevel@tonic-gate 	dev_info_t *auxdip;
58927c478bd9Sstevel@tonic-gate 	caddr_t addr;
58937c478bd9Sstevel@tonic-gate 
58947c478bd9Sstevel@tonic-gate 	/*
58957c478bd9Sstevel@tonic-gate 	 * Search sibling list, which happens to be safe inside attach
58967c478bd9Sstevel@tonic-gate 	 */
58977c478bd9Sstevel@tonic-gate 	auxdip = ddi_get_child(ddi_get_parent(dip));
58987c478bd9Sstevel@tonic-gate 	while (auxdip) {
58997c478bd9Sstevel@tonic-gate 		if (fd_isauxiodip(auxdip))
59007c478bd9Sstevel@tonic-gate 			break;
59017c478bd9Sstevel@tonic-gate 		auxdip = ddi_get_next_sibling(auxdip);
59027c478bd9Sstevel@tonic-gate 	}
59037c478bd9Sstevel@tonic-gate 
59047c478bd9Sstevel@tonic-gate 	if (auxdip == NULL)
59057c478bd9Sstevel@tonic-gate 		return (NULL);
59067c478bd9Sstevel@tonic-gate 
590729df58e5Spc157239 	addr = (caddr_t)(uintptr_t)(caddr32_t)ddi_getprop(DDI_DEV_T_ANY,
59087c478bd9Sstevel@tonic-gate 	    auxdip, DDI_PROP_DONTPASS, "address", 0);
59097c478bd9Sstevel@tonic-gate 
59107c478bd9Sstevel@tonic-gate 	return (addr);
59117c478bd9Sstevel@tonic-gate }
59127c478bd9Sstevel@tonic-gate 
59137c478bd9Sstevel@tonic-gate 
59147c478bd9Sstevel@tonic-gate /*
59157c478bd9Sstevel@tonic-gate  * set_rotational speed
59167c478bd9Sstevel@tonic-gate  * 300 rpm for high and low density.
59177c478bd9Sstevel@tonic-gate  * 360 rpm for medium density.
59187c478bd9Sstevel@tonic-gate  * for now, we assume that 3rd density is supported only for Sun4M,
59197c478bd9Sstevel@tonic-gate  * not for Clones. (else we would have to check for 82077, and do
59207c478bd9Sstevel@tonic-gate  * specific things for the MEDIUM_DENSITY BIT for clones.
59217c478bd9Sstevel@tonic-gate  * this code should not break CLONES.
59227c478bd9Sstevel@tonic-gate  *
59237c478bd9Sstevel@tonic-gate  * REMARK: there is a SOny requirement, to deselect the drive then
59247c478bd9Sstevel@tonic-gate  * select it again after the medium density change, since the
59257c478bd9Sstevel@tonic-gate  * leading edge of the select line latches the rotational Speed.
59267c478bd9Sstevel@tonic-gate  * then after that, we have to wait 500 ms for the rotation to
59277c478bd9Sstevel@tonic-gate  * stabilize.
59287c478bd9Sstevel@tonic-gate  *
59297c478bd9Sstevel@tonic-gate  */
59307c478bd9Sstevel@tonic-gate static void
59317c478bd9Sstevel@tonic-gate set_rotational_speed(struct fdctlr *fdc, int unit)
59327c478bd9Sstevel@tonic-gate {
59337c478bd9Sstevel@tonic-gate 	int check;
59347c478bd9Sstevel@tonic-gate 	int is_medium;
59357c478bd9Sstevel@tonic-gate 
59367c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
59377c478bd9Sstevel@tonic-gate 
59387c478bd9Sstevel@tonic-gate 	/*
59397c478bd9Sstevel@tonic-gate 	 * if we do not have a Sun4m, medium density is not supported.
59407c478bd9Sstevel@tonic-gate 	 */
59417c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_MACHIO)
59427c478bd9Sstevel@tonic-gate 		return;
59437c478bd9Sstevel@tonic-gate 
59447c478bd9Sstevel@tonic-gate 	/*
59457c478bd9Sstevel@tonic-gate 	 * if FDUNIT_SET_SPEED is set, set the speed.
59467c478bd9Sstevel@tonic-gate 	 * else,
59477c478bd9Sstevel@tonic-gate 	 *	if there is a change, do it, if not leave it alone.
59487c478bd9Sstevel@tonic-gate 	 *	there is a change if un->un_chars->fdc_medium does not match
59497c478bd9Sstevel@tonic-gate 	 *	un->un_flags & FDUNIT_MEDIUM
59507c478bd9Sstevel@tonic-gate 	 *	un->un_flags & FDUNIT_MEDIUM specifies the last setting.
59517c478bd9Sstevel@tonic-gate 	 *	un->un_chars->fdc_medium specifies next setting.
59527c478bd9Sstevel@tonic-gate 	 *	if there is a change, wait 500ms according to Sony spec.
59537c478bd9Sstevel@tonic-gate 	 */
59547c478bd9Sstevel@tonic-gate 
59557c478bd9Sstevel@tonic-gate 	is_medium = fdc->c_un->un_chars->fdc_medium;
59567c478bd9Sstevel@tonic-gate 
59577c478bd9Sstevel@tonic-gate 	if (fdc->c_un->un_flags & FDUNIT_SET_SPEED) {
59587c478bd9Sstevel@tonic-gate 		check = 1;
59597c478bd9Sstevel@tonic-gate 	} else {
59607c478bd9Sstevel@tonic-gate 		check = is_medium ^
59617c478bd9Sstevel@tonic-gate 		    ((fdc->c_un->un_flags & FDUNIT_MEDIUM) ? 1 : 0);
59627c478bd9Sstevel@tonic-gate 
59637c478bd9Sstevel@tonic-gate 		/* Set the un_flags if necessary */
59647c478bd9Sstevel@tonic-gate 
59657c478bd9Sstevel@tonic-gate 		if (check)
59667c478bd9Sstevel@tonic-gate 			fdc->c_un->un_flags ^= FDUNIT_MEDIUM;
59677c478bd9Sstevel@tonic-gate 	}
59687c478bd9Sstevel@tonic-gate 
59697c478bd9Sstevel@tonic-gate 	fdc->c_un->un_flags &= ~FDUNIT_SET_SPEED;
59707c478bd9Sstevel@tonic-gate 
59717c478bd9Sstevel@tonic-gate 
59727c478bd9Sstevel@tonic-gate 	if (check) {
59737c478bd9Sstevel@tonic-gate 
59747c478bd9Sstevel@tonic-gate 		fdselect(fdc, unit, 0);
59757c478bd9Sstevel@tonic-gate 		drv_usecwait(5);
59767c478bd9Sstevel@tonic-gate 
59777c478bd9Sstevel@tonic-gate 		if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_SLAVIO) {
59787c478bd9Sstevel@tonic-gate 			Set_dor(fdc, MEDIUM_DENSITY, is_medium);
59797c478bd9Sstevel@tonic-gate 		}
59807c478bd9Sstevel@tonic-gate 
59817c478bd9Sstevel@tonic-gate 		if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_CHEERIO) {
59827c478bd9Sstevel@tonic-gate 			if (is_medium) {
59837c478bd9Sstevel@tonic-gate 				Set_auxio(fdc, AUX_MEDIUM_DENSITY);
59847c478bd9Sstevel@tonic-gate 			} else {
59857c478bd9Sstevel@tonic-gate 				Set_auxio(fdc, AUX_HIGH_DENSITY);
59867c478bd9Sstevel@tonic-gate 			}
59877c478bd9Sstevel@tonic-gate 
59887c478bd9Sstevel@tonic-gate 		}
59897c478bd9Sstevel@tonic-gate 
59907c478bd9Sstevel@tonic-gate 		if (is_medium) {
59917c478bd9Sstevel@tonic-gate 			drv_usecwait(5);
59927c478bd9Sstevel@tonic-gate 		}
59937c478bd9Sstevel@tonic-gate 
59947c478bd9Sstevel@tonic-gate 		fdselect(fdc, unit, 1);	/* Sony requirement */
59957c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "rotation:medium\n"));
59967c478bd9Sstevel@tonic-gate 		drv_usecwait(500000);
59977c478bd9Sstevel@tonic-gate 	}
59987c478bd9Sstevel@tonic-gate }
59997c478bd9Sstevel@tonic-gate 
60007c478bd9Sstevel@tonic-gate static void
60017c478bd9Sstevel@tonic-gate fd_media_watch(void *arg)
60027c478bd9Sstevel@tonic-gate {
60037c478bd9Sstevel@tonic-gate 	dev_t		dev;
60047c478bd9Sstevel@tonic-gate 	struct fdunit *un;
60057c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc;
60067c478bd9Sstevel@tonic-gate 	int		unit;
60077c478bd9Sstevel@tonic-gate 
60087c478bd9Sstevel@tonic-gate 	dev = (dev_t)arg;
60097c478bd9Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
60107c478bd9Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
60117c478bd9Sstevel@tonic-gate 	un = fdc->c_un;
60127c478bd9Sstevel@tonic-gate 
60137c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
60147c478bd9Sstevel@tonic-gate 
60157c478bd9Sstevel@tonic-gate 	if (un->un_media_timeout_id == 0) {
60167c478bd9Sstevel@tonic-gate 		/*
60177c478bd9Sstevel@tonic-gate 		 * Untimeout is about to be called.
60187c478bd9Sstevel@tonic-gate 		 * Don't call fd_get_media_state again
60197c478bd9Sstevel@tonic-gate 		 */
60207c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
60217c478bd9Sstevel@tonic-gate 		return;
60227c478bd9Sstevel@tonic-gate 	}
60237c478bd9Sstevel@tonic-gate 
60247c478bd9Sstevel@tonic-gate 
60257c478bd9Sstevel@tonic-gate 	un->un_media_state = fd_get_media_state(fdc, unit);
60267c478bd9Sstevel@tonic-gate 	cv_broadcast(&fdc->c_statecv);
60277c478bd9Sstevel@tonic-gate 
60287c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
60297c478bd9Sstevel@tonic-gate 
60307c478bd9Sstevel@tonic-gate 	if (un->un_media_timeout) {
60317c478bd9Sstevel@tonic-gate 		un->un_media_timeout_id = timeout(fd_media_watch,
60327c478bd9Sstevel@tonic-gate 		    (void *)(ulong_t)dev, un->un_media_timeout);
60337c478bd9Sstevel@tonic-gate 	}
60347c478bd9Sstevel@tonic-gate }
60357c478bd9Sstevel@tonic-gate 
60367c478bd9Sstevel@tonic-gate enum dkio_state
60377c478bd9Sstevel@tonic-gate fd_get_media_state(struct fdctlr *fdc, int unit)
60387c478bd9Sstevel@tonic-gate {
60397c478bd9Sstevel@tonic-gate 	enum dkio_state state;
60407c478bd9Sstevel@tonic-gate 
60417c478bd9Sstevel@tonic-gate 	ASSERT(fdc->c_un->un_unit_no == unit);
60427c478bd9Sstevel@tonic-gate 
60437c478bd9Sstevel@tonic-gate 	if (fdsense_chng(fdc, unit)) {
60447c478bd9Sstevel@tonic-gate 		/* check disk only if DSKCHG "high" */
60457c478bd9Sstevel@tonic-gate 		if (fdcheckdisk(fdc, unit)) {
60467c478bd9Sstevel@tonic-gate 			state = DKIO_EJECTED;
60477c478bd9Sstevel@tonic-gate 		} else {
60487c478bd9Sstevel@tonic-gate 			state = DKIO_INSERTED;
60497c478bd9Sstevel@tonic-gate 		}
60507c478bd9Sstevel@tonic-gate 	} else {
60517c478bd9Sstevel@tonic-gate 		state = DKIO_INSERTED;
60527c478bd9Sstevel@tonic-gate 	}
60537c478bd9Sstevel@tonic-gate 	return (state);
60547c478bd9Sstevel@tonic-gate }
60557c478bd9Sstevel@tonic-gate 
60567c478bd9Sstevel@tonic-gate static int
60577c478bd9Sstevel@tonic-gate fd_check_media(dev_t dev, enum dkio_state state)
60587c478bd9Sstevel@tonic-gate {
60597c478bd9Sstevel@tonic-gate 	struct fdunit *un;
60607c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc;
60617c478bd9Sstevel@tonic-gate 	int		unit;
60627c478bd9Sstevel@tonic-gate 
60637c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: start\n"));
60647c478bd9Sstevel@tonic-gate 
60657c478bd9Sstevel@tonic-gate 	fdc = fd_getctlr(dev);
60667c478bd9Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
60677c478bd9Sstevel@tonic-gate 	un = fdc->c_un;
60687c478bd9Sstevel@tonic-gate 
60697c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
60707c478bd9Sstevel@tonic-gate 
60717c478bd9Sstevel@tonic-gate 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
60727c478bd9Sstevel@tonic-gate 
60737c478bd9Sstevel@tonic-gate 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
60747c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
60757c478bd9Sstevel@tonic-gate 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
60767c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
60777c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
60787c478bd9Sstevel@tonic-gate 			    failed. \n"));
60797c478bd9Sstevel@tonic-gate 
60807c478bd9Sstevel@tonic-gate 			(void) pm_idle_component(fdc->c_dip, 0);
60817c478bd9Sstevel@tonic-gate 			return (EIO);
60827c478bd9Sstevel@tonic-gate 		}
60837c478bd9Sstevel@tonic-gate 
60847c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
60857c478bd9Sstevel@tonic-gate 	}
60867c478bd9Sstevel@tonic-gate 
60877c478bd9Sstevel@tonic-gate 	un->un_media_state = fd_get_media_state(fdc, unit);
60887c478bd9Sstevel@tonic-gate 
60897c478bd9Sstevel@tonic-gate 	/* turn on timeout */
60907c478bd9Sstevel@tonic-gate 	un->un_media_timeout = drv_usectohz(fd_check_media_time);
60917c478bd9Sstevel@tonic-gate 	un->un_media_timeout_id = timeout(fd_media_watch,
60927c478bd9Sstevel@tonic-gate 	    (void *)(ulong_t)dev, un->un_media_timeout);
60937c478bd9Sstevel@tonic-gate 
60947c478bd9Sstevel@tonic-gate 	while (un->un_media_state == state) {
60957c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&fdc->c_statecv, &fdc->c_lolock) == 0) {
60967c478bd9Sstevel@tonic-gate 			un->un_media_timeout = 0;
60977c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
60987c478bd9Sstevel@tonic-gate 			return (EINTR);
60997c478bd9Sstevel@tonic-gate 		}
61007c478bd9Sstevel@tonic-gate 	}
61017c478bd9Sstevel@tonic-gate 
61027c478bd9Sstevel@tonic-gate 	if (un->un_media_timeout_id) {
61037c478bd9Sstevel@tonic-gate 		timeout_id_t timeid = un->un_media_timeout_id;
61047c478bd9Sstevel@tonic-gate 		un->un_media_timeout_id = 0;
61057c478bd9Sstevel@tonic-gate 
61067c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
61077c478bd9Sstevel@tonic-gate 		(void) untimeout(timeid);
61087c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_lolock);
61097c478bd9Sstevel@tonic-gate 	}
61107c478bd9Sstevel@tonic-gate 
61117c478bd9Sstevel@tonic-gate 	if (un->un_media_state == DKIO_INSERTED) {
61127c478bd9Sstevel@tonic-gate 		if (fdgetlabel(fdc, unit)) {
61137c478bd9Sstevel@tonic-gate 			mutex_exit(&fdc->c_lolock);
61147c478bd9Sstevel@tonic-gate 			return (EIO);
61157c478bd9Sstevel@tonic-gate 		}
61167c478bd9Sstevel@tonic-gate 	}
61177c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
61187c478bd9Sstevel@tonic-gate 
61197c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: end\n"));
61207c478bd9Sstevel@tonic-gate 	return (0);
61217c478bd9Sstevel@tonic-gate }
61227c478bd9Sstevel@tonic-gate 
61237c478bd9Sstevel@tonic-gate /*
61247c478bd9Sstevel@tonic-gate  * fd_get_media_info :
61257c478bd9Sstevel@tonic-gate  * 	Collects medium information for
61267c478bd9Sstevel@tonic-gate  *	DKIOCGMEDIAINFO ioctl.
61277c478bd9Sstevel@tonic-gate  */
61287c478bd9Sstevel@tonic-gate 
61297c478bd9Sstevel@tonic-gate static int
61307c478bd9Sstevel@tonic-gate fd_get_media_info(struct fdunit *un, caddr_t buf, int flag)
61317c478bd9Sstevel@tonic-gate {
61327c478bd9Sstevel@tonic-gate 	struct dk_minfo media_info;
61337c478bd9Sstevel@tonic-gate 	int err = 0;
61347c478bd9Sstevel@tonic-gate 
61357c478bd9Sstevel@tonic-gate 	media_info.dki_media_type = DK_FLOPPY;
61367c478bd9Sstevel@tonic-gate 	media_info.dki_lbsize = un->un_chars->fdc_sec_size;
61377c478bd9Sstevel@tonic-gate 	media_info.dki_capacity = un->un_chars->fdc_ncyl *
61387c478bd9Sstevel@tonic-gate 	    un->un_chars->fdc_secptrack * un->un_chars->fdc_nhead;
61397c478bd9Sstevel@tonic-gate 
61407c478bd9Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)&media_info, buf,
61417c478bd9Sstevel@tonic-gate 	    sizeof (struct dk_minfo), flag))
61427c478bd9Sstevel@tonic-gate 		err = EFAULT;
61437c478bd9Sstevel@tonic-gate 	return (err);
61447c478bd9Sstevel@tonic-gate }
61457c478bd9Sstevel@tonic-gate 
61467c478bd9Sstevel@tonic-gate /*
61477c478bd9Sstevel@tonic-gate  * fd_power :
61487c478bd9Sstevel@tonic-gate  *	Power entry point of fd driver.
61497c478bd9Sstevel@tonic-gate  */
61507c478bd9Sstevel@tonic-gate 
61517c478bd9Sstevel@tonic-gate static int
61527c478bd9Sstevel@tonic-gate fd_power(dev_info_t *dip, int component, int level)
61537c478bd9Sstevel@tonic-gate {
61547c478bd9Sstevel@tonic-gate 
61557c478bd9Sstevel@tonic-gate 	struct fdctlr *fdc;
61567c478bd9Sstevel@tonic-gate 	int instance;
61577c478bd9Sstevel@tonic-gate 	int rval;
61587c478bd9Sstevel@tonic-gate 
61597c478bd9Sstevel@tonic-gate 	if ((level < PM_LEVEL_OFF) || (level > PM_LEVEL_ON) ||
61607c478bd9Sstevel@tonic-gate 	    (component != 0)) {
61617c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
61627c478bd9Sstevel@tonic-gate 	}
61637c478bd9Sstevel@tonic-gate 
61647c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
61657c478bd9Sstevel@tonic-gate 	fdc = fd_getctlr(instance << FDINSTSHIFT);
61667c478bd9Sstevel@tonic-gate 	if (fdc->c_un == NULL)
61677c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
61687c478bd9Sstevel@tonic-gate 
61697c478bd9Sstevel@tonic-gate 	if (level == PM_LEVEL_OFF) {
61707c478bd9Sstevel@tonic-gate 		rval = fd_pm_lower_power(fdc);
61717c478bd9Sstevel@tonic-gate 	}
61727c478bd9Sstevel@tonic-gate 	if (level == PM_LEVEL_ON) {
61737c478bd9Sstevel@tonic-gate 		rval = fd_pm_raise_power(fdc);
61747c478bd9Sstevel@tonic-gate 	}
61757c478bd9Sstevel@tonic-gate 	return (rval);
61767c478bd9Sstevel@tonic-gate }
61777c478bd9Sstevel@tonic-gate 
61787c478bd9Sstevel@tonic-gate /*
61797c478bd9Sstevel@tonic-gate  * fd_pm_lower_power :
61807c478bd9Sstevel@tonic-gate  *	This function is called only during pm suspend. At this point,
61817c478bd9Sstevel@tonic-gate  *	the power management framework thinks the device is idle for
61827c478bd9Sstevel@tonic-gate  *	long enough to go to a low power mode. If the device is busy,
61837c478bd9Sstevel@tonic-gate  *	then this function returns DDI_FAILURE.
61847c478bd9Sstevel@tonic-gate  */
61857c478bd9Sstevel@tonic-gate 
61867c478bd9Sstevel@tonic-gate static int
61877c478bd9Sstevel@tonic-gate fd_pm_lower_power(struct fdctlr *fdc)
61887c478bd9Sstevel@tonic-gate {
61897c478bd9Sstevel@tonic-gate 
61907c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
61917c478bd9Sstevel@tonic-gate 
61927c478bd9Sstevel@tonic-gate 	if ((fdc->c_un->un_state == FD_STATE_SUSPENDED) ||
61937c478bd9Sstevel@tonic-gate 	    (fdc->c_un->un_state == FD_STATE_STOPPED)) {
61947c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
61957c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
61967c478bd9Sstevel@tonic-gate 	}
61977c478bd9Sstevel@tonic-gate 
61987c478bd9Sstevel@tonic-gate 
61997c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_lower_power called\n"));
62007c478bd9Sstevel@tonic-gate 
62017c478bd9Sstevel@tonic-gate 	/* if the device is busy then we fail the lower power request */
62027c478bd9Sstevel@tonic-gate 	if (fdc->c_flags & FDCFLG_BUSY) {
62037c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_PWR, (C, "fd_pm_lower_power : \
62047c478bd9Sstevel@tonic-gate controller is busy.\n"));
62057c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
62067c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
62077c478bd9Sstevel@tonic-gate 	}
62087c478bd9Sstevel@tonic-gate 
62097c478bd9Sstevel@tonic-gate 	fdc->c_un->un_state = FD_STATE_STOPPED;
62107c478bd9Sstevel@tonic-gate 
62117c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
62127c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
62137c478bd9Sstevel@tonic-gate }
62147c478bd9Sstevel@tonic-gate 
62157c478bd9Sstevel@tonic-gate /*
62167c478bd9Sstevel@tonic-gate  * fd_pm_raise_power :
62177c478bd9Sstevel@tonic-gate  *	This function performs the necessary steps for resuming a
62187c478bd9Sstevel@tonic-gate  *	device, either from pm suspend or CPR. Here the controller
62197c478bd9Sstevel@tonic-gate  *	is reset, initialized and the state is set to FD_STATE_NORMAL.
62207c478bd9Sstevel@tonic-gate  */
62217c478bd9Sstevel@tonic-gate 
62227c478bd9Sstevel@tonic-gate static int
62237c478bd9Sstevel@tonic-gate fd_pm_raise_power(struct fdctlr *fdc)
62247c478bd9Sstevel@tonic-gate {
62257c478bd9Sstevel@tonic-gate 
62267c478bd9Sstevel@tonic-gate 	struct fdunit *un = fdc->c_un;
62277c478bd9Sstevel@tonic-gate 	int unit;
62287c478bd9Sstevel@tonic-gate 
62297c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_raise_power called\n"));
62307c478bd9Sstevel@tonic-gate 	mutex_enter(&fdc->c_lolock);
62317c478bd9Sstevel@tonic-gate 	fdgetcsb(fdc);
62327c478bd9Sstevel@tonic-gate 
62337c478bd9Sstevel@tonic-gate 	/* Reset the dma engine */
62347c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_DMA) {
62357c478bd9Sstevel@tonic-gate 		mutex_enter(&fdc->c_hilock);
62367c478bd9Sstevel@tonic-gate 		reset_dma_controller(fdc);
62377c478bd9Sstevel@tonic-gate 		set_dma_control_register(fdc, DCSR_INIT_BITS);
62387c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_hilock);
62397c478bd9Sstevel@tonic-gate 	}
62407c478bd9Sstevel@tonic-gate 
62417c478bd9Sstevel@tonic-gate 	/*
62427c478bd9Sstevel@tonic-gate 	 * Force a rotational speed set in the next
62437c478bd9Sstevel@tonic-gate 	 * call to set_rotational_speed().
62447c478bd9Sstevel@tonic-gate 	 */
62457c478bd9Sstevel@tonic-gate 
62467c478bd9Sstevel@tonic-gate 	fdc->c_un->un_flags |= FDUNIT_SET_SPEED;
62477c478bd9Sstevel@tonic-gate 
62487c478bd9Sstevel@tonic-gate 	/* Reset and configure the controller */
62497c478bd9Sstevel@tonic-gate 	(void) fdreset(fdc);
62507c478bd9Sstevel@tonic-gate 
62517c478bd9Sstevel@tonic-gate 	unit = fdc->c_un->un_unit_no;
62527c478bd9Sstevel@tonic-gate 
62537c478bd9Sstevel@tonic-gate 	/* Recalibrate the drive */
62547c478bd9Sstevel@tonic-gate 	if (fdrecalseek(fdc, unit, -1, 0) != 0) {
62557c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "raise_power : recalibrate \
62567c478bd9Sstevel@tonic-gate failed\n"));
62577c478bd9Sstevel@tonic-gate 		fdretcsb(fdc);
62587c478bd9Sstevel@tonic-gate 		mutex_exit(&fdc->c_lolock);
62597c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
62607c478bd9Sstevel@tonic-gate 	}
62617c478bd9Sstevel@tonic-gate 
62627c478bd9Sstevel@tonic-gate 	/* Select the drive through the AUXIO registers */
62637c478bd9Sstevel@tonic-gate 	fdselect(fdc, unit, 0);
62647c478bd9Sstevel@tonic-gate 	un->un_state = FD_STATE_NORMAL;
62657c478bd9Sstevel@tonic-gate 	fdretcsb(fdc);
62667c478bd9Sstevel@tonic-gate 	mutex_exit(&fdc->c_lolock);
62677c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
62687c478bd9Sstevel@tonic-gate }
62697c478bd9Sstevel@tonic-gate 
62707c478bd9Sstevel@tonic-gate /*
62717c478bd9Sstevel@tonic-gate  * create_pm_components :
62727c478bd9Sstevel@tonic-gate  *	creates the power management components for auto pm framework.
62737c478bd9Sstevel@tonic-gate  */
62747c478bd9Sstevel@tonic-gate 
62757c478bd9Sstevel@tonic-gate static void
62767c478bd9Sstevel@tonic-gate create_pm_components(dev_info_t *dip)
62777c478bd9Sstevel@tonic-gate {
62787c478bd9Sstevel@tonic-gate 	char	*un_pm_comp[] = { "NAME=spindle-motor", "0=off", "1=on"};
62797c478bd9Sstevel@tonic-gate 
62807c478bd9Sstevel@tonic-gate 	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
62817c478bd9Sstevel@tonic-gate 	    "pm-components", un_pm_comp, 3) == DDI_PROP_SUCCESS) {
62827c478bd9Sstevel@tonic-gate 
62837c478bd9Sstevel@tonic-gate 		(void) pm_raise_power(dip, 0, PM_LEVEL_ON);
62847c478bd9Sstevel@tonic-gate 	}
62857c478bd9Sstevel@tonic-gate }
62867c478bd9Sstevel@tonic-gate 
62877c478bd9Sstevel@tonic-gate /*
62887c478bd9Sstevel@tonic-gate  * set_data_count_register(struct fdctlr *fdc, uint32_t count)
62897c478bd9Sstevel@tonic-gate  * 	Set the data count in appropriate dma register.
62907c478bd9Sstevel@tonic-gate  */
62917c478bd9Sstevel@tonic-gate 
62927c478bd9Sstevel@tonic-gate static void
62937c478bd9Sstevel@tonic-gate set_data_count_register(struct fdctlr *fdc, uint32_t count)
62947c478bd9Sstevel@tonic-gate {
62957c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
62967c478bd9Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
62977c478bd9Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
62987c478bd9Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr, count);
62997c478bd9Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
63007c478bd9Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
63017c478bd9Sstevel@tonic-gate 		count = count - 1; /* 8237 needs it */
63027c478bd9Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
63037c478bd9Sstevel@tonic-gate 		switch (fdc->sb_dma_channel) {
63047c478bd9Sstevel@tonic-gate 		case 0 :
63057c478bd9Sstevel@tonic-gate 			ddi_put16(fdc->c_handlep_dma,
63067c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT],
63077c478bd9Sstevel@tonic-gate 			    count & 0xFFFF);
63087c478bd9Sstevel@tonic-gate 			break;
63097c478bd9Sstevel@tonic-gate 		case 1 :
63107c478bd9Sstevel@tonic-gate 			ddi_put16(fdc->c_handlep_dma,
63117c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT],
63127c478bd9Sstevel@tonic-gate 			    count & 0xFFFF);
63137c478bd9Sstevel@tonic-gate 			break;
63147c478bd9Sstevel@tonic-gate 		case 2 :
63157c478bd9Sstevel@tonic-gate 			ddi_put16(fdc->c_handlep_dma,
63167c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT],
63177c478bd9Sstevel@tonic-gate 			    count & 0xFFFF);
63187c478bd9Sstevel@tonic-gate 			break;
63197c478bd9Sstevel@tonic-gate 		case 3 :
63207c478bd9Sstevel@tonic-gate 			ddi_put16(fdc->c_handlep_dma,
63217c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT],
63227c478bd9Sstevel@tonic-gate 			    count & 0xFFFF);
63237c478bd9Sstevel@tonic-gate 			break;
63247c478bd9Sstevel@tonic-gate 		default :
63257c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_SDMA,
63267c478bd9Sstevel@tonic-gate 			    (C, "set_data_count: wrong channel %x\n",
63277c478bd9Sstevel@tonic-gate 			    fdc->sb_dma_channel));
63287c478bd9Sstevel@tonic-gate 			break;
63297c478bd9Sstevel@tonic-gate 		}
63307c478bd9Sstevel@tonic-gate 	}
63317c478bd9Sstevel@tonic-gate }
63327c478bd9Sstevel@tonic-gate 
63337c478bd9Sstevel@tonic-gate /*
63347c478bd9Sstevel@tonic-gate  * get_data_count_register(struct fdctlr *fdc)
63357c478bd9Sstevel@tonic-gate  * 	Read the data count from appropriate dma register.
63367c478bd9Sstevel@tonic-gate  */
63377c478bd9Sstevel@tonic-gate 
63387c478bd9Sstevel@tonic-gate static uint32_t
63397c478bd9Sstevel@tonic-gate get_data_count_register(struct fdctlr *fdc)
63407c478bd9Sstevel@tonic-gate {
63417c478bd9Sstevel@tonic-gate 	uint32_t retval = 0;
63427c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
63437c478bd9Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
63447c478bd9Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
63457c478bd9Sstevel@tonic-gate 		retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr);
63467c478bd9Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
63477c478bd9Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
63487c478bd9Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
63497c478bd9Sstevel@tonic-gate 		switch (fdc->sb_dma_channel) {
63507c478bd9Sstevel@tonic-gate 		case 0 :
63517c478bd9Sstevel@tonic-gate 			retval = ddi_get16(fdc->c_handlep_dma,
63527c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT]);
63537c478bd9Sstevel@tonic-gate 			break;
63547c478bd9Sstevel@tonic-gate 		case 1 :
63557c478bd9Sstevel@tonic-gate 			retval = ddi_get16(fdc->c_handlep_dma,
63567c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT]);
63577c478bd9Sstevel@tonic-gate 			break;
63587c478bd9Sstevel@tonic-gate 		case 2 :
63597c478bd9Sstevel@tonic-gate 			retval = ddi_get16(fdc->c_handlep_dma,
63607c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT]);
63617c478bd9Sstevel@tonic-gate 			break;
63627c478bd9Sstevel@tonic-gate 		case 3 :
63637c478bd9Sstevel@tonic-gate 			retval = ddi_get16(fdc->c_handlep_dma,
63647c478bd9Sstevel@tonic-gate 			    (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT]);
63657c478bd9Sstevel@tonic-gate 			break;
63667c478bd9Sstevel@tonic-gate 		default :
63677c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_SDMA,
63687c478bd9Sstevel@tonic-gate 			    (C, "get_data_count: wrong channel %x\n",
63697c478bd9Sstevel@tonic-gate 			    fdc->sb_dma_channel));
63707c478bd9Sstevel@tonic-gate 			break;
63717c478bd9Sstevel@tonic-gate 		}
63727c478bd9Sstevel@tonic-gate 		retval = (uint32_t)((uint16_t)(retval +1));
63737c478bd9Sstevel@tonic-gate 	}
63747c478bd9Sstevel@tonic-gate 
63757c478bd9Sstevel@tonic-gate 	return (retval);
63767c478bd9Sstevel@tonic-gate 
63777c478bd9Sstevel@tonic-gate }
63787c478bd9Sstevel@tonic-gate 
63797c478bd9Sstevel@tonic-gate /*
63807c478bd9Sstevel@tonic-gate  * reset_dma_controller(struct fdctlr *fdc)
63817c478bd9Sstevel@tonic-gate  * 	Reset and initialize the dma controller.
63827c478bd9Sstevel@tonic-gate  */
63837c478bd9Sstevel@tonic-gate 
63847c478bd9Sstevel@tonic-gate static void
63857c478bd9Sstevel@tonic-gate reset_dma_controller(struct fdctlr *fdc)
63867c478bd9Sstevel@tonic-gate {
63877c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
63887c478bd9Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
63897c478bd9Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
63907c478bd9Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, DCSR_RESET);
639119397407SSherry Moore 		while (get_dma_control_register(fdc) & DCSR_CYC_PEND)
639219397407SSherry Moore 			;
63937c478bd9Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, 0);
63947c478bd9Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
63957c478bd9Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
63967c478bd9Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
63977c478bd9Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MASK],
63987c478bd9Sstevel@tonic-gate 		    (fdc->sb_dma_channel & 0x3));
63997c478bd9Sstevel@tonic-gate 
64007c478bd9Sstevel@tonic-gate 	}
64017c478bd9Sstevel@tonic-gate }
64027c478bd9Sstevel@tonic-gate 
64037c478bd9Sstevel@tonic-gate /*
64047c478bd9Sstevel@tonic-gate  * Get the DMA control register for CHEERIO.
64057c478bd9Sstevel@tonic-gate  * For SouthBridge 8237 DMA controller, this register is not valid.
64067c478bd9Sstevel@tonic-gate  * So, just return 0.
64077c478bd9Sstevel@tonic-gate  */
64087c478bd9Sstevel@tonic-gate static uint32_t
64097c478bd9Sstevel@tonic-gate get_dma_control_register(struct fdctlr *fdc)
64107c478bd9Sstevel@tonic-gate {
64117c478bd9Sstevel@tonic-gate 	uint32_t retval = 0;
64127c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
64137c478bd9Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
64147c478bd9Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
64157c478bd9Sstevel@tonic-gate 		retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr);
64167c478bd9Sstevel@tonic-gate 	}
64177c478bd9Sstevel@tonic-gate 
64187c478bd9Sstevel@tonic-gate 	return (retval);
64197c478bd9Sstevel@tonic-gate }
64207c478bd9Sstevel@tonic-gate 
64217c478bd9Sstevel@tonic-gate 
64227c478bd9Sstevel@tonic-gate /*
64237c478bd9Sstevel@tonic-gate  * set_data_address_register(struct fdctlr *fdc)
64247c478bd9Sstevel@tonic-gate  * 	Set the data address in appropriate dma register.
64257c478bd9Sstevel@tonic-gate  */
64267c478bd9Sstevel@tonic-gate static void
64277c478bd9Sstevel@tonic-gate set_data_address_register(struct fdctlr *fdc, uint32_t address)
64287c478bd9Sstevel@tonic-gate {
64297c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
64307c478bd9Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
64317c478bd9Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
64327c478bd9Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dacr, address);
64337c478bd9Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
64347c478bd9Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
64357c478bd9Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
64367c478bd9Sstevel@tonic-gate 		switch (fdc->sb_dma_channel) {
64377c478bd9Sstevel@tonic-gate 			case 0 :
64387c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64397c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_0PAGE],
64407c478bd9Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64417c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64427c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_0HPG],
64437c478bd9Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64447c478bd9Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64457c478bd9Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_0ADR],
64467c478bd9Sstevel@tonic-gate 				    address & 0xFFFF);
64477c478bd9Sstevel@tonic-gate 				break;
64487c478bd9Sstevel@tonic-gate 			case 1 :
64497c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64507c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_1PAGE],
64517c478bd9Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64527c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64537c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_1HPG],
64547c478bd9Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64557c478bd9Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64567c478bd9Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_1ADR],
64577c478bd9Sstevel@tonic-gate 				    address & 0xFFFF);
64587c478bd9Sstevel@tonic-gate 				break;
64597c478bd9Sstevel@tonic-gate 			case 2 :
64607c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64617c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_2PAGE],
64627c478bd9Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64637c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64647c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_2HPG],
64657c478bd9Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64667c478bd9Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64677c478bd9Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_2ADR],
64687c478bd9Sstevel@tonic-gate 				    address & 0xFFFF);
64697c478bd9Sstevel@tonic-gate 				break;
64707c478bd9Sstevel@tonic-gate 			case 3 :
64717c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64727c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_3PAGE],
64737c478bd9Sstevel@tonic-gate 				    (address & 0xFF0000) >>16);
64747c478bd9Sstevel@tonic-gate 				ddi_put8(fdc->c_handlep_dma,
64757c478bd9Sstevel@tonic-gate 				    &dma_reg->sb_dma_regs[DMA_3HPG],
64767c478bd9Sstevel@tonic-gate 				    (address & 0xFF000000) >>24);
64777c478bd9Sstevel@tonic-gate 				ddi_put16(fdc->c_handlep_dma,
64787c478bd9Sstevel@tonic-gate 				    (ushort_t *)&dma_reg->sb_dma_regs[DMA_3ADR],
64797c478bd9Sstevel@tonic-gate 				    address & 0xFFFF);
64807c478bd9Sstevel@tonic-gate 				break;
64817c478bd9Sstevel@tonic-gate 			default :
64827c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L3, FDEM_SDMA,
64837c478bd9Sstevel@tonic-gate 				    (C, "set_data_address: wrong channel %x\n",
64847c478bd9Sstevel@tonic-gate 				    fdc->sb_dma_channel));
64857c478bd9Sstevel@tonic-gate 			break;
64867c478bd9Sstevel@tonic-gate 		}
64877c478bd9Sstevel@tonic-gate 	}
64887c478bd9Sstevel@tonic-gate 
64897c478bd9Sstevel@tonic-gate }
64907c478bd9Sstevel@tonic-gate 
64917c478bd9Sstevel@tonic-gate 
64927c478bd9Sstevel@tonic-gate /*
64937c478bd9Sstevel@tonic-gate  * set_dma_mode(struct fdctlr *fdc, int val)
64947c478bd9Sstevel@tonic-gate  * 	Set the appropriate dma direction and registers.
64957c478bd9Sstevel@tonic-gate  */
64967c478bd9Sstevel@tonic-gate static void
64977c478bd9Sstevel@tonic-gate set_dma_mode(struct fdctlr *fdc, int val)
64987c478bd9Sstevel@tonic-gate {
64997c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
65007c478bd9Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
65017c478bd9Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
65027c478bd9Sstevel@tonic-gate 		if (val == CSB_READ)
65037c478bd9Sstevel@tonic-gate 			ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
65047c478bd9Sstevel@tonic-gate 			    DCSR_INIT_BITS|DCSR_WRITE);
65057c478bd9Sstevel@tonic-gate 		else
65067c478bd9Sstevel@tonic-gate 			ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
65077c478bd9Sstevel@tonic-gate 			    DCSR_INIT_BITS);
65087c478bd9Sstevel@tonic-gate 
65097c478bd9Sstevel@tonic-gate 	} else if (fdc->c_fdtype & FDCTYPE_SB) {
65107c478bd9Sstevel@tonic-gate 		uint8_t mode_reg_val, chn_mask;
65117c478bd9Sstevel@tonic-gate 		struct sb_dma_reg *dma_reg;
65127c478bd9Sstevel@tonic-gate 		dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
65137c478bd9Sstevel@tonic-gate 
65147c478bd9Sstevel@tonic-gate 		if (val == CSB_READ) {
65157c478bd9Sstevel@tonic-gate 			mode_reg_val = fdc->sb_dma_channel | DMAMODE_READ
65167c478bd9Sstevel@tonic-gate 			    | DMAMODE_SINGLE;
65177c478bd9Sstevel@tonic-gate 		} else { /* Read operation */
65187c478bd9Sstevel@tonic-gate 			mode_reg_val = fdc->sb_dma_channel | DMAMODE_WRITE
65197c478bd9Sstevel@tonic-gate 			    | DMAMODE_SINGLE;
65207c478bd9Sstevel@tonic-gate 		}
65217c478bd9Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MODE],
65227c478bd9Sstevel@tonic-gate 		    mode_reg_val);
65237c478bd9Sstevel@tonic-gate 		chn_mask = 1 << (fdc->sb_dma_channel & 0x3);
65247c478bd9Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_dma,
65257c478bd9Sstevel@tonic-gate 		    &dma_reg->sb_dma_regs[DMAC1_ALLMASK], ~chn_mask);
65267c478bd9Sstevel@tonic-gate 		fdc->sb_dma_lock = 1;
65277c478bd9Sstevel@tonic-gate 	}
65287c478bd9Sstevel@tonic-gate }
65297c478bd9Sstevel@tonic-gate 
65307c478bd9Sstevel@tonic-gate /*
65317c478bd9Sstevel@tonic-gate  * This function is valid only for CHEERIO/RIO based
65327c478bd9Sstevel@tonic-gate  * controllers. The control register for the dma channel
65337c478bd9Sstevel@tonic-gate  * is initialized by this function.
65347c478bd9Sstevel@tonic-gate  */
65357c478bd9Sstevel@tonic-gate 
65367c478bd9Sstevel@tonic-gate static void
65377c478bd9Sstevel@tonic-gate set_dma_control_register(struct fdctlr *fdc, uint32_t val)
65387c478bd9Sstevel@tonic-gate {
65397c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
65407c478bd9Sstevel@tonic-gate 		struct cheerio_dma_reg *dma_reg;
65417c478bd9Sstevel@tonic-gate 		dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
65427c478bd9Sstevel@tonic-gate 		ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, val);
65437c478bd9Sstevel@tonic-gate 	}
65447c478bd9Sstevel@tonic-gate }
65457c478bd9Sstevel@tonic-gate 
65467c478bd9Sstevel@tonic-gate static void
65477c478bd9Sstevel@tonic-gate release_sb_dma(struct fdctlr *fdc)
65487c478bd9Sstevel@tonic-gate {
65497c478bd9Sstevel@tonic-gate 	struct sb_dma_reg *dma_reg;
65507c478bd9Sstevel@tonic-gate 	dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
65517c478bd9Sstevel@tonic-gate 	/* Unmask all the channels to release the DMA controller */
65527c478bd9Sstevel@tonic-gate 	ddi_put8(fdc->c_handlep_dma,
65537c478bd9Sstevel@tonic-gate 	    &dma_reg->sb_dma_regs[DMAC1_ALLMASK], NULL);
65547c478bd9Sstevel@tonic-gate 	fdc->sb_dma_lock = 0;
65557c478bd9Sstevel@tonic-gate }
65567c478bd9Sstevel@tonic-gate 
65577c478bd9Sstevel@tonic-gate static void
65587c478bd9Sstevel@tonic-gate quiesce_fd_interrupt(struct fdctlr *fdc)
65597c478bd9Sstevel@tonic-gate {
65607c478bd9Sstevel@tonic-gate 	/*
65617c478bd9Sstevel@tonic-gate 	 * The following code is put here to take care of HW problem.
65627c478bd9Sstevel@tonic-gate 	 * The HW problem is as follows:
65637c478bd9Sstevel@tonic-gate 	 *
65647c478bd9Sstevel@tonic-gate 	 *	After poweron the Southbridge floppy controller asserts the
65657c478bd9Sstevel@tonic-gate 	 * interrupt in tristate. This causes continuous interrupts to
65667c478bd9Sstevel@tonic-gate 	 * be generated.
65677c478bd9Sstevel@tonic-gate 	 * Until the Hardware is FIXED we will have to use the following code
65687c478bd9Sstevel@tonic-gate 	 * to set the interrupt line to proper state after poweron.
65697c478bd9Sstevel@tonic-gate 	 */
65707c478bd9Sstevel@tonic-gate 	if (fdc->c_fdtype & FDCTYPE_SB) {
65717c478bd9Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
65727c478bd9Sstevel@tonic-gate 		    0x0);
65737c478bd9Sstevel@tonic-gate 		drv_usecwait(200);
65747c478bd9Sstevel@tonic-gate 		ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
65757c478bd9Sstevel@tonic-gate 		    0xC);
65767c478bd9Sstevel@tonic-gate 		drv_usecwait(200);
65777c478bd9Sstevel@tonic-gate 		Set_Fifo(fdc, 0xE6);
65787c478bd9Sstevel@tonic-gate 		drv_usecwait(200);
65797c478bd9Sstevel@tonic-gate 	}
65807c478bd9Sstevel@tonic-gate }
6581