xref: /titanic_51/usr/src/uts/common/io/fd.c (revision ca925f54ccacc64abb1dc147c736397a9ccaab0e)
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 /*
2219397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Floppy Disk driver
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Set CMOS feature:
337c478bd9Sstevel@tonic-gate  *	CMOS_CONF_MEM:	CMOS memory contains configuration info
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate #define	CMOS_CONF_MEM
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/param.h>
397c478bd9Sstevel@tonic-gate #include <sys/systm.h>
407c478bd9Sstevel@tonic-gate #include <sys/buf.h>
417c478bd9Sstevel@tonic-gate #include <sys/file.h>
427c478bd9Sstevel@tonic-gate #include <sys/open.h>
437c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
447c478bd9Sstevel@tonic-gate #include <sys/uio.h>
457c478bd9Sstevel@tonic-gate #include <sys/conf.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
487c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
497c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
507c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
517c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
527c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
537c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
547c478bd9Sstevel@tonic-gate #include <sys/ddidmareq.h>
557c478bd9Sstevel@tonic-gate #include <sys/fdio.h>
567c478bd9Sstevel@tonic-gate #include <sys/fdc.h>
577c478bd9Sstevel@tonic-gate #include <sys/fd_debug.h>
587c478bd9Sstevel@tonic-gate #include <sys/fdmedia.h>
597c478bd9Sstevel@tonic-gate #include <sys/debug.h>
607c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Local Function Prototypes
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate static int fd_unit_is_open(struct fdisk *);
667c478bd9Sstevel@tonic-gate static int fdgetlabel(struct fcu_obj *, int);
677c478bd9Sstevel@tonic-gate static void fdstart(struct fcu_obj *);
687c478bd9Sstevel@tonic-gate static int fd_build_label_vtoc(struct fcu_obj *, struct fdisk *,
697c478bd9Sstevel@tonic-gate     struct vtoc *, struct dk_label *);
707c478bd9Sstevel@tonic-gate static void fd_build_user_vtoc(struct fcu_obj *, struct fdisk *,
717c478bd9Sstevel@tonic-gate     struct vtoc *);
727c478bd9Sstevel@tonic-gate static int fd_rawioctl(struct fcu_obj *, int, caddr_t, int);
737c478bd9Sstevel@tonic-gate static void fd_media_watch(void *);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static int fd_open(dev_t *, int, int, cred_t *);
767c478bd9Sstevel@tonic-gate static int fd_close(dev_t, int, int, cred_t *);
777c478bd9Sstevel@tonic-gate static int fd_strategy(struct buf *);
787c478bd9Sstevel@tonic-gate static int fd_read(dev_t, struct uio *, cred_t *);
797c478bd9Sstevel@tonic-gate static int fd_write(dev_t, struct uio *, cred_t *);
807c478bd9Sstevel@tonic-gate static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
817c478bd9Sstevel@tonic-gate static int fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
827c478bd9Sstevel@tonic-gate     caddr_t, int *);
837c478bd9Sstevel@tonic-gate static int fd_check_media(dev_t dev, enum dkio_state state);
847c478bd9Sstevel@tonic-gate static int fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag);
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static struct cb_ops fd_cb_ops = {
877c478bd9Sstevel@tonic-gate 	fd_open,		/* open */
887c478bd9Sstevel@tonic-gate 	fd_close,		/* close */
897c478bd9Sstevel@tonic-gate 	fd_strategy,		/* strategy */
907c478bd9Sstevel@tonic-gate 	nodev,			/* print */
917c478bd9Sstevel@tonic-gate 	nodev,			/* dump */
927c478bd9Sstevel@tonic-gate 	fd_read,		/* read */
937c478bd9Sstevel@tonic-gate 	fd_write,		/* write */
947c478bd9Sstevel@tonic-gate 	fd_ioctl,		/* ioctl */
957c478bd9Sstevel@tonic-gate 	nodev,			/* devmap */
967c478bd9Sstevel@tonic-gate 	nodev,			/* mmap */
977c478bd9Sstevel@tonic-gate 	nodev,			/* segmap */
987c478bd9Sstevel@tonic-gate 	nochpoll,		/* poll */
997c478bd9Sstevel@tonic-gate 	fd_prop_op,		/* cb_prop_op */
1007c478bd9Sstevel@tonic-gate 	0,			/* streamtab  */
1017c478bd9Sstevel@tonic-gate 	D_NEW | D_MP		/* Driver compatibility flag */
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static int fd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
1057c478bd9Sstevel@tonic-gate static int fd_probe(dev_info_t *);
1067c478bd9Sstevel@tonic-gate static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
1077c478bd9Sstevel@tonic-gate static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate static struct dev_ops fd_ops = {
1107c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1117c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
1127c478bd9Sstevel@tonic-gate 	fd_getinfo,		/* getinfo */
1137c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
1147c478bd9Sstevel@tonic-gate 	fd_probe,		/* probe */
1157c478bd9Sstevel@tonic-gate 	fd_attach,		/* attach */
1167c478bd9Sstevel@tonic-gate 	fd_detach,		/* detach */
1177c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
1187c478bd9Sstevel@tonic-gate 	&fd_cb_ops,		/* driver operations */
11919397407SSherry Moore 	(struct bus_ops *)0,	/* bus operations */
12019397407SSherry Moore 	NULL,			/* power */
12119397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
1227c478bd9Sstevel@tonic-gate };
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * static data
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate static void *fd_state_head;		/* opaque handle top of state structs */
1297c478bd9Sstevel@tonic-gate static int fd_check_media_time = 5000000;	/* 5 second state check */
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * error handling
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  * for debugging,
1357c478bd9Sstevel@tonic-gate  *		set fderrlevel to 1
1367c478bd9Sstevel@tonic-gate  *		set fderrmask  to 224  or 644
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate #ifdef DEBUG
1397c478bd9Sstevel@tonic-gate static uint_t fderrmask = FDEM_ALL;
1407c478bd9Sstevel@tonic-gate #endif
1417c478bd9Sstevel@tonic-gate static int fderrlevel = 5;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate #define	KIOSP	KSTAT_IO_PTR(fdp->d_iostat)
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate static struct driver_minor_data {
1467c478bd9Sstevel@tonic-gate 	char	*name;
1477c478bd9Sstevel@tonic-gate 	int	minor;
1487c478bd9Sstevel@tonic-gate 	int	type;
1497c478bd9Sstevel@tonic-gate } fd_minor [] = {
1507c478bd9Sstevel@tonic-gate 	{ "a", 0, S_IFBLK},
1517c478bd9Sstevel@tonic-gate 	{ "b", 1, S_IFBLK},
1527c478bd9Sstevel@tonic-gate 	{ "c", 2, S_IFBLK},
1537c478bd9Sstevel@tonic-gate 	{ "a,raw", 0, S_IFCHR},
1547c478bd9Sstevel@tonic-gate 	{ "b,raw", 1, S_IFCHR},
1557c478bd9Sstevel@tonic-gate 	{ "c,raw", 2, S_IFCHR},
1567c478bd9Sstevel@tonic-gate 	{0}
1577c478bd9Sstevel@tonic-gate };
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1607c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* Type of module. This one is a driver */
16119397407SSherry Moore 	"Floppy Disk driver",	/* Name of the module. */
1627c478bd9Sstevel@tonic-gate 	&fd_ops,		/* driver ops */
1637c478bd9Sstevel@tonic-gate };
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1667c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
1677c478bd9Sstevel@tonic-gate };
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate int
1717c478bd9Sstevel@tonic-gate _init(void)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	int retval;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if ((retval = ddi_soft_state_init(&fd_state_head,
1767c478bd9Sstevel@tonic-gate 	    sizeof (struct fdisk) + sizeof (struct fd_drive) +
1777c478bd9Sstevel@tonic-gate 	    sizeof (struct fd_char) + sizeof (struct fdattr), 0)) != 0)
1787c478bd9Sstevel@tonic-gate 		return (retval);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if ((retval = mod_install(&modlinkage)) != 0)
1817c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&fd_state_head);
1827c478bd9Sstevel@tonic-gate 	return (retval);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate int
1867c478bd9Sstevel@tonic-gate _fini(void)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	int retval;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	if ((retval = mod_remove(&modlinkage)) != 0)
1917c478bd9Sstevel@tonic-gate 		return (retval);
1927c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&fd_state_head);
1937c478bd9Sstevel@tonic-gate 	return (retval);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate int
1977c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate static int
2047c478bd9Sstevel@tonic-gate fd_getdrive(dev_t dev, struct fcu_obj **fjpp, struct fdisk **fdpp)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	if (fdpp) {
2077c478bd9Sstevel@tonic-gate 		*fdpp = ddi_get_soft_state(fd_state_head, DRIVE(dev));
2087c478bd9Sstevel@tonic-gate 		if (*fdpp && fjpp) {
2097c478bd9Sstevel@tonic-gate 			*fjpp = (*fdpp)->d_obj;
2107c478bd9Sstevel@tonic-gate 			if (*fjpp)
2117c478bd9Sstevel@tonic-gate 				return ((*fjpp)->fj_unit);
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 	return (-1);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2187c478bd9Sstevel@tonic-gate static int
2197c478bd9Sstevel@tonic-gate fd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	dev_t dev = (dev_t)arg;
2227c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
2237c478bd9Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
2247c478bd9Sstevel@tonic-gate 	int rval;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	switch (cmd) {
2277c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2287c478bd9Sstevel@tonic-gate 		(void) fd_getdrive(dev, &fjp, &fdp);
2297c478bd9Sstevel@tonic-gate 		/*
2307c478bd9Sstevel@tonic-gate 		 * Ignoring return value because success is checked by
2317c478bd9Sstevel@tonic-gate 		 * verifying fjp and fdp and returned unit value is not used.
2327c478bd9Sstevel@tonic-gate 		 */
2337c478bd9Sstevel@tonic-gate 		if (fjp && fdp) {
2347c478bd9Sstevel@tonic-gate 			*result = fjp->fj_dip;
2357c478bd9Sstevel@tonic-gate 			rval = DDI_SUCCESS;
2367c478bd9Sstevel@tonic-gate 		} else
2377c478bd9Sstevel@tonic-gate 			rval = DDI_FAILURE;
2387c478bd9Sstevel@tonic-gate 		break;
2397c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2407c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)DRIVE(dev);
2417c478bd9Sstevel@tonic-gate 		rval = DDI_SUCCESS;
2427c478bd9Sstevel@tonic-gate 		break;
2437c478bd9Sstevel@tonic-gate 	default:
2447c478bd9Sstevel@tonic-gate 		rval = DDI_FAILURE;
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 	return (rval);
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2507c478bd9Sstevel@tonic-gate #define	CMOS_ADDR	0x70
2517c478bd9Sstevel@tonic-gate #define	CMOS_DATA	0x71
2527c478bd9Sstevel@tonic-gate #define	CMOS_FDRV	0x10
2537c478bd9Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate static int
2567c478bd9Sstevel@tonic-gate fd_probe(dev_info_t *dip)
2577c478bd9Sstevel@tonic-gate {
2587c478bd9Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2597c478bd9Sstevel@tonic-gate 	int cmos;
2607c478bd9Sstevel@tonic-gate 	int drive_type;
2617c478bd9Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
2627c478bd9Sstevel@tonic-gate 	int debug[2];
2637c478bd9Sstevel@tonic-gate 	int drive_size;
2647c478bd9Sstevel@tonic-gate 	int len;
2657c478bd9Sstevel@tonic-gate 	int unit_num;
2667c478bd9Sstevel@tonic-gate 	char density[8];
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	len = sizeof (debug);
2697c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
2707c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) ==
2717c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
2727c478bd9Sstevel@tonic-gate 		fderrlevel = debug[0];
2737c478bd9Sstevel@tonic-gate #ifdef DEBUG
2747c478bd9Sstevel@tonic-gate 		fderrmask = (uint_t)debug[1];
2757c478bd9Sstevel@tonic-gate #endif
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 	len = sizeof (unit_num);
2787c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
2797c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
2807c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
2817c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_ATTA,
2827c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd_probe failed: dip %p", (void *)dip));
2837c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2877c478bd9Sstevel@tonic-gate 	/* get the cmos memory values quick and dirty */
2887c478bd9Sstevel@tonic-gate 	outb(CMOS_ADDR, CMOS_FDRV);
2897c478bd9Sstevel@tonic-gate 	cmos = drive_type = (int)inb(CMOS_DATA);
2907c478bd9Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	switch (unit_num) {
2937c478bd9Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2947c478bd9Sstevel@tonic-gate 	case 0:
2957c478bd9Sstevel@tonic-gate 		drive_type = drive_type >> 4;
2967c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
2977c478bd9Sstevel@tonic-gate 	case 1:
2987c478bd9Sstevel@tonic-gate 		if (cmos && (drive_type & 0x0F)) {
2997c478bd9Sstevel@tonic-gate 			break;
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 		/*
3027c478bd9Sstevel@tonic-gate 		 * Some enhanced floppy-disk controller adaptor cards
3037c478bd9Sstevel@tonic-gate 		 * require NO drives defined in the CMOS configuration
3047c478bd9Sstevel@tonic-gate 		 * memory.
3057c478bd9Sstevel@tonic-gate 		 * So fall through
3067c478bd9Sstevel@tonic-gate 		 */
3077c478bd9Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3087c478bd9Sstevel@tonic-gate 	default:		/* need to check conf file */
3097c478bd9Sstevel@tonic-gate 		len = sizeof (density);
3107c478bd9Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
3117c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "density", (caddr_t)&density, &len) !=
3127c478bd9Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
3137c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
3147c478bd9Sstevel@tonic-gate 			    (CE_WARN,
3157c478bd9Sstevel@tonic-gate 			    "fd_probe failed density: dip %p unit %d",
3167c478bd9Sstevel@tonic-gate 			    (void *)dip, unit_num));
3177c478bd9Sstevel@tonic-gate 			return (DDI_PROBE_FAILURE);
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 		len = sizeof (drive_size);
3207c478bd9Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
3217c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "size", (caddr_t)&drive_size, &len) !=
3227c478bd9Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
3237c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
3247c478bd9Sstevel@tonic-gate 			    (CE_WARN, "fd_probe failed size: dip %p unit %d",
3257c478bd9Sstevel@tonic-gate 			    (void *)dip, unit_num));
3267c478bd9Sstevel@tonic-gate 			return (DDI_PROBE_FAILURE);
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L3, FDEM_ATTA,
3307c478bd9Sstevel@tonic-gate 	    (CE_WARN, "fd_probe dip %p unit %d", (void *)dip, unit_num));
3317c478bd9Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /* ARGSUSED */
3367c478bd9Sstevel@tonic-gate static int
3377c478bd9Sstevel@tonic-gate fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp;
3407c478bd9Sstevel@tonic-gate 	struct fdisk *fdp;
3417c478bd9Sstevel@tonic-gate 	struct driver_minor_data *dmdp;
3427c478bd9Sstevel@tonic-gate 	int mode_3D;
3437c478bd9Sstevel@tonic-gate 	int drive_num, drive_size, drive_type;
3447c478bd9Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
3457c478bd9Sstevel@tonic-gate 	int cmos;
3467c478bd9Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3477c478bd9Sstevel@tonic-gate 	int len, sig_minor;
3487c478bd9Sstevel@tonic-gate 	int unit_num;
3497c478bd9Sstevel@tonic-gate 	char density[8];
3507c478bd9Sstevel@tonic-gate 	char name[MAXNAMELEN];
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	switch (cmd) {
3537c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
3547c478bd9Sstevel@tonic-gate 		len = sizeof (unit_num);
3557c478bd9Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
3567c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
3577c478bd9Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
3587c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
3597c478bd9Sstevel@tonic-gate 			    (CE_WARN, "fd_attach failed: dip %p", (void *)dip));
3607c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
3647c478bd9Sstevel@tonic-gate 		outb(CMOS_ADDR, CMOS_FDRV);
3657c478bd9Sstevel@tonic-gate 		cmos = drive_type = (int)inb(CMOS_DATA);
3667c478bd9Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		switch (unit_num) {
3697c478bd9Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
3707c478bd9Sstevel@tonic-gate 		case 0:
3717c478bd9Sstevel@tonic-gate 			drive_type = drive_type >> 4;
3727c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
3737c478bd9Sstevel@tonic-gate 		case 1:
3747c478bd9Sstevel@tonic-gate 			drive_type = drive_type & 0x0F;
3757c478bd9Sstevel@tonic-gate 			if (cmos)
3767c478bd9Sstevel@tonic-gate 				break;
3777c478bd9Sstevel@tonic-gate 			/*
3787c478bd9Sstevel@tonic-gate 			 * Some enhanced floppy-disk controller adaptor cards
3797c478bd9Sstevel@tonic-gate 			 * require NO drives defined in the CMOS configuration
3807c478bd9Sstevel@tonic-gate 			 * memory.
3817c478bd9Sstevel@tonic-gate 			 * So fall through
3827c478bd9Sstevel@tonic-gate 			 */
3837c478bd9Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3847c478bd9Sstevel@tonic-gate 		default:		/* need to check .conf file */
3857c478bd9Sstevel@tonic-gate 			drive_type = 0;
3867c478bd9Sstevel@tonic-gate 			len = sizeof (density);
3877c478bd9Sstevel@tonic-gate 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
3887c478bd9Sstevel@tonic-gate 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "density",
3897c478bd9Sstevel@tonic-gate 			    (caddr_t)&density, &len) != DDI_PROP_SUCCESS)
3907c478bd9Sstevel@tonic-gate 				density[0] = '\0';
3917c478bd9Sstevel@tonic-gate 			len = sizeof (drive_size);
3927c478bd9Sstevel@tonic-gate 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
3937c478bd9Sstevel@tonic-gate 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "size",
3947c478bd9Sstevel@tonic-gate 			    (caddr_t)&drive_size, &len) != DDI_PROP_SUCCESS)
3957c478bd9Sstevel@tonic-gate 				drive_size = 0;
3967c478bd9Sstevel@tonic-gate 			if (strcmp(density, "DSDD") == 0) {
3977c478bd9Sstevel@tonic-gate 				if (drive_size == 5)
3987c478bd9Sstevel@tonic-gate 					drive_type = 1;
3997c478bd9Sstevel@tonic-gate 				else if (drive_size == 3)
4007c478bd9Sstevel@tonic-gate 					drive_type = 3;
4017c478bd9Sstevel@tonic-gate 			} else if (strcmp(density, "DSHD") == 0) {
4027c478bd9Sstevel@tonic-gate 				if (drive_size == 5)
4037c478bd9Sstevel@tonic-gate 					drive_type = 2;
4047c478bd9Sstevel@tonic-gate 				else if (drive_size == 3)
4057c478bd9Sstevel@tonic-gate 					drive_type = 4;
4067c478bd9Sstevel@tonic-gate 			} else if (strcmp(density, "DSED") == 0 &&
4077c478bd9Sstevel@tonic-gate 			    drive_size == 3) {
4087c478bd9Sstevel@tonic-gate 				drive_type = 6;
4097c478bd9Sstevel@tonic-gate 			}
4107c478bd9Sstevel@tonic-gate 			break;
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 		if (drive_type == 0) {
4137c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
4147c478bd9Sstevel@tonic-gate 			    (CE_WARN, "fd_attach failed type: dip %p unit %d",
4157c478bd9Sstevel@tonic-gate 			    (void *)dip, unit_num));
4167c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		drive_num = ddi_get_instance(dip);
4207c478bd9Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(fd_state_head, drive_num) != 0)
4217c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4227c478bd9Sstevel@tonic-gate 		fdp = ddi_get_soft_state(fd_state_head, drive_num);
4237c478bd9Sstevel@tonic-gate 		fjp = fdp->d_obj = ddi_get_driver_private(dip);
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 		mutex_init(&fjp->fj_lock, NULL, MUTEX_DRIVER, *fjp->fj_iblock);
4267c478bd9Sstevel@tonic-gate 		sema_init(&fdp->d_ocsem, 1, NULL, SEMA_DRIVER, NULL);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		fjp->fj_drive = (struct fd_drive *)(fdp + 1);
4297c478bd9Sstevel@tonic-gate 		fjp->fj_chars = (struct fd_char *)(fjp->fj_drive + 1);
4307c478bd9Sstevel@tonic-gate 		fjp->fj_attr = (struct fdattr *)(fjp->fj_chars + 1);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 		/*
4337c478bd9Sstevel@tonic-gate 		 * set default floppy drive characteristics & geometry
4347c478bd9Sstevel@tonic-gate 		 */
4357c478bd9Sstevel@tonic-gate 		switch (drive_type) {	/* assume doubled sided */
4367c478bd9Sstevel@tonic-gate 		case 2:			/* 5.25 high density */
4377c478bd9Sstevel@tonic-gate 			*fjp->fj_drive = dfd_525HD;
4387c478bd9Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_5H | 1<<FMT_5D9 | 1<<FMT_5D8 |
4397c478bd9Sstevel@tonic-gate 			    1<<FMT_5D4 | 1<<FMT_5D16;
4407c478bd9Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_5H;
4417c478bd9Sstevel@tonic-gate 			break;
4427c478bd9Sstevel@tonic-gate 		case 4:			/* 3.5 high density */
4437c478bd9Sstevel@tonic-gate 			*fjp->fj_drive = dfd_350HD;
4447c478bd9Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_3H | 1<<FMT_3I | 1<<FMT_3D;
4457c478bd9Sstevel@tonic-gate 			len = sizeof (mode_3D);
4467c478bd9Sstevel@tonic-gate 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
4477c478bd9Sstevel@tonic-gate 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "mode_3D",
4487c478bd9Sstevel@tonic-gate 			    (caddr_t)&mode_3D, &len) != DDI_PROP_SUCCESS)
4497c478bd9Sstevel@tonic-gate 				mode_3D = 0;
4507c478bd9Sstevel@tonic-gate 			if (mode_3D && (fjp->fj_fdc->c_flags & FCFLG_3DMODE))
4517c478bd9Sstevel@tonic-gate 				/*
4527c478bd9Sstevel@tonic-gate 				 * 3D mode should be enabled only if a dual-
4537c478bd9Sstevel@tonic-gate 				 * speed 3.5" high-density drive and a
4547c478bd9Sstevel@tonic-gate 				 * supported floppy controller are installed.
4557c478bd9Sstevel@tonic-gate 				 */
4567c478bd9Sstevel@tonic-gate 				fdp->d_media |= 1 << FMT_3M;
4577c478bd9Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3H;
4587c478bd9Sstevel@tonic-gate 			break;
4597c478bd9Sstevel@tonic-gate 		case 1:			/* 5.25 double density */
4607c478bd9Sstevel@tonic-gate 			*fjp->fj_drive = dfd_525DD;
4617c478bd9Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_5D9 | 1<<FMT_5D8 | 1<<FMT_5D4 |
4627c478bd9Sstevel@tonic-gate 			    1<<FMT_5D16;
4637c478bd9Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_5D9;
4647c478bd9Sstevel@tonic-gate 			break;
4657c478bd9Sstevel@tonic-gate 		case 3:			/* 3.5 double density */
4667c478bd9Sstevel@tonic-gate 			*fjp->fj_drive = dfd_350HD;
4677c478bd9Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_3D;
4687c478bd9Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3D;
4697c478bd9Sstevel@tonic-gate 			break;
4707c478bd9Sstevel@tonic-gate 		case 5:			/* 3.5 extended density */
4717c478bd9Sstevel@tonic-gate 		case 6:
4727c478bd9Sstevel@tonic-gate 		case 7:
4737c478bd9Sstevel@tonic-gate 			*fjp->fj_drive = dfd_350ED;
4747c478bd9Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_3E | 1<<FMT_3H | 1<<FMT_3I |
4757c478bd9Sstevel@tonic-gate 			    1<<FMT_3D;
4767c478bd9Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3E;
4777c478bd9Sstevel@tonic-gate 			break;
4787c478bd9Sstevel@tonic-gate 		case 0:			/* no drive defined */
4797c478bd9Sstevel@tonic-gate 		default:
4807c478bd9Sstevel@tonic-gate 			goto no_attach;
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 		*fjp->fj_chars = *defchar[fdp->d_deffdtype];
4837c478bd9Sstevel@tonic-gate 		*fjp->fj_attr = fdtypes[fdp->d_deffdtype];
4847c478bd9Sstevel@tonic-gate 		bcopy(fdparts[fdp->d_deffdtype], fdp->d_part,
4857c478bd9Sstevel@tonic-gate 		    sizeof (struct partition) * NDKMAP);
4867c478bd9Sstevel@tonic-gate 		fjp->fj_rotspd = fdtypes[fdp->d_deffdtype].fda_rotatespd;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		sig_minor = drive_num << 3;
4897c478bd9Sstevel@tonic-gate 		for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
4907c478bd9Sstevel@tonic-gate 			if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
4917c478bd9Sstevel@tonic-gate 			    sig_minor | dmdp->minor, DDI_NT_FD, NULL)
4927c478bd9Sstevel@tonic-gate 			    == DDI_FAILURE) {
4937c478bd9Sstevel@tonic-gate 				ddi_remove_minor_node(dip, NULL);
4947c478bd9Sstevel@tonic-gate 				goto no_attach;
4957c478bd9Sstevel@tonic-gate 			}
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_ATTA,
4997c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd_attach: dip %p unit %d",
5007c478bd9Sstevel@tonic-gate 		    (void *)dip, unit_num));
5017c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "fd%d", drive_num);
5027c478bd9Sstevel@tonic-gate 		fdp->d_iostat = kstat_create("fd", drive_num, name, "disk",
5037c478bd9Sstevel@tonic-gate 		    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
5047c478bd9Sstevel@tonic-gate 		if (fdp->d_iostat) {
5057c478bd9Sstevel@tonic-gate 			fdp->d_iostat->ks_lock = &fjp->fj_lock;
5067c478bd9Sstevel@tonic-gate 			kstat_install(fdp->d_iostat);
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		fjp->fj_data = (caddr_t)fdp;
5107c478bd9Sstevel@tonic-gate 		fjp->fj_flags |= FUNIT_DRVATCH;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		/*
5137c478bd9Sstevel@tonic-gate 		 * Add a zero-length attribute to tell the world we support
5147c478bd9Sstevel@tonic-gate 		 * kernel ioctls (for layered drivers)
5157c478bd9Sstevel@tonic-gate 		 */
5167c478bd9Sstevel@tonic-gate 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
5177c478bd9Sstevel@tonic-gate 		    DDI_KERNEL_IOCTL, NULL, 0);
518*ca925f54SGarrett D'Amore 
519*ca925f54SGarrett D'Amore 		/*
520*ca925f54SGarrett D'Amore 		 * We want to get suspend/resume events, so that we can
521*ca925f54SGarrett D'Amore 		 * refuse to suspend when pcfs is mounted.
522*ca925f54SGarrett D'Amore 		 */
523*ca925f54SGarrett D'Amore 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
524*ca925f54SGarrett D'Amore 		    "pm-hardware-state", "needs-suspend-resume");
525*ca925f54SGarrett D'Amore 
5267c478bd9Sstevel@tonic-gate 		/*
5277c478bd9Sstevel@tonic-gate 		 * Ignoring return value because, for passed arguments, only
5287c478bd9Sstevel@tonic-gate 		 * DDI_SUCCESS is returned.
5297c478bd9Sstevel@tonic-gate 		 */
5307c478bd9Sstevel@tonic-gate 		ddi_report_dev(dip);
5317c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
534*ca925f54SGarrett D'Amore 		/* nothing for us to do */
5357c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	default:
5387c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate no_attach:
5417c478bd9Sstevel@tonic-gate 	fjp->fj_drive = NULL;
5427c478bd9Sstevel@tonic-gate 	fjp->fj_chars = NULL;
5437c478bd9Sstevel@tonic-gate 	fjp->fj_attr = NULL;
5447c478bd9Sstevel@tonic-gate 	mutex_destroy(&fjp->fj_lock);
5457c478bd9Sstevel@tonic-gate 	sema_destroy(&fdp->d_ocsem);
5467c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(fd_state_head, drive_num);
5477c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L3, FDEM_ATTA,
5487c478bd9Sstevel@tonic-gate 	    (CE_WARN, "fd_attach failed: dip %p unit %d",
5497c478bd9Sstevel@tonic-gate 	    (void *)dip, unit_num));
5507c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate /* ARGSUSED */
5557c478bd9Sstevel@tonic-gate static int
5567c478bd9Sstevel@tonic-gate fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp;
5597c478bd9Sstevel@tonic-gate 	struct fdisk *fdp;
5607c478bd9Sstevel@tonic-gate 	int drive_num;
5617c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fd_detach dip %p",
5647c478bd9Sstevel@tonic-gate 	    (void *)dip));
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	drive_num = ddi_get_instance(dip);
5677c478bd9Sstevel@tonic-gate 	if (!(fdp = ddi_get_soft_state(fd_state_head, drive_num)))
5687c478bd9Sstevel@tonic-gate 		return (rval);
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	switch (cmd) {
5717c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
5727c478bd9Sstevel@tonic-gate 		if (fd_unit_is_open(fdp)) {
573*ca925f54SGarrett D'Amore 			rval = DDI_FAILURE;
5747c478bd9Sstevel@tonic-gate 			break;
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 		kstat_delete(fdp->d_iostat);
5777c478bd9Sstevel@tonic-gate 		fdp->d_iostat = NULL;
5787c478bd9Sstevel@tonic-gate 		fjp = (struct fcu_obj *)fdp->d_obj;
579*ca925f54SGarrett D'Amore 		fjp->fj_flags &= ~FUNIT_DRVATCH;
5807c478bd9Sstevel@tonic-gate 		fjp->fj_data = NULL;
5817c478bd9Sstevel@tonic-gate 		fjp->fj_drive = NULL;
5827c478bd9Sstevel@tonic-gate 		fjp->fj_chars = NULL;
5837c478bd9Sstevel@tonic-gate 		fjp->fj_attr = NULL;
5847c478bd9Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
5857c478bd9Sstevel@tonic-gate 		mutex_destroy(&fjp->fj_lock);
5867c478bd9Sstevel@tonic-gate 		sema_destroy(&fdp->d_ocsem);
5877c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(fd_state_head, drive_num);
5887c478bd9Sstevel@tonic-gate 		break;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
591*ca925f54SGarrett D'Amore 		/*
592*ca925f54SGarrett D'Amore 		 * Bad, bad, bad things will happen if someone
593*ca925f54SGarrett D'Amore 		 * *changes* the disk in the drive while it is mounted
594*ca925f54SGarrett D'Amore 		 * and the system is suspended.  We have no way to
595*ca925f54SGarrett D'Amore 		 * detect that.  (Undetected filesystem corruption.
596*ca925f54SGarrett D'Amore 		 * Its akin to changing the boot disk while the system
597*ca925f54SGarrett D'Amore 		 * is suspended.  Don't do it!)
598*ca925f54SGarrett D'Amore 		 *
599*ca925f54SGarrett D'Amore 		 * So we refuse to suspend if there is a mounted filesystem.
600*ca925f54SGarrett D'Amore 		 * (We guess this by looking for a block open.  Character
601*ca925f54SGarrett D'Amore 		 * opens are fine.)  This limits some of the usability of
602*ca925f54SGarrett D'Amore 		 * suspend/resume, but it certainly avoids this
603*ca925f54SGarrett D'Amore 		 * potential filesytem corruption from pilot error.
604*ca925f54SGarrett D'Amore 		 * Given the decreasing popularity of floppy media, we
605*ca925f54SGarrett D'Amore 		 * don't see this as much of a limitation.
606*ca925f54SGarrett D'Amore 		 */
607*ca925f54SGarrett D'Amore 		if (fdp->d_regopen[OTYP_BLK]) {
608*ca925f54SGarrett D'Amore 			cmn_err(CE_NOTE,
609*ca925f54SGarrett D'Amore 			    "Unable to suspend while floppy is in use.");
610*ca925f54SGarrett D'Amore 			rval = DDI_FAILURE;
6117c478bd9Sstevel@tonic-gate 		}
6127c478bd9Sstevel@tonic-gate 		break;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	default:
615*ca925f54SGarrett D'Amore 		rval = DDI_FAILURE;
6167c478bd9Sstevel@tonic-gate 		break;
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 	return (rval);
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate static int
6237c478bd9Sstevel@tonic-gate fd_part_is_open(struct fdisk *fdp, int part)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate 	int i;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	for (i = 0; i < (OTYPCNT - 1); i++)
6287c478bd9Sstevel@tonic-gate 		if (fdp->d_regopen[i] & (1 << part))
6297c478bd9Sstevel@tonic-gate 			return (1);
6307c478bd9Sstevel@tonic-gate 	return (0);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate static int
6347c478bd9Sstevel@tonic-gate fd_unit_is_open(struct fdisk *fdp)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	int i;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++)
6397c478bd9Sstevel@tonic-gate 		if (fdp->d_lyropen[i])
6407c478bd9Sstevel@tonic-gate 			return (1);
6417c478bd9Sstevel@tonic-gate 	for (i = 0; i < (OTYPCNT - 1); i++)
6427c478bd9Sstevel@tonic-gate 		if (fdp->d_regopen[i])
6437c478bd9Sstevel@tonic-gate 			return (1);
6447c478bd9Sstevel@tonic-gate 	return (0);
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6487c478bd9Sstevel@tonic-gate static int
6497c478bd9Sstevel@tonic-gate fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
6507c478bd9Sstevel@tonic-gate {
6517c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
6527c478bd9Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
6537c478bd9Sstevel@tonic-gate 	struct partition *pp;
6547c478bd9Sstevel@tonic-gate 	dev_t dev;
6557c478bd9Sstevel@tonic-gate 	int part, unit;
6567c478bd9Sstevel@tonic-gate 	int part_is_open;
6577c478bd9Sstevel@tonic-gate 	int rval;
6587c478bd9Sstevel@tonic-gate 	uint_t pbit;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	dev = *devp;
6617c478bd9Sstevel@tonic-gate 	unit = fd_getdrive(dev, &fjp, &fdp);
6627c478bd9Sstevel@tonic-gate 	if (!fjp || !fdp)
6637c478bd9Sstevel@tonic-gate 		return (ENXIO);
6647c478bd9Sstevel@tonic-gate 	part = PARTITION(dev);
6657c478bd9Sstevel@tonic-gate 	pbit = 1 << part;
6667c478bd9Sstevel@tonic-gate 	pp = &fdp->d_part[part];
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/*
6697c478bd9Sstevel@tonic-gate 	 * Serialize opens/closes
6707c478bd9Sstevel@tonic-gate 	 */
6717c478bd9Sstevel@tonic-gate 	sema_p(&fdp->d_ocsem);
6727c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
6737c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_open: fd%d part %d flag %x otype %x\n", DRIVE(dev),
6747c478bd9Sstevel@tonic-gate 	    part, flag, otyp));
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	/*
6777c478bd9Sstevel@tonic-gate 	 * Check for previous exclusive open, or trying to exclusive open
6787c478bd9Sstevel@tonic-gate 	 * An "exclusive open" on any partition is not guaranteed to
6797c478bd9Sstevel@tonic-gate 	 * protect against opens on another partition that overlaps it.
6807c478bd9Sstevel@tonic-gate 	 */
6817c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
6827c478bd9Sstevel@tonic-gate 		part_is_open = (fdp->d_lyropen[part] != 0);
6837c478bd9Sstevel@tonic-gate 	} else {
6847c478bd9Sstevel@tonic-gate 		part_is_open = fd_part_is_open(fdp, part);
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 	if ((fdp->d_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
6877c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_OPEN, (CE_CONT,
6887c478bd9Sstevel@tonic-gate 		    "fd_open: exclparts %lx openparts %lx lyrcnt %lx pbit %x\n",
6897c478bd9Sstevel@tonic-gate 		    fdp->d_exclmask, fdp->d_regopen[otyp], fdp->d_lyropen[part],
6907c478bd9Sstevel@tonic-gate 		    pbit));
6917c478bd9Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
6927c478bd9Sstevel@tonic-gate 		return (EBUSY);
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/*
6967c478bd9Sstevel@tonic-gate 	 * Ensure that drive is recalibrated on first open of new diskette.
6977c478bd9Sstevel@tonic-gate 	 */
6987c478bd9Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 1);
6997c478bd9Sstevel@tonic-gate 	if (fjp->fj_ops->fco_getchng(fjp, unit) != 0) {
7007c478bd9Sstevel@tonic-gate 		if (fjp->fj_ops->fco_rcseek(fjp, unit, -1, 0)) {
7017c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L2, FDEM_OPEN,
7027c478bd9Sstevel@tonic-gate 			    (CE_NOTE, "fd_open fd%d: not ready", DRIVE(dev)));
7037c478bd9Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
7047c478bd9Sstevel@tonic-gate 			sema_v(&fdp->d_ocsem);
7057c478bd9Sstevel@tonic-gate 			return (ENXIO);
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 	if (flag & (FNDELAY | FNONBLOCK)) {
7107c478bd9Sstevel@tonic-gate 		/* don't attempt access, just return successfully */
7117c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
7127c478bd9Sstevel@tonic-gate 		goto out;
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	/*
7167c478bd9Sstevel@tonic-gate 	 * auto-sense the density/format of the diskette
7177c478bd9Sstevel@tonic-gate 	 */
7187c478bd9Sstevel@tonic-gate 	rval = fdgetlabel(fjp, unit);
7197c478bd9Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 0);
7207c478bd9Sstevel@tonic-gate 	if (rval) {
7217c478bd9Sstevel@tonic-gate 		/* didn't find label (couldn't read anything) */
7227c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_OPEN,
7237c478bd9Sstevel@tonic-gate 		    (CE_NOTE, "fd%d: drive not ready", DRIVE(dev)));
7247c478bd9Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
7257c478bd9Sstevel@tonic-gate 		return (EIO);
7267c478bd9Sstevel@tonic-gate 	}
7277c478bd9Sstevel@tonic-gate 	/* check partition */
7287c478bd9Sstevel@tonic-gate 	if (pp->p_size == 0) {
7297c478bd9Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
7307c478bd9Sstevel@tonic-gate 		return (ENXIO);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 	/*
7337c478bd9Sstevel@tonic-gate 	 * if opening for writing, check write protect on diskette
7347c478bd9Sstevel@tonic-gate 	 */
7357c478bd9Sstevel@tonic-gate 	if ((flag & FWRITE) && (fdp->d_obj->fj_flags & FUNIT_WPROT)) {
7367c478bd9Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
7377c478bd9Sstevel@tonic-gate 		return (EROFS);
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate out:
7417c478bd9Sstevel@tonic-gate 	/*
7427c478bd9Sstevel@tonic-gate 	 * mark open as having succeeded
7437c478bd9Sstevel@tonic-gate 	 */
7447c478bd9Sstevel@tonic-gate 	if (flag & FEXCL)
7457c478bd9Sstevel@tonic-gate 		fdp->d_exclmask |= pbit;
7467c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR)
7477c478bd9Sstevel@tonic-gate 		fdp->d_lyropen[part]++;
7487c478bd9Sstevel@tonic-gate 	else
7497c478bd9Sstevel@tonic-gate 		fdp->d_regopen[otyp] |= 1 << part;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	sema_v(&fdp->d_ocsem);
7527c478bd9Sstevel@tonic-gate 	return (0);
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate /*
7567c478bd9Sstevel@tonic-gate  * fdgetlabel - read the SunOS label off the diskette
7577c478bd9Sstevel@tonic-gate  *	if it can read a valid label it does so, else it will use a
7587c478bd9Sstevel@tonic-gate  *	default.  If it can`t read the diskette - that is an error.
7597c478bd9Sstevel@tonic-gate  *
7607c478bd9Sstevel@tonic-gate  * RETURNS: 0 for ok - meaning that it could at least read the device,
7617c478bd9Sstevel@tonic-gate  *	!0 for error XXX TBD NYD error codes
7627c478bd9Sstevel@tonic-gate  */
7637c478bd9Sstevel@tonic-gate static int
7647c478bd9Sstevel@tonic-gate fdgetlabel(struct fcu_obj *fjp, int unit)
7657c478bd9Sstevel@tonic-gate {
7667c478bd9Sstevel@tonic-gate 	struct dk_label *label;
7677c478bd9Sstevel@tonic-gate 	struct fdisk *fdp;
7687c478bd9Sstevel@tonic-gate 	char *newlabel;
7697c478bd9Sstevel@tonic-gate 	short *sp;
7707c478bd9Sstevel@tonic-gate 	short count;
7717c478bd9Sstevel@tonic-gate 	short xsum;
7727c478bd9Sstevel@tonic-gate 	int tries, try_this;
7737c478bd9Sstevel@tonic-gate 	uint_t nexttype;
7747c478bd9Sstevel@tonic-gate 	int rval;
7757c478bd9Sstevel@tonic-gate 	short oldlvl;
7767c478bd9Sstevel@tonic-gate 	int i;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_GETL,
7797c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fdgetlabel fd unit %d\n", unit));
7807c478bd9Sstevel@tonic-gate 	fdp = (struct fdisk *)fjp->fj_data;
7817c478bd9Sstevel@tonic-gate 	fjp->fj_flags &= ~(FUNIT_UNLABELED);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	/*
7847c478bd9Sstevel@tonic-gate 	 * get some space to play with the label
7857c478bd9Sstevel@tonic-gate 	 */
7867c478bd9Sstevel@tonic-gate 	label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
7877c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_GETL, (CE_CONT,
7887c478bd9Sstevel@tonic-gate 	    "fdgetlabel fd unit %d kmem_zalloc: ptr = %p, size = %lx\n",
7897c478bd9Sstevel@tonic-gate 	    unit, (void *)label, (size_t)sizeof (struct dk_label)));
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	/*
7927c478bd9Sstevel@tonic-gate 	 * read block 0 (0/0/1) to find the label
7937c478bd9Sstevel@tonic-gate 	 * (disk is potentially not present or unformatted)
7947c478bd9Sstevel@tonic-gate 	 */
7957c478bd9Sstevel@tonic-gate 	/* noerrprint since this is a private cmd */
7967c478bd9Sstevel@tonic-gate 	oldlvl = fderrlevel;
7977c478bd9Sstevel@tonic-gate 	fderrlevel = FDEP_LMAX;
7987c478bd9Sstevel@tonic-gate 	/*
7997c478bd9Sstevel@tonic-gate 	 * try different characteristics (ie densities)
8007c478bd9Sstevel@tonic-gate 	 *
8017c478bd9Sstevel@tonic-gate 	 * if fdp->d_curfdtype is -1 then the current characteristics
8027c478bd9Sstevel@tonic-gate 	 * were set by ioctl and need to try it as well as everything
8037c478bd9Sstevel@tonic-gate 	 * in the table
8047c478bd9Sstevel@tonic-gate 	 */
8057c478bd9Sstevel@tonic-gate 	nexttype = fdp->d_deffdtype;
8067c478bd9Sstevel@tonic-gate 	try_this = 1;		/* always try the current characteristics */
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	for (tries = nfdtypes; tries; tries--) {
8097c478bd9Sstevel@tonic-gate 		if (try_this) {
8107c478bd9Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHAROK;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 			/* try reading last sector of cyl 1, head 0 */
8137c478bd9Sstevel@tonic-gate 			if (!(rval = fjp->fj_ops->fco_rw(fjp, unit,
8147c478bd9Sstevel@tonic-gate 			    FDREAD, 1, 0, fjp->fj_chars->fdc_secptrack,
8157c478bd9Sstevel@tonic-gate 			    (caddr_t)label,
8167c478bd9Sstevel@tonic-gate 			    sizeof (struct dk_label))) &&
8177c478bd9Sstevel@tonic-gate 			    /* and last sector plus 1 of cylinder 1 */
8187c478bd9Sstevel@tonic-gate 			    fjp->fj_ops->fco_rw(fjp, unit, FDREAD, 1,
8197c478bd9Sstevel@tonic-gate 			    0, fjp->fj_chars->fdc_secptrack + 1,
8207c478bd9Sstevel@tonic-gate 			    (caddr_t)label,
8217c478bd9Sstevel@tonic-gate 			    sizeof (struct dk_label)) &&
8227c478bd9Sstevel@tonic-gate 			    /* and label sector on cylinder 0 */
8237c478bd9Sstevel@tonic-gate 			    !(rval = fjp->fj_ops->fco_rw(fjp, unit,
8247c478bd9Sstevel@tonic-gate 			    FDREAD, 0, 0, 1, (caddr_t)label,
8257c478bd9Sstevel@tonic-gate 			    sizeof (struct dk_label))))
8267c478bd9Sstevel@tonic-gate 				break;
8277c478bd9Sstevel@tonic-gate 			if (rval == ENXIO)
8287c478bd9Sstevel@tonic-gate 				break;
8297c478bd9Sstevel@tonic-gate 		}
8307c478bd9Sstevel@tonic-gate 		/*
8317c478bd9Sstevel@tonic-gate 		 * try the next entry in the characteristics tbl
8327c478bd9Sstevel@tonic-gate 		 */
8337c478bd9Sstevel@tonic-gate 		fdp->d_curfdtype = (signed char)nexttype;
8347c478bd9Sstevel@tonic-gate 		nexttype = (nexttype + 1) % nfdtypes;
8357c478bd9Sstevel@tonic-gate 		if ((1 << fdp->d_curfdtype) & fdp->d_media) {
8367c478bd9Sstevel@tonic-gate 			*fjp->fj_chars = *defchar[fdp->d_curfdtype];
8377c478bd9Sstevel@tonic-gate 			*fjp->fj_attr = fdtypes[fdp->d_curfdtype];
8387c478bd9Sstevel@tonic-gate 			bcopy(fdparts[fdp->d_curfdtype], fdp->d_part,
8397c478bd9Sstevel@tonic-gate 			    sizeof (struct partition) * NDKMAP);
8407c478bd9Sstevel@tonic-gate 			/*
8417c478bd9Sstevel@tonic-gate 			 * check for a double_density diskette
8427c478bd9Sstevel@tonic-gate 			 * in a high_density 5.25" drive
8437c478bd9Sstevel@tonic-gate 			 */
8447c478bd9Sstevel@tonic-gate 			if (fjp->fj_chars->fdc_transfer_rate == 250 &&
8457c478bd9Sstevel@tonic-gate 			    fjp->fj_rotspd > fjp->fj_attr->fda_rotatespd) {
8467c478bd9Sstevel@tonic-gate 				/*
8477c478bd9Sstevel@tonic-gate 				 * yes - adjust transfer rate since we don't
8487c478bd9Sstevel@tonic-gate 				 * know if we have a 5.25" dual-speed drive
8497c478bd9Sstevel@tonic-gate 				 */
8507c478bd9Sstevel@tonic-gate 				fjp->fj_attr->fda_rotatespd = 360;
8517c478bd9Sstevel@tonic-gate 				fjp->fj_chars->fdc_transfer_rate = 300;
8527c478bd9Sstevel@tonic-gate 				fjp->fj_chars->fdc_medium = 5;
8537c478bd9Sstevel@tonic-gate 			}
8547c478bd9Sstevel@tonic-gate 			if ((2 * fjp->fj_chars->fdc_ncyl) ==
8557c478bd9Sstevel@tonic-gate 			    defchar[fdp->d_deffdtype]->fdc_ncyl) {
8567c478bd9Sstevel@tonic-gate 				/* yes - adjust steps per cylinder */
8577c478bd9Sstevel@tonic-gate 				fjp->fj_chars->fdc_steps = 2;
8587c478bd9Sstevel@tonic-gate 			} else
8597c478bd9Sstevel@tonic-gate 				fjp->fj_chars->fdc_steps = 1;
8607c478bd9Sstevel@tonic-gate 			try_this = 1;
8617c478bd9Sstevel@tonic-gate 		} else
8627c478bd9Sstevel@tonic-gate 			try_this = 0;
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 	fderrlevel = oldlvl;	/* print errors again */
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	if (rval) {
8677c478bd9Sstevel@tonic-gate 		fdp->d_curfdtype = fdp->d_deffdtype;
8687c478bd9Sstevel@tonic-gate 		goto out;			/* couldn't read anything */
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_GETL,
8727c478bd9Sstevel@tonic-gate 	    (CE_CONT,
8737c478bd9Sstevel@tonic-gate 	    "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n",
8747c478bd9Sstevel@tonic-gate 	    unit, fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_secptrack,
8757c478bd9Sstevel@tonic-gate 	    fjp->fj_chars->fdc_steps, fjp->fj_attr->fda_rotatespd,
8767c478bd9Sstevel@tonic-gate 	    fjp->fj_attr->fda_intrlv));
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	/*
8797c478bd9Sstevel@tonic-gate 	 * _something_ was read  -  look for unixtype label
8807c478bd9Sstevel@tonic-gate 	 */
8817c478bd9Sstevel@tonic-gate 	if (label->dkl_magic != DKL_MAGIC ||
8827c478bd9Sstevel@tonic-gate 	    label->dkl_vtoc.v_sanity != VTOC_SANE) {
8837c478bd9Sstevel@tonic-gate 		/* not a label - no magic number */
8847c478bd9Sstevel@tonic-gate 		goto nolabel;	/* no errors, but no label */
8857c478bd9Sstevel@tonic-gate 	}
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	count = sizeof (struct dk_label) / sizeof (short);
8887c478bd9Sstevel@tonic-gate 	sp = (short *)label;
8897c478bd9Sstevel@tonic-gate 	xsum = 0;
8907c478bd9Sstevel@tonic-gate 	while (count--)
8917c478bd9Sstevel@tonic-gate 		xsum ^= *sp++;	/* should add up to 0 */
8927c478bd9Sstevel@tonic-gate 	if (xsum) {
8937c478bd9Sstevel@tonic-gate 		/* not a label - checksum didn't compute */
8947c478bd9Sstevel@tonic-gate 		goto nolabel;	/* no errors, but no label */
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/*
8987c478bd9Sstevel@tonic-gate 	 * the SunOS label overrides current diskette characteristics
8997c478bd9Sstevel@tonic-gate 	 */
9007c478bd9Sstevel@tonic-gate 	fjp->fj_chars->fdc_ncyl = label->dkl_pcyl;
9017c478bd9Sstevel@tonic-gate 	fjp->fj_chars->fdc_nhead = label->dkl_nhead;
9027c478bd9Sstevel@tonic-gate 	fjp->fj_chars->fdc_secptrack = (label->dkl_nsect * DEV_BSIZE) /
9037c478bd9Sstevel@tonic-gate 	    fjp->fj_chars->fdc_sec_size;
9047c478bd9Sstevel@tonic-gate 	if (defchar[fdp->d_deffdtype]->fdc_ncyl == 2 * fjp->fj_chars->fdc_ncyl)
9057c478bd9Sstevel@tonic-gate 		fjp->fj_chars->fdc_steps = 2;
9067c478bd9Sstevel@tonic-gate 	else
9077c478bd9Sstevel@tonic-gate 		fjp->fj_chars->fdc_steps = 1;
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	fjp->fj_attr->fda_rotatespd = label->dkl_rpm;
9107c478bd9Sstevel@tonic-gate 	fjp->fj_attr->fda_intrlv = label->dkl_intrlv;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	fdp->d_vtoc_version = label->dkl_vtoc.v_version;
9137c478bd9Sstevel@tonic-gate 	bcopy(label->dkl_vtoc.v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
9147c478bd9Sstevel@tonic-gate 	bcopy(label->dkl_vtoc.v_asciilabel,
9157c478bd9Sstevel@tonic-gate 	    fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
9167c478bd9Sstevel@tonic-gate 	/*
9177c478bd9Sstevel@tonic-gate 	 * logical partitions
9187c478bd9Sstevel@tonic-gate 	 */
9197c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
9207c478bd9Sstevel@tonic-gate 		fdp->d_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag;
9217c478bd9Sstevel@tonic-gate 		fdp->d_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag;
9227c478bd9Sstevel@tonic-gate 		fdp->d_part[i].p_start = label->dkl_vtoc.v_part[i].p_start;
9237c478bd9Sstevel@tonic-gate 		fdp->d_part[i].p_size = label->dkl_vtoc.v_part[i].p_size;
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 		fdp->d_vtoc_timestamp[i] = label->dkl_vtoc.timestamp[i];
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	fjp->fj_flags |= FUNIT_LABELOK;
9297c478bd9Sstevel@tonic-gate 	goto out;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate nolabel:
9327c478bd9Sstevel@tonic-gate 	/*
9337c478bd9Sstevel@tonic-gate 	 * if not found, fill in label info from default (mark default used)
9347c478bd9Sstevel@tonic-gate 	 */
9357c478bd9Sstevel@tonic-gate 	if (fdp->d_media & (1<<FMT_3D))
9367c478bd9Sstevel@tonic-gate 		newlabel = deflabel_35;
9377c478bd9Sstevel@tonic-gate 	else /* if (fdp->d_media & (1<<FMT_5D9)) */
9387c478bd9Sstevel@tonic-gate 		newlabel = deflabel_525;
9397c478bd9Sstevel@tonic-gate 	bzero(fdp->d_vtoc_volume, LEN_DKL_VVOL);
9407c478bd9Sstevel@tonic-gate 	(void) sprintf(fdp->d_vtoc_asciilabel, newlabel,
9417c478bd9Sstevel@tonic-gate 	    fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_nhead,
9427c478bd9Sstevel@tonic-gate 	    fjp->fj_chars->fdc_secptrack);
9437c478bd9Sstevel@tonic-gate 	fjp->fj_flags |= FUNIT_UNLABELED;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate out:
9467c478bd9Sstevel@tonic-gate 	kmem_free(label, sizeof (struct dk_label));
9477c478bd9Sstevel@tonic-gate 	return (rval);
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9527c478bd9Sstevel@tonic-gate static int
9537c478bd9Sstevel@tonic-gate fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
9567c478bd9Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
9577c478bd9Sstevel@tonic-gate 	int part, part_is_closed;
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate #ifdef DEBUG
9607c478bd9Sstevel@tonic-gate 	int unit;
9617c478bd9Sstevel@tonic-gate #define	DEBUG_ASSIGN	unit=
9627c478bd9Sstevel@tonic-gate #else
9637c478bd9Sstevel@tonic-gate #define	DEBUG_ASSIGN	(void)
9647c478bd9Sstevel@tonic-gate #endif
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	DEBUG_ASSIGN fd_getdrive(dev, &fjp, &fdp);
9677c478bd9Sstevel@tonic-gate 	/*
9687c478bd9Sstevel@tonic-gate 	 * Ignoring return in non DEBUG mode because success is checked by
9697c478bd9Sstevel@tonic-gate 	 * verifying fjp and fdp and returned unit value is not used.
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	if (!fjp || !fdp)
9727c478bd9Sstevel@tonic-gate 		return (ENXIO);
9737c478bd9Sstevel@tonic-gate 	part = PARTITION(dev);
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	sema_p(&fdp->d_ocsem);
9767c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CLOS,
9777c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_close: fd unit %d part %d otype %x\n",
9787c478bd9Sstevel@tonic-gate 	    unit, part, otyp));
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
9817c478bd9Sstevel@tonic-gate 		if (fdp->d_lyropen[part])
9827c478bd9Sstevel@tonic-gate 			fdp->d_lyropen[part]--;
9837c478bd9Sstevel@tonic-gate 		part_is_closed = (fdp->d_lyropen[part] == 0);
9847c478bd9Sstevel@tonic-gate 	} else {
9857c478bd9Sstevel@tonic-gate 		fdp->d_regopen[otyp] &= ~(1<<part);
9867c478bd9Sstevel@tonic-gate 		part_is_closed = 1;
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 	if (part_is_closed) {
9897c478bd9Sstevel@tonic-gate 		if (part == 2 && fdp->d_exclmask&(1<<part))
9907c478bd9Sstevel@tonic-gate 			fdp->d_exclmask = 0;
9917c478bd9Sstevel@tonic-gate 		else
9927c478bd9Sstevel@tonic-gate 			fdp->d_exclmask &= ~(1<<part);
9937c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_CLOS,
9947c478bd9Sstevel@tonic-gate 		    (CE_CONT,
9957c478bd9Sstevel@tonic-gate 		    "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n",
9967c478bd9Sstevel@tonic-gate 		    fdp->d_exclmask, fdp->d_regopen[otyp],
9977c478bd9Sstevel@tonic-gate 		    fdp->d_lyropen[part]));
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		if (fd_unit_is_open(fdp) == 0)
10007c478bd9Sstevel@tonic-gate 			fdp->d_obj->fj_flags &= ~FUNIT_CHANGED;
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 	sema_v(&fdp->d_ocsem);
10037c478bd9Sstevel@tonic-gate 	return (0);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate /* ARGSUSED */
10077c478bd9Sstevel@tonic-gate static int
10087c478bd9Sstevel@tonic-gate fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
10097c478bd9Sstevel@tonic-gate {
10107c478bd9Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
10117c478bd9Sstevel@tonic-gate }
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate /* ARGSUSED */
10147c478bd9Sstevel@tonic-gate static int
10157c478bd9Sstevel@tonic-gate fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
10167c478bd9Sstevel@tonic-gate {
10177c478bd9Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate /*
10217c478bd9Sstevel@tonic-gate  * fd_strategy
10227c478bd9Sstevel@tonic-gate  *	checks operation, hangs buf struct off fdcntlr, calls fdstart
10237c478bd9Sstevel@tonic-gate  *	if not already busy.  Note that if we call start, then the operation
10247c478bd9Sstevel@tonic-gate  *	will already be done on return (start sleeps).
10257c478bd9Sstevel@tonic-gate  */
10267c478bd9Sstevel@tonic-gate static int
10277c478bd9Sstevel@tonic-gate fd_strategy(struct buf *bp)
10287c478bd9Sstevel@tonic-gate {
10297c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp;
10307c478bd9Sstevel@tonic-gate 	struct fdisk *fdp;
10317c478bd9Sstevel@tonic-gate 	struct partition *pp;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_STRA,
10347c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
10357c478bd9Sstevel@tonic-gate 	    (void *)bp, bp->b_edev));
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	(void) fd_getdrive(bp->b_edev, &fjp, &fdp);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	/*
10407c478bd9Sstevel@tonic-gate 	 * Ignoring return because device exist.
10417c478bd9Sstevel@tonic-gate 	 * Returned unit value is not used.
10427c478bd9Sstevel@tonic-gate 	 */
10437c478bd9Sstevel@tonic-gate 	pp = &fdp->d_part[PARTITION(bp->b_edev)];
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	if (fjp->fj_chars->fdc_sec_size > NBPSCTR && (bp->b_blkno & 1))  {
10467c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
10477c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd%d: block %ld is not start of sector!",
10487c478bd9Sstevel@tonic-gate 		    DRIVE(bp->b_edev), (long)bp->b_blkno));
10497c478bd9Sstevel@tonic-gate 		bp->b_error = EINVAL;
10507c478bd9Sstevel@tonic-gate 		goto bad;
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	if ((bp->b_blkno > pp->p_size)) {
10547c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
10557c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd%d: block %ld is past the end! (nblk=%ld)",
10567c478bd9Sstevel@tonic-gate 		    DRIVE(bp->b_edev), (long)bp->b_blkno, pp->p_size));
10577c478bd9Sstevel@tonic-gate 		bp->b_error = ENOSPC;
10587c478bd9Sstevel@tonic-gate 		goto bad;
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	/* if at end of file, skip out now */
10627c478bd9Sstevel@tonic-gate 	if (bp->b_blkno == pp->p_size) {
10637c478bd9Sstevel@tonic-gate 		if ((bp->b_flags & B_READ) == 0) {
10647c478bd9Sstevel@tonic-gate 			/* a write needs to get an error! */
10657c478bd9Sstevel@tonic-gate 			bp->b_error = ENOSPC;
10667c478bd9Sstevel@tonic-gate 			goto bad;
10677c478bd9Sstevel@tonic-gate 		}
10687c478bd9Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
10697c478bd9Sstevel@tonic-gate 		biodone(bp);
10707c478bd9Sstevel@tonic-gate 		return (0);
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	/* if operation not a multiple of sector size, is error! */
10747c478bd9Sstevel@tonic-gate 	if (bp->b_bcount % fjp->fj_chars->fdc_sec_size)  {
10757c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
10767c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd%d: count %ld must be a multiple of %d",
10777c478bd9Sstevel@tonic-gate 		    DRIVE(bp->b_edev), bp->b_bcount,
10787c478bd9Sstevel@tonic-gate 		    fjp->fj_chars->fdc_sec_size));
10797c478bd9Sstevel@tonic-gate 		bp->b_error = EINVAL;
10807c478bd9Sstevel@tonic-gate 		goto bad;
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	/*
10847c478bd9Sstevel@tonic-gate 	 * Put the buf request in the drive's queue, FIFO.
10857c478bd9Sstevel@tonic-gate 	 */
10867c478bd9Sstevel@tonic-gate 	bp->av_forw = 0;
10877c478bd9Sstevel@tonic-gate 	mutex_enter(&fjp->fj_lock);
10887c478bd9Sstevel@tonic-gate 	if (fdp->d_iostat)
10897c478bd9Sstevel@tonic-gate 		kstat_waitq_enter(KIOSP);
10907c478bd9Sstevel@tonic-gate 	if (fdp->d_actf)
10917c478bd9Sstevel@tonic-gate 		fdp->d_actl->av_forw = bp;
10927c478bd9Sstevel@tonic-gate 	else
10937c478bd9Sstevel@tonic-gate 		fdp->d_actf = bp;
10947c478bd9Sstevel@tonic-gate 	fdp->d_actl = bp;
10957c478bd9Sstevel@tonic-gate 	if (!(fjp->fj_flags & FUNIT_BUSY)) {
10967c478bd9Sstevel@tonic-gate 		fdstart(fjp);
10977c478bd9Sstevel@tonic-gate 	}
10987c478bd9Sstevel@tonic-gate 	mutex_exit(&fjp->fj_lock);
10997c478bd9Sstevel@tonic-gate 	return (0);
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate bad:
11027c478bd9Sstevel@tonic-gate 	bp->b_resid = bp->b_bcount;
11037c478bd9Sstevel@tonic-gate 	bp->b_flags |= B_ERROR;
11047c478bd9Sstevel@tonic-gate 	biodone(bp);
11057c478bd9Sstevel@tonic-gate 	return (0);
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate /*
11097c478bd9Sstevel@tonic-gate  * fdstart
11107c478bd9Sstevel@tonic-gate  *	called from fd_strategy() or from fdXXXX() to setup and
11117c478bd9Sstevel@tonic-gate  *	start operations of read or write only (using buf structs).
11127c478bd9Sstevel@tonic-gate  *	Because the chip doesn't handle crossing cylinder boundaries on
11137c478bd9Sstevel@tonic-gate  *	the fly, this takes care of those boundary conditions.  Note that
11147c478bd9Sstevel@tonic-gate  *	it sleeps until the operation is done *within fdstart* - so that
11157c478bd9Sstevel@tonic-gate  *	when fdstart returns, the operation is already done.
11167c478bd9Sstevel@tonic-gate  */
11177c478bd9Sstevel@tonic-gate static void
11187c478bd9Sstevel@tonic-gate fdstart(struct fcu_obj *fjp)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate 	struct buf *bp;
11217c478bd9Sstevel@tonic-gate 	struct fdisk *fdp = (struct fdisk *)fjp->fj_data;
11227c478bd9Sstevel@tonic-gate 	struct fd_char *chp;
11237c478bd9Sstevel@tonic-gate 	struct partition *pp;
11247c478bd9Sstevel@tonic-gate 	uint_t ptend;
11257c478bd9Sstevel@tonic-gate 	uint_t bincyl;		/* (the number of the desired) block in cyl. */
11267c478bd9Sstevel@tonic-gate 	uint_t blk, len, tlen;
11277c478bd9Sstevel@tonic-gate 	uint_t secpcyl;		/* number of sectors per cylinder */
11287c478bd9Sstevel@tonic-gate 	int cyl, head, sect;
11297c478bd9Sstevel@tonic-gate 	int sctrshft, unit;
11307c478bd9Sstevel@tonic-gate 	caddr_t	addr;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fjp->fj_lock));
11337c478bd9Sstevel@tonic-gate 	fjp->fj_flags |= FUNIT_BUSY;
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	while ((bp = fdp->d_actf) != NULL) {
11367c478bd9Sstevel@tonic-gate 		fdp->d_actf = bp->av_forw;
11377c478bd9Sstevel@tonic-gate 		fdp->d_current = bp;
11387c478bd9Sstevel@tonic-gate 		if (fdp->d_iostat) {
11397c478bd9Sstevel@tonic-gate 			kstat_waitq_to_runq(KIOSP);
11407c478bd9Sstevel@tonic-gate 		}
11417c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_STRT,
11447c478bd9Sstevel@tonic-gate 		    (CE_CONT, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n",
11457c478bd9Sstevel@tonic-gate 		    (void *)bp, (long)bp->b_blkno, bp->b_bcount));
11467c478bd9Sstevel@tonic-gate 		bp->b_flags &= ~B_ERROR;
11477c478bd9Sstevel@tonic-gate 		bp->b_error = 0;
11487c478bd9Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;	/* init resid */
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 		ASSERT(DRIVE(bp->b_edev) == ddi_get_instance(fjp->fj_dip));
11517c478bd9Sstevel@tonic-gate 		unit = fjp->fj_unit;
11527c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 		bp_mapin(bp);			/* map in buffers */
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 		pp = &fdp->d_part[PARTITION(bp->b_edev)];
11577c478bd9Sstevel@tonic-gate 		/* starting blk adjusted for the partition */
11587c478bd9Sstevel@tonic-gate 		blk = bp->b_blkno + pp->p_start;
11597c478bd9Sstevel@tonic-gate 		ptend = pp->p_start + pp->p_size;   /* end of the partition */
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 		chp = fjp->fj_chars;
11627c478bd9Sstevel@tonic-gate 		secpcyl = chp->fdc_nhead * chp->fdc_secptrack;
11637c478bd9Sstevel@tonic-gate 		switch (chp->fdc_sec_size) {
11647c478bd9Sstevel@tonic-gate 		/* convert logical block numbers to sector numbers */
11657c478bd9Sstevel@tonic-gate 		case 1024:
11667c478bd9Sstevel@tonic-gate 			sctrshft = SCTRSHFT + 1;
11677c478bd9Sstevel@tonic-gate 			blk >>= 1;
11687c478bd9Sstevel@tonic-gate 			ptend >>= 1;
11697c478bd9Sstevel@tonic-gate 			break;
11707c478bd9Sstevel@tonic-gate 		default:
11717c478bd9Sstevel@tonic-gate 		case NBPSCTR:
11727c478bd9Sstevel@tonic-gate 			sctrshft = SCTRSHFT;
11737c478bd9Sstevel@tonic-gate 			break;
11747c478bd9Sstevel@tonic-gate 		case 256:
11757c478bd9Sstevel@tonic-gate 			sctrshft = SCTRSHFT - 1;
11767c478bd9Sstevel@tonic-gate 			blk <<= 1;
11777c478bd9Sstevel@tonic-gate 			ptend <<= 1;
11787c478bd9Sstevel@tonic-gate 			break;
11797c478bd9Sstevel@tonic-gate 		}
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		/*
11827c478bd9Sstevel@tonic-gate 		 * If off the end, limit to actual amount that
11837c478bd9Sstevel@tonic-gate 		 * can be transferred.
11847c478bd9Sstevel@tonic-gate 		 */
11857c478bd9Sstevel@tonic-gate 		if ((blk + (bp->b_bcount >> sctrshft)) > ptend)
11867c478bd9Sstevel@tonic-gate 			/* to end of partition */
11877c478bd9Sstevel@tonic-gate 			len = (ptend - blk) << sctrshft;
11887c478bd9Sstevel@tonic-gate 		else
11897c478bd9Sstevel@tonic-gate 			len = bp->b_bcount;
11907c478bd9Sstevel@tonic-gate 		addr = bp->b_un.b_addr;		/* data buffer address */
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 		/*
11937c478bd9Sstevel@tonic-gate 		 * now we have the real start blk, addr and len for xfer op
11947c478bd9Sstevel@tonic-gate 		 */
11957c478bd9Sstevel@tonic-gate 		while (len != 0) {
11967c478bd9Sstevel@tonic-gate 			/* start cyl of req */
11977c478bd9Sstevel@tonic-gate 			cyl = blk / secpcyl;
11987c478bd9Sstevel@tonic-gate 			bincyl = blk % secpcyl;
11997c478bd9Sstevel@tonic-gate 			/* start head of req */
12007c478bd9Sstevel@tonic-gate 			head = bincyl / chp->fdc_secptrack;
12017c478bd9Sstevel@tonic-gate 			/* start sector of req */
12027c478bd9Sstevel@tonic-gate 			sect = (bincyl % chp->fdc_secptrack) + 1;
12037c478bd9Sstevel@tonic-gate 			/*
12047c478bd9Sstevel@tonic-gate 			 * If the desired block and length will go beyond the
12057c478bd9Sstevel@tonic-gate 			 * cylinder end, then limit it to the cylinder end.
12067c478bd9Sstevel@tonic-gate 			 */
12077c478bd9Sstevel@tonic-gate 			if (bp->b_flags & B_READ) {
12087c478bd9Sstevel@tonic-gate 				if (len > ((secpcyl - bincyl) << sctrshft))
12097c478bd9Sstevel@tonic-gate 					tlen = (secpcyl - bincyl) << sctrshft;
12107c478bd9Sstevel@tonic-gate 				else
12117c478bd9Sstevel@tonic-gate 					tlen = len;
12127c478bd9Sstevel@tonic-gate 			} else {
12137c478bd9Sstevel@tonic-gate 				if (len >
12147c478bd9Sstevel@tonic-gate 				    ((chp->fdc_secptrack - sect + 1) <<
12157c478bd9Sstevel@tonic-gate 				    sctrshft))
12167c478bd9Sstevel@tonic-gate 					tlen =
12177c478bd9Sstevel@tonic-gate 					    (chp->fdc_secptrack - sect + 1) <<
12187c478bd9Sstevel@tonic-gate 					    sctrshft;
12197c478bd9Sstevel@tonic-gate 				else
12207c478bd9Sstevel@tonic-gate 					tlen = len;
12217c478bd9Sstevel@tonic-gate 			}
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L0, FDEM_STRT, (CE_CONT,
12247c478bd9Sstevel@tonic-gate 			    "  blk 0x%x addr 0x%p len 0x%x "
12257c478bd9Sstevel@tonic-gate 			    "cyl %d head %d sec %d\n  resid 0x%lx, tlen %d\n",
12267c478bd9Sstevel@tonic-gate 			    blk, (void *)addr, len, cyl, head, sect,
12277c478bd9Sstevel@tonic-gate 			    bp->b_resid, tlen));
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 			/*
12307c478bd9Sstevel@tonic-gate 			 * (try to) do the operation - failure returns an errno
12317c478bd9Sstevel@tonic-gate 			 */
12327c478bd9Sstevel@tonic-gate 			bp->b_error = fjp->fj_ops->fco_rw(fjp, unit,
12337c478bd9Sstevel@tonic-gate 			    bp->b_flags & B_READ, cyl, head, sect, addr, tlen);
12347c478bd9Sstevel@tonic-gate 			if (bp->b_error != 0) {
12357c478bd9Sstevel@tonic-gate 				FDERRPRINT(FDEP_L3, FDEM_STRT, (CE_WARN,
12367c478bd9Sstevel@tonic-gate 				    "fdstart: bad exec of bp: 0x%p, err=%d",
12377c478bd9Sstevel@tonic-gate 				    (void *)bp, bp->b_error));
12387c478bd9Sstevel@tonic-gate 				bp->b_flags |= B_ERROR;
12397c478bd9Sstevel@tonic-gate 				break;
12407c478bd9Sstevel@tonic-gate 			}
12417c478bd9Sstevel@tonic-gate 			blk += tlen >> sctrshft;
12427c478bd9Sstevel@tonic-gate 			len -= tlen;
12437c478bd9Sstevel@tonic-gate 			addr += tlen;
12447c478bd9Sstevel@tonic-gate 			bp->b_resid -= tlen;
12457c478bd9Sstevel@tonic-gate 		}
12467c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_STRT,
12477c478bd9Sstevel@tonic-gate 		    (CE_CONT, "fdstart done: b_resid %lu, b_count %lu\n",
12487c478bd9Sstevel@tonic-gate 		    bp->b_resid, bp->b_bcount));
12497c478bd9Sstevel@tonic-gate 		if (fdp->d_iostat) {
12507c478bd9Sstevel@tonic-gate 			if (bp->b_flags & B_READ) {
12517c478bd9Sstevel@tonic-gate 				KIOSP->reads++;
12527c478bd9Sstevel@tonic-gate 				KIOSP->nread += (bp->b_bcount - bp->b_resid);
12537c478bd9Sstevel@tonic-gate 			} else {
12547c478bd9Sstevel@tonic-gate 				KIOSP->writes++;
12557c478bd9Sstevel@tonic-gate 				KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
12567c478bd9Sstevel@tonic-gate 			}
12577c478bd9Sstevel@tonic-gate 			kstat_runq_exit(KIOSP);
12587c478bd9Sstevel@tonic-gate 		}
12597c478bd9Sstevel@tonic-gate 		bp_mapout(bp);
12607c478bd9Sstevel@tonic-gate 		biodone(bp);
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
12637c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
12647c478bd9Sstevel@tonic-gate 		fdp->d_current = 0;
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 	fjp->fj_flags ^= FUNIT_BUSY;
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate /* ARGSUSED */
12707c478bd9Sstevel@tonic-gate static int
12717c478bd9Sstevel@tonic-gate fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
12727c478bd9Sstevel@tonic-gate 	int *rval_p)
12737c478bd9Sstevel@tonic-gate {
12747c478bd9Sstevel@tonic-gate 	union {
12757c478bd9Sstevel@tonic-gate 		struct dk_cinfo dki;
12767c478bd9Sstevel@tonic-gate 		struct dk_geom dkg;
12777c478bd9Sstevel@tonic-gate 		struct dk_allmap dka;
12787c478bd9Sstevel@tonic-gate 		struct fd_char fdchar;
12797c478bd9Sstevel@tonic-gate 		struct fd_drive drvchar;
12807c478bd9Sstevel@tonic-gate 		int	temp;
12817c478bd9Sstevel@tonic-gate 	} cpy;
12827c478bd9Sstevel@tonic-gate 	struct vtoc vtoc;
12837c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
12847c478bd9Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
12857c478bd9Sstevel@tonic-gate 	struct dk_map *dmp;
12867c478bd9Sstevel@tonic-gate 	struct dk_label *label;
12877c478bd9Sstevel@tonic-gate 	int nblks, part, unit;
12887c478bd9Sstevel@tonic-gate 	int rval = 0;
12897c478bd9Sstevel@tonic-gate 	enum dkio_state state;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	unit = fd_getdrive(dev, &fjp, &fdp);
12927c478bd9Sstevel@tonic-gate 	if (!fjp || !fdp)
12937c478bd9Sstevel@tonic-gate 		return (ENXIO);
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
12967c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_ioctl fd unit %d: cmd %x, arg %lx\n",
12977c478bd9Sstevel@tonic-gate 	    unit, cmd, arg));
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	switch (cmd) {
13007c478bd9Sstevel@tonic-gate 	case DKIOCINFO:
13017c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_dkinfo(fjp, &cpy.dki);
13027c478bd9Sstevel@tonic-gate 		cpy.dki.dki_cnum = FDCTLR(fjp->fj_unit);
13037c478bd9Sstevel@tonic-gate 		cpy.dki.dki_unit = FDUNIT(fjp->fj_unit);
13047c478bd9Sstevel@tonic-gate 		cpy.dki.dki_partition = PARTITION(dev);
13057c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&cpy.dki, (void *)arg, sizeof (cpy.dki), flag))
13067c478bd9Sstevel@tonic-gate 			rval = EFAULT;
13077c478bd9Sstevel@tonic-gate 		break;
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	case DKIOCG_PHYGEOM:
13107c478bd9Sstevel@tonic-gate 	case DKIOCG_VIRTGEOM:
13117c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
13127c478bd9Sstevel@tonic-gate 		goto get_geom;
13137c478bd9Sstevel@tonic-gate 	case DKIOCGGEOM:
13147c478bd9Sstevel@tonic-gate 		if (fjp->fj_flags & FUNIT_LABELOK)
13157c478bd9Sstevel@tonic-gate 			cpy.dkg.dkg_nsect = (fjp->fj_chars->fdc_secptrack *
13167c478bd9Sstevel@tonic-gate 			    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
13177c478bd9Sstevel@tonic-gate 		else
13187c478bd9Sstevel@tonic-gate 			cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
13197c478bd9Sstevel@tonic-gate get_geom:
13207c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_pcyl = fjp->fj_chars->fdc_ncyl;
13217c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_ncyl = fjp->fj_chars->fdc_ncyl;
13227c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_nhead = fjp->fj_chars->fdc_nhead;
13237c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_intrlv = fjp->fj_attr->fda_intrlv;
13247c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_rpm = fjp->fj_attr->fda_rotatespd;
13257c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_read_reinstruct =
13267c478bd9Sstevel@tonic-gate 		    (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
13277c478bd9Sstevel@tonic-gate 		cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
13287c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&cpy.dkg, (void *)arg, sizeof (cpy.dkg), flag))
13297c478bd9Sstevel@tonic-gate 			rval = EFAULT;
13307c478bd9Sstevel@tonic-gate 		break;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	case DKIOCSGEOM:
13337c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.dkg,
13347c478bd9Sstevel@tonic-gate 		    sizeof (struct dk_geom), flag)) {
13357c478bd9Sstevel@tonic-gate 			rval = EFAULT;
13367c478bd9Sstevel@tonic-gate 			break;
13377c478bd9Sstevel@tonic-gate 		}
13387c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
13397c478bd9Sstevel@tonic-gate 		fjp->fj_chars->fdc_ncyl = cpy.dkg.dkg_ncyl;
13407c478bd9Sstevel@tonic-gate 		fjp->fj_chars->fdc_nhead = cpy.dkg.dkg_nhead;
13417c478bd9Sstevel@tonic-gate 		fjp->fj_chars->fdc_secptrack = cpy.dkg.dkg_nsect;
13427c478bd9Sstevel@tonic-gate 		fjp->fj_attr->fda_intrlv = cpy.dkg.dkg_intrlv;
13437c478bd9Sstevel@tonic-gate 		fjp->fj_attr->fda_rotatespd = cpy.dkg.dkg_rpm;
13447c478bd9Sstevel@tonic-gate 		fdp->d_curfdtype = -1;
13457c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
13467c478bd9Sstevel@tonic-gate 		break;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	/*
13497c478bd9Sstevel@tonic-gate 	 * return the map of all logical partitions
13507c478bd9Sstevel@tonic-gate 	 */
13517c478bd9Sstevel@tonic-gate 	case DKIOCGAPART:
13527c478bd9Sstevel@tonic-gate 		/*
13537c478bd9Sstevel@tonic-gate 		 * Note the conversion from starting sector number
13547c478bd9Sstevel@tonic-gate 		 * to starting cylinder number.
13557c478bd9Sstevel@tonic-gate 		 * Return error if division results in a remainder.
13567c478bd9Sstevel@tonic-gate 		 */
13577c478bd9Sstevel@tonic-gate 		nblks = fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack;
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
13607c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
13617c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
13627c478bd9Sstevel@tonic-gate 		{
13637c478bd9Sstevel@tonic-gate 			struct dk_allmap32 dka32;
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 			for (part = 0; part < NDKMAP; part++) {
13667c478bd9Sstevel@tonic-gate 				if ((fdp->d_part[part].p_start % nblks) != 0)
13677c478bd9Sstevel@tonic-gate 					return (EINVAL);
13687c478bd9Sstevel@tonic-gate 				dka32.dka_map[part].dkl_cylno =
13697c478bd9Sstevel@tonic-gate 				    fdp->d_part[part].p_start / nblks;
13707c478bd9Sstevel@tonic-gate 				dka32.dka_map[part].dkl_nblk =
13717c478bd9Sstevel@tonic-gate 				    fdp->d_part[part].p_size;
13727c478bd9Sstevel@tonic-gate 			}
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&dka32, (void *)arg,
13757c478bd9Sstevel@tonic-gate 			    sizeof (struct dk_allmap32), flag))
13767c478bd9Sstevel@tonic-gate 				rval = EFAULT;
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 			break;
13797c478bd9Sstevel@tonic-gate 		}
13807c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 			dmp = (struct dk_map *)&cpy.dka;
13857c478bd9Sstevel@tonic-gate 			for (part = 0; part < NDKMAP; part++) {
13867c478bd9Sstevel@tonic-gate 				if ((fdp->d_part[part].p_start % nblks) != 0)
13877c478bd9Sstevel@tonic-gate 					return (EINVAL);
13887c478bd9Sstevel@tonic-gate 				dmp->dkl_cylno =
13897c478bd9Sstevel@tonic-gate 				    fdp->d_part[part].p_start / nblks;
13907c478bd9Sstevel@tonic-gate 				dmp->dkl_nblk = fdp->d_part[part].p_size;
13917c478bd9Sstevel@tonic-gate 				dmp++;
13927c478bd9Sstevel@tonic-gate 			}
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&cpy.dka, (void *)arg,
13957c478bd9Sstevel@tonic-gate 			    sizeof (struct dk_allmap), flag))
13967c478bd9Sstevel@tonic-gate 				rval = EFAULT;
13977c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
13987c478bd9Sstevel@tonic-gate 			break;
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 		}
14017c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 		break;
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 	/*
14067c478bd9Sstevel@tonic-gate 	 * Set the map of all logical partitions
14077c478bd9Sstevel@tonic-gate 	 */
14087c478bd9Sstevel@tonic-gate 	case DKIOCSAPART:
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
14117c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
14127c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
14137c478bd9Sstevel@tonic-gate 		{
14147c478bd9Sstevel@tonic-gate 			struct dk_allmap32 dka32;
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &dka32,
14177c478bd9Sstevel@tonic-gate 			    sizeof (dka32), flag)) {
14187c478bd9Sstevel@tonic-gate 				rval = EFAULT;
14197c478bd9Sstevel@tonic-gate 				break;
14207c478bd9Sstevel@tonic-gate 			}
14217c478bd9Sstevel@tonic-gate 			for (part = 0; part < NDKMAP; part++) {
14227c478bd9Sstevel@tonic-gate 				cpy.dka.dka_map[part].dkl_cylno =
14237c478bd9Sstevel@tonic-gate 				    dka32.dka_map[part].dkl_cylno;
14247c478bd9Sstevel@tonic-gate 				cpy.dka.dka_map[part].dkl_nblk =
14257c478bd9Sstevel@tonic-gate 				    dka32.dka_map[part].dkl_nblk;
14267c478bd9Sstevel@tonic-gate 			}
14277c478bd9Sstevel@tonic-gate 			break;
14287c478bd9Sstevel@tonic-gate 		}
14297c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14327c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.dka, sizeof (cpy.dka), flag))
14337c478bd9Sstevel@tonic-gate 			rval = EFAULT;
14347c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 			break;
14377c478bd9Sstevel@tonic-gate 		}
14387c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 		if (rval != 0)
14417c478bd9Sstevel@tonic-gate 			break;
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 		dmp = (struct dk_map *)&cpy.dka;
14447c478bd9Sstevel@tonic-gate 		nblks = fjp->fj_chars->fdc_nhead *
14457c478bd9Sstevel@tonic-gate 		    fjp->fj_chars->fdc_secptrack;
14467c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
14477c478bd9Sstevel@tonic-gate 		/*
14487c478bd9Sstevel@tonic-gate 		 * Note the conversion from starting cylinder number
14497c478bd9Sstevel@tonic-gate 		 * to starting sector number.
14507c478bd9Sstevel@tonic-gate 		 */
14517c478bd9Sstevel@tonic-gate 		for (part = 0; part < NDKMAP; part++) {
14527c478bd9Sstevel@tonic-gate 			fdp->d_part[part].p_start = dmp->dkl_cylno *
14537c478bd9Sstevel@tonic-gate 			    nblks;
14547c478bd9Sstevel@tonic-gate 			fdp->d_part[part].p_size = dmp->dkl_nblk;
14557c478bd9Sstevel@tonic-gate 			dmp++;
14567c478bd9Sstevel@tonic-gate 		}
14577c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 		break;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	case DKIOCGVTOC:
14627c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 		/*
14657c478bd9Sstevel@tonic-gate 		 * Exit if the diskette has no label.
14667c478bd9Sstevel@tonic-gate 		 * Also, get the label to make sure the correct one is
14677c478bd9Sstevel@tonic-gate 		 * being used since the diskette may have changed
14687c478bd9Sstevel@tonic-gate 		 */
14697c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
14707c478bd9Sstevel@tonic-gate 		rval = fdgetlabel(fjp, unit);
14717c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
14727c478bd9Sstevel@tonic-gate 		if (rval) {
14737c478bd9Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
14747c478bd9Sstevel@tonic-gate 			rval = EINVAL;
14757c478bd9Sstevel@tonic-gate 			break;
14767c478bd9Sstevel@tonic-gate 		}
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 		fd_build_user_vtoc(fjp, fdp, &vtoc);
14797c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
14827c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
14837c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
14847c478bd9Sstevel@tonic-gate 		{
14857c478bd9Sstevel@tonic-gate 			struct vtoc32	vtoc32;
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 			vtoctovtoc32(vtoc, vtoc32);
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&vtoc32, (void *)arg,
14907c478bd9Sstevel@tonic-gate 			    sizeof (vtoc32), flag))
14917c478bd9Sstevel@tonic-gate 				rval = EFAULT;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 			break;
14947c478bd9Sstevel@tonic-gate 		}
14957c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14987c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&vtoc, (void *)arg,
14997c478bd9Sstevel@tonic-gate 			    sizeof (vtoc), flag))
15007c478bd9Sstevel@tonic-gate 				rval = EFAULT;
15017c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15027c478bd9Sstevel@tonic-gate 			break;
15037c478bd9Sstevel@tonic-gate 		}
15047c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 		break;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	case DKIOCSVTOC:
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15117c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
15127c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
15137c478bd9Sstevel@tonic-gate 		{
15147c478bd9Sstevel@tonic-gate 			struct vtoc32	vtoc32;
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &vtoc32,
15177c478bd9Sstevel@tonic-gate 			    sizeof (vtoc32), flag)) {
15187c478bd9Sstevel@tonic-gate 				rval = EFAULT;
15197c478bd9Sstevel@tonic-gate 				break;
15207c478bd9Sstevel@tonic-gate 			}
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 			vtoc32tovtoc(vtoc32, vtoc);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 			break;
15257c478bd9Sstevel@tonic-gate 		}
15267c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
15297c478bd9Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &vtoc, sizeof (vtoc), flag))
15307c478bd9Sstevel@tonic-gate 				rval = EFAULT;
15317c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15327c478bd9Sstevel@tonic-gate 			break;
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 		if (rval != 0)
15377c478bd9Sstevel@tonic-gate 			break;
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 		label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 		if ((rval = fd_build_label_vtoc(fjp, fdp, &vtoc, label)) == 0) {
15457c478bd9Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 1);
15467c478bd9Sstevel@tonic-gate 			rval = fjp->fj_ops->fco_rw(fjp, unit, FDWRITE,
15477c478bd9Sstevel@tonic-gate 			    0, 0, 1, (caddr_t)label, sizeof (struct dk_label));
15487c478bd9Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
15497c478bd9Sstevel@tonic-gate 		}
15507c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
15517c478bd9Sstevel@tonic-gate 		kmem_free(label, sizeof (struct dk_label));
15527c478bd9Sstevel@tonic-gate 		break;
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	case DKIOCSTATE:
15557c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_IOCT,
15567c478bd9Sstevel@tonic-gate 		    (CE_CONT, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit));
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) {
15597c478bd9Sstevel@tonic-gate 			rval = EFAULT;
15607c478bd9Sstevel@tonic-gate 			break;
15617c478bd9Sstevel@tonic-gate 		}
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 		rval = fd_check_media(dev, state);
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&fdp->d_media_state, (void *)arg,
15667c478bd9Sstevel@tonic-gate 		    sizeof (int), flag))
15677c478bd9Sstevel@tonic-gate 			rval = EFAULT;
15687c478bd9Sstevel@tonic-gate 		break;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	case FDIOGCHAR:
15717c478bd9Sstevel@tonic-gate 		if (ddi_copyout(fjp->fj_chars, (void *)arg,
15727c478bd9Sstevel@tonic-gate 		    sizeof (struct fd_char), flag))
15737c478bd9Sstevel@tonic-gate 			rval = EFAULT;
15747c478bd9Sstevel@tonic-gate 		break;
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	case FDIOSCHAR:
15777c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.fdchar,
15787c478bd9Sstevel@tonic-gate 		    sizeof (struct fd_char), flag)) {
15797c478bd9Sstevel@tonic-gate 			rval = EFAULT;
15807c478bd9Sstevel@tonic-gate 			break;
15817c478bd9Sstevel@tonic-gate 		}
15827c478bd9Sstevel@tonic-gate 		switch (cpy.fdchar.fdc_transfer_rate) {
15837c478bd9Sstevel@tonic-gate 		case 417:
15847c478bd9Sstevel@tonic-gate 			if ((fdp->d_media & (1 << FMT_3M)) == 0) {
15857c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
15867c478bd9Sstevel@tonic-gate 				    "fdioschar:Medium density not supported\n");
15877c478bd9Sstevel@tonic-gate 				rval = EINVAL;
15887c478bd9Sstevel@tonic-gate 				break;
15897c478bd9Sstevel@tonic-gate 			}
15907c478bd9Sstevel@tonic-gate 			mutex_enter(&fjp->fj_lock);
15917c478bd9Sstevel@tonic-gate 			fjp->fj_attr->fda_rotatespd = 360;
15927c478bd9Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
15937c478bd9Sstevel@tonic-gate 			/* cpy.fdchar.fdc_transfer_rate = 500; */
15947c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
15957c478bd9Sstevel@tonic-gate 		case 1000:
15967c478bd9Sstevel@tonic-gate 		case 500:
15977c478bd9Sstevel@tonic-gate 		case 300:
15987c478bd9Sstevel@tonic-gate 		case 250:
15997c478bd9Sstevel@tonic-gate 			mutex_enter(&fjp->fj_lock);
16007c478bd9Sstevel@tonic-gate 			*(fjp->fj_chars) = cpy.fdchar;
16017c478bd9Sstevel@tonic-gate 			fdp->d_curfdtype = -1;
16027c478bd9Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHAROK;
16037c478bd9Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 			break;
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 		default:
16087c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L4, FDEM_IOCT,
16097c478bd9Sstevel@tonic-gate 			    (CE_WARN, "fd_ioctl fd unit %d: FDIOSCHAR odd "
16107c478bd9Sstevel@tonic-gate 			    "xfer rate %dkbs",
16117c478bd9Sstevel@tonic-gate 			    unit, cpy.fdchar.fdc_transfer_rate));
16127c478bd9Sstevel@tonic-gate 			rval = EINVAL;
16137c478bd9Sstevel@tonic-gate 			break;
16147c478bd9Sstevel@tonic-gate 		}
16157c478bd9Sstevel@tonic-gate 		break;
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	/*
16187c478bd9Sstevel@tonic-gate 	 * set all characteristics and geometry to the defaults
16197c478bd9Sstevel@tonic-gate 	 */
16207c478bd9Sstevel@tonic-gate 	case FDDEFGEOCHAR:
16217c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
16227c478bd9Sstevel@tonic-gate 		fdp->d_curfdtype = fdp->d_deffdtype;
16237c478bd9Sstevel@tonic-gate 		*fjp->fj_chars = *defchar[fdp->d_curfdtype];
16247c478bd9Sstevel@tonic-gate 		*fjp->fj_attr = fdtypes[fdp->d_curfdtype];
16257c478bd9Sstevel@tonic-gate 		bcopy(fdparts[fdp->d_curfdtype],
16267c478bd9Sstevel@tonic-gate 		    fdp->d_part, sizeof (struct partition) * NDKMAP);
16277c478bd9Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHAROK;
16287c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
16297c478bd9Sstevel@tonic-gate 		break;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	case FDEJECT:  /* eject disk */
16327c478bd9Sstevel@tonic-gate 	case DKIOCEJECT:
16337c478bd9Sstevel@tonic-gate 		fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
16347c478bd9Sstevel@tonic-gate 		rval = ENOSYS;
16357c478bd9Sstevel@tonic-gate 		break;
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	case FDGETCHANGE: /* disk changed */
16387c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.temp, sizeof (int), flag)) {
16397c478bd9Sstevel@tonic-gate 			rval = EFAULT;
16407c478bd9Sstevel@tonic-gate 			break;
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
16437c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 		if (fjp->fj_flags & FUNIT_CHANGED)
16467c478bd9Sstevel@tonic-gate 			cpy.temp |= FDGC_HISTORY;
16477c478bd9Sstevel@tonic-gate 		else
16487c478bd9Sstevel@tonic-gate 			cpy.temp &= ~FDGC_HISTORY;
16497c478bd9Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHANGED;
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 		if (fjp->fj_ops->fco_getchng(fjp, unit)) {
16527c478bd9Sstevel@tonic-gate 			cpy.temp |= FDGC_DETECTED;
16537c478bd9Sstevel@tonic-gate 			fjp->fj_ops->fco_resetchng(fjp, unit);
16547c478bd9Sstevel@tonic-gate 			/*
16557c478bd9Sstevel@tonic-gate 			 * check diskette again only if it was removed
16567c478bd9Sstevel@tonic-gate 			 */
16577c478bd9Sstevel@tonic-gate 			if (fjp->fj_ops->fco_getchng(fjp, unit)) {
16587c478bd9Sstevel@tonic-gate 				/*
16597c478bd9Sstevel@tonic-gate 				 * no diskette is present
16607c478bd9Sstevel@tonic-gate 				 */
16617c478bd9Sstevel@tonic-gate 				cpy.temp |= FDGC_CURRENT;
16627c478bd9Sstevel@tonic-gate 				if (fjp->fj_flags & FUNIT_CHGDET)
16637c478bd9Sstevel@tonic-gate 					/*
16647c478bd9Sstevel@tonic-gate 					 * again no diskette; not a new change
16657c478bd9Sstevel@tonic-gate 					 */
16667c478bd9Sstevel@tonic-gate 					cpy.temp ^= FDGC_DETECTED;
16677c478bd9Sstevel@tonic-gate 				else
16687c478bd9Sstevel@tonic-gate 					fjp->fj_flags |= FUNIT_CHGDET;
16697c478bd9Sstevel@tonic-gate 			} else {
16707c478bd9Sstevel@tonic-gate 				/*
16717c478bd9Sstevel@tonic-gate 				 * a new diskette is present
16727c478bd9Sstevel@tonic-gate 				 */
16737c478bd9Sstevel@tonic-gate 				cpy.temp &= ~FDGC_CURRENT;
16747c478bd9Sstevel@tonic-gate 				fjp->fj_flags &= ~FUNIT_CHGDET;
16757c478bd9Sstevel@tonic-gate 			}
16767c478bd9Sstevel@tonic-gate 		} else {
16777c478bd9Sstevel@tonic-gate 			cpy.temp &= ~(FDGC_DETECTED | FDGC_CURRENT);
16787c478bd9Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHGDET;
16797c478bd9Sstevel@tonic-gate 		}
16807c478bd9Sstevel@tonic-gate 		/*
16817c478bd9Sstevel@tonic-gate 		 * also get state of write protection
16827c478bd9Sstevel@tonic-gate 		 */
16837c478bd9Sstevel@tonic-gate 		if (fjp->fj_flags & FUNIT_WPROT) {
16847c478bd9Sstevel@tonic-gate 			cpy.temp |= FDGC_CURWPROT;
16857c478bd9Sstevel@tonic-gate 		} else {
16867c478bd9Sstevel@tonic-gate 			cpy.temp &= ~FDGC_CURWPROT;
16877c478bd9Sstevel@tonic-gate 		}
16887c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
16897c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&cpy.temp, (void *)arg, sizeof (int), flag))
16927c478bd9Sstevel@tonic-gate 			rval = EFAULT;
16937c478bd9Sstevel@tonic-gate 		break;
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	case FDGETDRIVECHAR:
16967c478bd9Sstevel@tonic-gate 		if (ddi_copyout(fjp->fj_drive, (void *)arg,
16977c478bd9Sstevel@tonic-gate 		    sizeof (struct fd_drive), flag))
16987c478bd9Sstevel@tonic-gate 			rval = EFAULT;
16997c478bd9Sstevel@tonic-gate 		break;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	case FDSETDRIVECHAR:
17027c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.drvchar,
17037c478bd9Sstevel@tonic-gate 		    sizeof (struct fd_drive), flag)) {
17047c478bd9Sstevel@tonic-gate 			rval = EFAULT;
17057c478bd9Sstevel@tonic-gate 			break;
17067c478bd9Sstevel@tonic-gate 		}
17077c478bd9Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
17087c478bd9Sstevel@tonic-gate 		*(fjp->fj_drive) = cpy.drvchar;
17097c478bd9Sstevel@tonic-gate 		fdp->d_curfdtype = -1;
17107c478bd9Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHAROK;
17117c478bd9Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
17127c478bd9Sstevel@tonic-gate 		break;
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	case DKIOCREMOVABLE: {
17157c478bd9Sstevel@tonic-gate 		int	i = 1;
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 		/* no brainer: floppies are always removable */
17187c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&i, (void *)arg, sizeof (int), flag)) {
17197c478bd9Sstevel@tonic-gate 			rval = EFAULT;
17207c478bd9Sstevel@tonic-gate 		}
17217c478bd9Sstevel@tonic-gate 		break;
17227c478bd9Sstevel@tonic-gate 	}
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	case DKIOCGMEDIAINFO:
17257c478bd9Sstevel@tonic-gate 		rval = fd_get_media_info(fjp, (caddr_t)arg, flag);
17267c478bd9Sstevel@tonic-gate 		break;
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	case FDIOCMD:
17297c478bd9Sstevel@tonic-gate 	{
17307c478bd9Sstevel@tonic-gate 		struct fd_cmd fc;
17317c478bd9Sstevel@tonic-gate 		int cyl, head, spc, spt;
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
17347c478bd9Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
17357c478bd9Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
17367c478bd9Sstevel@tonic-gate 		{
17377c478bd9Sstevel@tonic-gate 			struct fd_cmd32 fc32;
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &fc32,
17407c478bd9Sstevel@tonic-gate 			    sizeof (fc32), flag)) {
17417c478bd9Sstevel@tonic-gate 				rval = EFAULT;
17427c478bd9Sstevel@tonic-gate 				break;
17437c478bd9Sstevel@tonic-gate 			}
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 			fc.fdc_cmd = fc32.fdc_cmd;
17467c478bd9Sstevel@tonic-gate 			fc.fdc_flags = fc32.fdc_flags;
17477c478bd9Sstevel@tonic-gate 			fc.fdc_blkno = fc32.fdc_blkno;
17487c478bd9Sstevel@tonic-gate 			fc.fdc_secnt = fc32.fdc_secnt;
17497c478bd9Sstevel@tonic-gate 			fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
17507c478bd9Sstevel@tonic-gate 			fc.fdc_buflen = fc32.fdc_buflen;
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 			break;
17537c478bd9Sstevel@tonic-gate 		}
17547c478bd9Sstevel@tonic-gate 		case DDI_MODEL_NONE:
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &fc, sizeof (fc), flag)) {
17597c478bd9Sstevel@tonic-gate 				rval = EFAULT;
17607c478bd9Sstevel@tonic-gate 				break;
17617c478bd9Sstevel@tonic-gate 			}
17627c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
17637c478bd9Sstevel@tonic-gate 			break;
17647c478bd9Sstevel@tonic-gate 		}
17657c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 		if (rval != 0)
17687c478bd9Sstevel@tonic-gate 			break;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
17717c478bd9Sstevel@tonic-gate 			auto struct iovec aiov;
17727c478bd9Sstevel@tonic-gate 			auto struct uio auio;
17737c478bd9Sstevel@tonic-gate 			struct uio *uio = &auio;
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 			spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 			bzero(&auio, sizeof (struct uio));
17787c478bd9Sstevel@tonic-gate 			bzero(&aiov, sizeof (struct iovec));
17797c478bd9Sstevel@tonic-gate 			aiov.iov_base = fc.fdc_bufaddr;
17807c478bd9Sstevel@tonic-gate 			aiov.iov_len = (uint_t)fc.fdc_secnt *
17817c478bd9Sstevel@tonic-gate 			    fjp->fj_chars->fdc_sec_size;
17827c478bd9Sstevel@tonic-gate 			uio->uio_iov = &aiov;
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 			uio->uio_iovcnt = 1;
17857c478bd9Sstevel@tonic-gate 			uio->uio_resid = aiov.iov_len;
17867c478bd9Sstevel@tonic-gate 			uio->uio_segflg = UIO_USERSPACE;
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 			rval = physio(fd_strategy, (struct buf *)0, dev,
17897c478bd9Sstevel@tonic-gate 			    spc, minphys, uio);
17907c478bd9Sstevel@tonic-gate 			break;
17917c478bd9Sstevel@tonic-gate 		} else if (fc.fdc_cmd == FDCMD_FORMAT_TRACK) {
17927c478bd9Sstevel@tonic-gate 			spt = fjp->fj_chars->fdc_secptrack;	/* sec/trk */
17937c478bd9Sstevel@tonic-gate 			spc = fjp->fj_chars->fdc_nhead * spt;	/* sec/cyl */
17947c478bd9Sstevel@tonic-gate 			cyl = fc.fdc_blkno / spc;
17957c478bd9Sstevel@tonic-gate 			head = (fc.fdc_blkno % spc) / spt;
17967c478bd9Sstevel@tonic-gate 			if ((cyl | head) == 0)
17977c478bd9Sstevel@tonic-gate 				fjp->fj_flags &=
17987c478bd9Sstevel@tonic-gate 				    ~(FUNIT_LABELOK | FUNIT_UNLABELED);
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 			FDERRPRINT(FDEP_L0, FDEM_FORM,
18017c478bd9Sstevel@tonic-gate 			    (CE_CONT, "fd_format cyl %d, hd %d\n", cyl, head));
18027c478bd9Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 1);
18037c478bd9Sstevel@tonic-gate 			rval = fjp->fj_ops->fco_format(fjp, unit, cyl, head,
18047c478bd9Sstevel@tonic-gate 			    (int)fc.fdc_flags);
18057c478bd9Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 			break;
18087c478bd9Sstevel@tonic-gate 		}
18097c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L4, FDEM_IOCT,
18107c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete",
18117c478bd9Sstevel@tonic-gate 		    unit));
18127c478bd9Sstevel@tonic-gate 		rval = EINVAL;
18137c478bd9Sstevel@tonic-gate 		break;
18147c478bd9Sstevel@tonic-gate 	}
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	case FDRAW:
18177c478bd9Sstevel@tonic-gate 		rval = fd_rawioctl(fjp, unit, (caddr_t)arg, flag);
18187c478bd9Sstevel@tonic-gate 		break;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	default:
18217c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L4, FDEM_IOCT,
18227c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd_ioctl fd unit %d: invalid ioctl 0x%x",
18237c478bd9Sstevel@tonic-gate 		    unit, cmd));
18247c478bd9Sstevel@tonic-gate 		rval = ENOTTY;
18257c478bd9Sstevel@tonic-gate 		break;
18267c478bd9Sstevel@tonic-gate 	}
18277c478bd9Sstevel@tonic-gate 	return (rval);
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate static void
18317c478bd9Sstevel@tonic-gate fd_build_user_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	struct partition *vpart;
18347c478bd9Sstevel@tonic-gate 	int	i;
18357c478bd9Sstevel@tonic-gate 	int	xblk;
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	/*
18387c478bd9Sstevel@tonic-gate 	 * Return vtoc structure fields in the provided VTOC area, addressed
18397c478bd9Sstevel@tonic-gate 	 * by *vtocp.
18407c478bd9Sstevel@tonic-gate 	 *
18417c478bd9Sstevel@tonic-gate 	 */
18427c478bd9Sstevel@tonic-gate 	bzero(vtocp, sizeof (struct vtoc));
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_bootinfo,
18457c478bd9Sstevel@tonic-gate 	    vtocp->v_bootinfo, sizeof (vtocp->v_bootinfo));
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	vtocp->v_sanity = VTOC_SANE;
18487c478bd9Sstevel@tonic-gate 	vtocp->v_version = fdp->d_vtoc_version;
18497c478bd9Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_volume, vtocp->v_volume, LEN_DKL_VVOL);
18507c478bd9Sstevel@tonic-gate 	if (fjp->fj_flags & FUNIT_LABELOK) {
18517c478bd9Sstevel@tonic-gate 		vtocp->v_sectorsz = DEV_BSIZE;
18527c478bd9Sstevel@tonic-gate 		xblk = 1;
18537c478bd9Sstevel@tonic-gate 	} else {
18547c478bd9Sstevel@tonic-gate 		vtocp->v_sectorsz = fjp->fj_chars->fdc_sec_size;
18557c478bd9Sstevel@tonic-gate 		xblk = vtocp->v_sectorsz / DEV_BSIZE;
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 	vtocp->v_nparts = 3;	/* <= NDKMAP;	*/
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	/*
18607c478bd9Sstevel@tonic-gate 	 * Copy partitioning information.
18617c478bd9Sstevel@tonic-gate 	 */
18627c478bd9Sstevel@tonic-gate 	bcopy(fdp->d_part, vtocp->v_part, sizeof (struct partition) * NDKMAP);
18637c478bd9Sstevel@tonic-gate 	for (i = NDKMAP, vpart = vtocp->v_part; i && (xblk > 1); i--, vpart++) {
18647c478bd9Sstevel@tonic-gate 		/* correct partition info if sector size > 512 bytes */
18657c478bd9Sstevel@tonic-gate 		vpart->p_start /= xblk;
18667c478bd9Sstevel@tonic-gate 		vpart->p_size /= xblk;
18677c478bd9Sstevel@tonic-gate 	}
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_timestamp,
18707c478bd9Sstevel@tonic-gate 	    vtocp->timestamp, sizeof (fdp->d_vtoc_timestamp));
18717c478bd9Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_asciilabel, vtocp->v_asciilabel, LEN_DKL_ASCII);
18727c478bd9Sstevel@tonic-gate }
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate static int
18767c478bd9Sstevel@tonic-gate fd_build_label_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp,
18777c478bd9Sstevel@tonic-gate     struct dk_label *labelp)
18787c478bd9Sstevel@tonic-gate {
18797c478bd9Sstevel@tonic-gate 	struct partition *vpart;
18807c478bd9Sstevel@tonic-gate 	int	i;
18817c478bd9Sstevel@tonic-gate 	int	nblks;
18827c478bd9Sstevel@tonic-gate 	int	ncyl;
18837c478bd9Sstevel@tonic-gate 	ushort_t sum, *sp;
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	/*
18877c478bd9Sstevel@tonic-gate 	 * Sanity-check the vtoc
18887c478bd9Sstevel@tonic-gate 	 */
18897c478bd9Sstevel@tonic-gate 	if (vtocp->v_sanity != VTOC_SANE ||
18907c478bd9Sstevel@tonic-gate 	    vtocp->v_nparts > NDKMAP || vtocp->v_nparts <= 0) {
18917c478bd9Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
18927c478bd9Sstevel@tonic-gate 		    (CE_WARN, "fd_build_label:  sanity check on vtoc failed"));
18937c478bd9Sstevel@tonic-gate 		return (EINVAL);
18947c478bd9Sstevel@tonic-gate 	}
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 	/*
18977c478bd9Sstevel@tonic-gate 	 * before copying the vtoc, the partition information in it should be
18987c478bd9Sstevel@tonic-gate 	 * checked against the information the driver already has on the
18997c478bd9Sstevel@tonic-gate 	 * diskette.
19007c478bd9Sstevel@tonic-gate 	 */
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 	nblks = (fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack *
19037c478bd9Sstevel@tonic-gate 	    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
19047c478bd9Sstevel@tonic-gate 	if (nblks == 0 || fjp->fj_chars->fdc_ncyl == 0)
19057c478bd9Sstevel@tonic-gate 		return (EFAULT);
19067c478bd9Sstevel@tonic-gate 	vpart = vtocp->v_part;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	/*
19097c478bd9Sstevel@tonic-gate 	 * Check the partition information in the vtoc.  The starting sectors
19107c478bd9Sstevel@tonic-gate 	 * must lie along cylinder boundaries. (NDKMAP entries are checked
19117c478bd9Sstevel@tonic-gate 	 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
19127c478bd9Sstevel@tonic-gate 	 * is less than NDKMAP)
19137c478bd9Sstevel@tonic-gate 	 */
19147c478bd9Sstevel@tonic-gate 	for (i = NDKMAP; i; i--) {
19157c478bd9Sstevel@tonic-gate 		if ((vpart->p_start % nblks) != 0) {
19167c478bd9Sstevel@tonic-gate 			return (EINVAL);
19177c478bd9Sstevel@tonic-gate 		}
19187c478bd9Sstevel@tonic-gate 		ncyl = vpart->p_start / nblks;
19197c478bd9Sstevel@tonic-gate 		ncyl += vpart->p_size / nblks;
19207c478bd9Sstevel@tonic-gate 		if ((vpart->p_size % nblks) != 0)
19217c478bd9Sstevel@tonic-gate 			ncyl++;
19227c478bd9Sstevel@tonic-gate 		if (ncyl > (long)fjp->fj_chars->fdc_ncyl) {
19237c478bd9Sstevel@tonic-gate 			return (EINVAL);
19247c478bd9Sstevel@tonic-gate 		}
19257c478bd9Sstevel@tonic-gate 		vpart++;
19267c478bd9Sstevel@tonic-gate 	}
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	bcopy(vtocp->v_bootinfo, fdp->d_vtoc_bootinfo,
19307c478bd9Sstevel@tonic-gate 	    sizeof (vtocp->v_bootinfo));
19317c478bd9Sstevel@tonic-gate 	fdp->d_vtoc_version = vtocp->v_version;
19327c478bd9Sstevel@tonic-gate 	bcopy(vtocp->v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	/*
19357c478bd9Sstevel@tonic-gate 	 * Copy partitioning information.
19367c478bd9Sstevel@tonic-gate 	 */
19377c478bd9Sstevel@tonic-gate 	bcopy(vtocp->v_part, fdp->d_part, sizeof (struct partition) * NDKMAP);
19387c478bd9Sstevel@tonic-gate 	bcopy(vtocp->timestamp, fdp->d_vtoc_timestamp,
19397c478bd9Sstevel@tonic-gate 	    sizeof (fdp->d_vtoc_timestamp));
19407c478bd9Sstevel@tonic-gate 	bcopy(vtocp->v_asciilabel, fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	/*
19437c478bd9Sstevel@tonic-gate 	 * construct the diskette label in supplied buffer
19447c478bd9Sstevel@tonic-gate 	 */
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	/* Put appropriate vtoc structure fields into the disk label */
19477c478bd9Sstevel@tonic-gate 	labelp->dkl_vtoc.v_bootinfo[0] = (uint32_t)vtocp->v_bootinfo[0];
19487c478bd9Sstevel@tonic-gate 	labelp->dkl_vtoc.v_bootinfo[1] = (uint32_t)vtocp->v_bootinfo[1];
19497c478bd9Sstevel@tonic-gate 	labelp->dkl_vtoc.v_bootinfo[2] = (uint32_t)vtocp->v_bootinfo[2];
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	labelp->dkl_vtoc.v_sanity = vtocp->v_sanity;
19527c478bd9Sstevel@tonic-gate 	labelp->dkl_vtoc.v_version = vtocp->v_version;
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	bcopy(vtocp->v_volume, labelp->dkl_vtoc.v_volume, LEN_DKL_VVOL);
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	labelp->dkl_vtoc.v_nparts = vtocp->v_nparts;
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	bcopy(vtocp->v_reserved, labelp->dkl_vtoc.v_reserved,
19597c478bd9Sstevel@tonic-gate 	    sizeof (labelp->dkl_vtoc.v_reserved));
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	for (i = 0; i < (int)vtocp->v_nparts; i++) {
19627c478bd9Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_tag  = vtocp->v_part[i].p_tag;
19637c478bd9Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_flag  = vtocp->v_part[i].p_flag;
19647c478bd9Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_start  = vtocp->v_part[i].p_start;
19657c478bd9Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_size  = vtocp->v_part[i].p_size;
19667c478bd9Sstevel@tonic-gate 	}
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
19697c478bd9Sstevel@tonic-gate 		labelp->dkl_vtoc.v_timestamp[i] = vtocp->timestamp[i];
19707c478bd9Sstevel@tonic-gate 	}
19717c478bd9Sstevel@tonic-gate 	bcopy(vtocp->v_asciilabel, labelp->dkl_asciilabel, LEN_DKL_ASCII);
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	labelp->dkl_pcyl = fjp->fj_chars->fdc_ncyl;
19757c478bd9Sstevel@tonic-gate 	labelp->dkl_ncyl = fjp->fj_chars->fdc_ncyl;
19767c478bd9Sstevel@tonic-gate 	labelp->dkl_nhead = fjp->fj_chars->fdc_nhead;
19777c478bd9Sstevel@tonic-gate 	/*
19787c478bd9Sstevel@tonic-gate 	 * The fdc_secptrack field of the fd_char structure is the number
19797c478bd9Sstevel@tonic-gate 	 * of sectors per track where the sectors are fdc_sec_size.
19807c478bd9Sstevel@tonic-gate 	 * The dkl_nsect field of the dk_label structure is the number of
19817c478bd9Sstevel@tonic-gate 	 * DEV_BSIZE (512) byte sectors per track.
19827c478bd9Sstevel@tonic-gate 	 */
19837c478bd9Sstevel@tonic-gate 	labelp->dkl_nsect = (fjp->fj_chars->fdc_secptrack *
19847c478bd9Sstevel@tonic-gate 	    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
19857c478bd9Sstevel@tonic-gate 	labelp->dkl_intrlv = fjp->fj_attr->fda_intrlv;
19867c478bd9Sstevel@tonic-gate 	labelp->dkl_rpm = fjp->fj_attr->fda_rotatespd;
19877c478bd9Sstevel@tonic-gate 	labelp->dkl_read_reinstruct =
19887c478bd9Sstevel@tonic-gate 	    (int)(labelp->dkl_nsect * labelp->dkl_rpm * 4) / 60000;
19897c478bd9Sstevel@tonic-gate 	labelp->dkl_write_reinstruct = labelp->dkl_read_reinstruct;
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate 	labelp->dkl_magic = DKL_MAGIC;
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	sum = 0;
19947c478bd9Sstevel@tonic-gate 	labelp->dkl_cksum = 0;
19957c478bd9Sstevel@tonic-gate 	sp = (ushort_t *)labelp;
19967c478bd9Sstevel@tonic-gate 	while (sp < &(labelp->dkl_cksum)) {
19977c478bd9Sstevel@tonic-gate 		sum ^= *sp++;
19987c478bd9Sstevel@tonic-gate 	}
19997c478bd9Sstevel@tonic-gate 	labelp->dkl_cksum = sum;
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	return (0);
20027c478bd9Sstevel@tonic-gate }
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate static int
20057c478bd9Sstevel@tonic-gate fd_rawioctl(struct fcu_obj *fjp, int unit, caddr_t arg, int mode)
20067c478bd9Sstevel@tonic-gate {
20077c478bd9Sstevel@tonic-gate 	struct fd_raw fdr;
20087c478bd9Sstevel@tonic-gate 	char *arg_result = NULL;
20097c478bd9Sstevel@tonic-gate 	int flag = B_READ;
20107c478bd9Sstevel@tonic-gate 	int rval = 0;
20117c478bd9Sstevel@tonic-gate 	caddr_t	uaddr;
20127c478bd9Sstevel@tonic-gate 	uint_t ucount;
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
20157c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_rawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	if (fjp->fj_chars->fdc_medium != 3 && fjp->fj_chars->fdc_medium != 5) {
20187c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "fd_rawioctl: Medium density not supported\n");
20197c478bd9Sstevel@tonic-gate 		return (ENXIO);
20207c478bd9Sstevel@tonic-gate 	}
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20237c478bd9Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode & FMODELS)) {
20247c478bd9Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
20257c478bd9Sstevel@tonic-gate 	{
20267c478bd9Sstevel@tonic-gate 		struct fd_raw32 fdr32;
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 		if (ddi_copyin(arg, &fdr32, sizeof (fdr32), mode))
20297c478bd9Sstevel@tonic-gate 			return (EFAULT);
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate 		bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
20327c478bd9Sstevel@tonic-gate 		fdr.fdr_cnum = fdr32.fdr_cnum;
20337c478bd9Sstevel@tonic-gate 		fdr.fdr_nbytes = fdr32.fdr_nbytes;
20347c478bd9Sstevel@tonic-gate 		fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
20357c478bd9Sstevel@tonic-gate 		arg_result = ((struct fd_raw32 *)arg)->fdr_result;
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 		break;
20387c478bd9Sstevel@tonic-gate 	}
20397c478bd9Sstevel@tonic-gate 	case DDI_MODEL_NONE:
20407c478bd9Sstevel@tonic-gate #endif /* ! _MULTI_DATAMODEL */
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 		if (ddi_copyin(arg, &fdr, sizeof (fdr), mode))
20437c478bd9Sstevel@tonic-gate 			return (EFAULT);
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 		arg_result = ((struct fd_raw *)arg)->fdr_result;
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20487c478bd9Sstevel@tonic-gate 		break;
20497c478bd9Sstevel@tonic-gate 	}
20507c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 	/*
20557c478bd9Sstevel@tonic-gate 	 * copy user address & nbytes from raw_req so that we can
20567c478bd9Sstevel@tonic-gate 	 * put kernel address in req structure
20577c478bd9Sstevel@tonic-gate 	 */
20587c478bd9Sstevel@tonic-gate 	uaddr = fdr.fdr_addr;
20597c478bd9Sstevel@tonic-gate 	ucount = (uint_t)fdr.fdr_nbytes;
20607c478bd9Sstevel@tonic-gate 	unit &= 3;
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	switch (fdr.fdr_cmd[0] & 0x0f) {
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	case FDRAW_FORMAT:
20657c478bd9Sstevel@tonic-gate 		ucount += 16;
20667c478bd9Sstevel@tonic-gate 		fdr.fdr_addr = kmem_zalloc(ucount, KM_SLEEP);
20677c478bd9Sstevel@tonic-gate 		if (ddi_copyin(uaddr, fdr.fdr_addr,
20687c478bd9Sstevel@tonic-gate 		    (size_t)fdr.fdr_nbytes, mode)) {
20697c478bd9Sstevel@tonic-gate 			kmem_free(fdr.fdr_addr, ucount);
20707c478bd9Sstevel@tonic-gate 			return (EFAULT);
20717c478bd9Sstevel@tonic-gate 		}
20727c478bd9Sstevel@tonic-gate 		if ((*fdr.fdr_addr | fdr.fdr_addr[1]) == 0)
20737c478bd9Sstevel@tonic-gate 			fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
20747c478bd9Sstevel@tonic-gate 		flag = B_WRITE;
20757c478bd9Sstevel@tonic-gate 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
20767c478bd9Sstevel@tonic-gate 		break;
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	case FDRAW_WRCMD:
20797c478bd9Sstevel@tonic-gate 	case FDRAW_WRITEDEL:
20807c478bd9Sstevel@tonic-gate 		flag = B_WRITE;
20817c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
20827c478bd9Sstevel@tonic-gate 	case FDRAW_RDCMD:
20837c478bd9Sstevel@tonic-gate 	case FDRAW_READDEL:
20847c478bd9Sstevel@tonic-gate 	case FDRAW_READTRACK:
20857c478bd9Sstevel@tonic-gate 		if (ucount) {
20867c478bd9Sstevel@tonic-gate 			/*
20877c478bd9Sstevel@tonic-gate 			 * In SunOS 4.X, we used to as_fault things in.
20887c478bd9Sstevel@tonic-gate 			 * We really cannot do this in 5.0/SVr4. Unless
20897c478bd9Sstevel@tonic-gate 			 * someone really believes that speed is of the
20907c478bd9Sstevel@tonic-gate 			 * essence here, it is just much simpler to do
20917c478bd9Sstevel@tonic-gate 			 * this in kernel space and use copyin/copyout.
20927c478bd9Sstevel@tonic-gate 			 */
20937c478bd9Sstevel@tonic-gate 			fdr.fdr_addr = kmem_alloc((size_t)ucount, KM_SLEEP);
20947c478bd9Sstevel@tonic-gate 			if (flag == B_WRITE) {
20957c478bd9Sstevel@tonic-gate 				if (ddi_copyin(uaddr, fdr.fdr_addr, ucount,
20967c478bd9Sstevel@tonic-gate 				    mode)) {
20977c478bd9Sstevel@tonic-gate 					kmem_free(fdr.fdr_addr, ucount);
20987c478bd9Sstevel@tonic-gate 					return (EFAULT);
20997c478bd9Sstevel@tonic-gate 				}
21007c478bd9Sstevel@tonic-gate 			}
21017c478bd9Sstevel@tonic-gate 		} else
21027c478bd9Sstevel@tonic-gate 			return (EINVAL);
21037c478bd9Sstevel@tonic-gate 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
21047c478bd9Sstevel@tonic-gate 		break;
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 	case FDRAW_READID:
21077c478bd9Sstevel@tonic-gate 	case FDRAW_REZERO:
21087c478bd9Sstevel@tonic-gate 	case FDRAW_SEEK:
21097c478bd9Sstevel@tonic-gate 	case FDRAW_SENSE_DRV:
21107c478bd9Sstevel@tonic-gate 		ucount = 0;
21117c478bd9Sstevel@tonic-gate 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
21127c478bd9Sstevel@tonic-gate 		break;
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	case FDRAW_SPECIFY:
21157c478bd9Sstevel@tonic-gate 		fdr.fdr_cmd[2] &= 0xfe;	/* keep NoDMA bit clear */
21167c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
21177c478bd9Sstevel@tonic-gate 	case FDRAW_SENSE_INT:
21187c478bd9Sstevel@tonic-gate 		ucount = 0;
21197c478bd9Sstevel@tonic-gate 		break;
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	default:
21227c478bd9Sstevel@tonic-gate 		return (EINVAL);
21237c478bd9Sstevel@tonic-gate 	}
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	/*
21267c478bd9Sstevel@tonic-gate 	 * Note that we ignore any error returns from controller
21277c478bd9Sstevel@tonic-gate 	 * This is the way the driver has been, and it may be
21287c478bd9Sstevel@tonic-gate 	 * that the raw ioctl senders simply don't want to
21297c478bd9Sstevel@tonic-gate 	 * see any errors returned in this fashion.
21307c478bd9Sstevel@tonic-gate 	 */
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 1);
21337c478bd9Sstevel@tonic-gate 	rval = fjp->fj_ops->fco_rwioctl(fjp, unit, (caddr_t)&fdr);
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	if (ucount && flag == B_READ && rval == 0) {
21367c478bd9Sstevel@tonic-gate 		if (ddi_copyout(fdr.fdr_addr, uaddr, ucount, mode)) {
21377c478bd9Sstevel@tonic-gate 			rval = EFAULT;
21387c478bd9Sstevel@tonic-gate 		}
21397c478bd9Sstevel@tonic-gate 	}
21407c478bd9Sstevel@tonic-gate 	if (ddi_copyout(fdr.fdr_result, arg_result, sizeof (fdr.fdr_cmd), mode))
21417c478bd9Sstevel@tonic-gate 		rval = EFAULT;
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 0);
21447c478bd9Sstevel@tonic-gate 	if (ucount)
21457c478bd9Sstevel@tonic-gate 		kmem_free(fdr.fdr_addr, ucount);
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate 	return (rval);
21487c478bd9Sstevel@tonic-gate }
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate /*
21517c478bd9Sstevel@tonic-gate  * property operation routine.  return the number of blocks for the partition
21527c478bd9Sstevel@tonic-gate  * in question or forward the request to the property facilities.
21537c478bd9Sstevel@tonic-gate  */
21547c478bd9Sstevel@tonic-gate static int
21557c478bd9Sstevel@tonic-gate fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
21567c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
21577c478bd9Sstevel@tonic-gate {
21587c478bd9Sstevel@tonic-gate 	struct fcu_obj	*fjp = NULL;
21597c478bd9Sstevel@tonic-gate 	struct fdisk	*fdp = NULL;
21607c478bd9Sstevel@tonic-gate 	uint64_t	nblocks64;
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PROP,
21637c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_prop_op: dip %p %s\n", (void *)dip, name));
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	/*
21667c478bd9Sstevel@tonic-gate 	 * Our dynamic properties are all device specific and size oriented.
21677c478bd9Sstevel@tonic-gate 	 * Requests issued under conditions where size is valid are passed
21687c478bd9Sstevel@tonic-gate 	 * to ddi_prop_op_nblocks with the size information, otherwise the
21697c478bd9Sstevel@tonic-gate 	 * request is passed to ddi_prop_op.
21707c478bd9Sstevel@tonic-gate 	 */
21717c478bd9Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY) {
21727c478bd9Sstevel@tonic-gate pass:  		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
21737c478bd9Sstevel@tonic-gate 		    name, valuep, lengthp));
21747c478bd9Sstevel@tonic-gate 	} else {
21757c478bd9Sstevel@tonic-gate 		/*
21767c478bd9Sstevel@tonic-gate 		 * Ignoring return value because success is checked by
21777c478bd9Sstevel@tonic-gate 		 * verifying fjp and fdp and returned unit value is not used.
21787c478bd9Sstevel@tonic-gate 		 */
21797c478bd9Sstevel@tonic-gate 		(void) fd_getdrive(dev, &fjp, &fdp);
21807c478bd9Sstevel@tonic-gate 		if (!fjp || !fdp)
21817c478bd9Sstevel@tonic-gate 			goto pass;
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 		/* get nblocks value */
21847c478bd9Sstevel@tonic-gate 		nblocks64 = (ulong_t)fdp->d_part[PARTITION(dev)].p_size;
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 		return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
21877c478bd9Sstevel@tonic-gate 		    name, valuep, lengthp, nblocks64));
21887c478bd9Sstevel@tonic-gate 	}
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate static void
21927c478bd9Sstevel@tonic-gate fd_media_watch(void *arg)
21937c478bd9Sstevel@tonic-gate {
21947c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp;
21957c478bd9Sstevel@tonic-gate 	struct fdisk *fdp;
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate #ifdef DEBUG
21987c478bd9Sstevel@tonic-gate 	int	unit;
21997c478bd9Sstevel@tonic-gate #define	DEBUG_ASSIGN	unit=
22007c478bd9Sstevel@tonic-gate #else
22017c478bd9Sstevel@tonic-gate #define	DEBUG_ASSIGN	(void)
22027c478bd9Sstevel@tonic-gate #endif
22037c478bd9Sstevel@tonic-gate 	DEBUG_ASSIGN fd_getdrive((dev_t)arg, &fjp, &fdp);
22047c478bd9Sstevel@tonic-gate 	/*
22057c478bd9Sstevel@tonic-gate 	 * Ignoring return in non DEBUG mode because device exist.
22067c478bd9Sstevel@tonic-gate 	 * Returned unit value is not used.
22077c478bd9Sstevel@tonic-gate 	 */
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_IOCT,
22107c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_media_watch unit %d\n", unit));
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 	/*
22137c478bd9Sstevel@tonic-gate 	 * fd_get_media_state() cannot be called from this timeout function
22147c478bd9Sstevel@tonic-gate 	 * because the  floppy drive has to be selected first, and that could
22157c478bd9Sstevel@tonic-gate 	 * force this function to sleep (while waiting for the select
22167c478bd9Sstevel@tonic-gate 	 * semaphore).
22177c478bd9Sstevel@tonic-gate 	 * Instead, just wakeup up driver.
22187c478bd9Sstevel@tonic-gate 	 */
22197c478bd9Sstevel@tonic-gate 	mutex_enter(&fjp->fj_lock);
22207c478bd9Sstevel@tonic-gate 	cv_broadcast(&fdp->d_statecv);
22217c478bd9Sstevel@tonic-gate 	mutex_exit(&fjp->fj_lock);
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate enum dkio_state
22257c478bd9Sstevel@tonic-gate fd_get_media_state(struct fcu_obj *fjp, int unit)
22267c478bd9Sstevel@tonic-gate {
22277c478bd9Sstevel@tonic-gate 	enum dkio_state state;
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 	if (fjp->fj_ops->fco_getchng(fjp, unit)) {
22307c478bd9Sstevel@tonic-gate 		/* recheck disk only if DSKCHG "high" */
22317c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_resetchng(fjp, unit);
22327c478bd9Sstevel@tonic-gate 		if (fjp->fj_ops->fco_getchng(fjp, unit)) {
22337c478bd9Sstevel@tonic-gate 			if (fjp->fj_flags & FUNIT_CHGDET) {
22347c478bd9Sstevel@tonic-gate 				/*
22357c478bd9Sstevel@tonic-gate 				 * again no diskette; not a new change
22367c478bd9Sstevel@tonic-gate 				 */
22377c478bd9Sstevel@tonic-gate 				state = DKIO_NONE;
22387c478bd9Sstevel@tonic-gate 			} else {
22397c478bd9Sstevel@tonic-gate 				/*
22407c478bd9Sstevel@tonic-gate 				 * a new change; diskette was ejected
22417c478bd9Sstevel@tonic-gate 				 */
22427c478bd9Sstevel@tonic-gate 				fjp->fj_flags |= FUNIT_CHGDET;
22437c478bd9Sstevel@tonic-gate 				state = DKIO_EJECTED;
22447c478bd9Sstevel@tonic-gate 			}
22457c478bd9Sstevel@tonic-gate 		} else {
22467c478bd9Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHGDET;
22477c478bd9Sstevel@tonic-gate 			state = DKIO_INSERTED;
22487c478bd9Sstevel@tonic-gate 		}
22497c478bd9Sstevel@tonic-gate 	} else {
22507c478bd9Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHGDET;
22517c478bd9Sstevel@tonic-gate 		state = DKIO_INSERTED;
22527c478bd9Sstevel@tonic-gate 	}
22537c478bd9Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_IOCT,
22547c478bd9Sstevel@tonic-gate 	    (CE_CONT, "fd_get_media_state unit %d: state %x\n", unit, state));
22557c478bd9Sstevel@tonic-gate 	return (state);
22567c478bd9Sstevel@tonic-gate }
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate static int
22597c478bd9Sstevel@tonic-gate fd_check_media(dev_t dev, enum dkio_state state)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate 	struct fcu_obj *fjp;
22627c478bd9Sstevel@tonic-gate 	struct fdisk *fdp;
22637c478bd9Sstevel@tonic-gate 	int	unit;
22647c478bd9Sstevel@tonic-gate 	int	err;
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 	unit = fd_getdrive(dev, &fjp, &fdp);
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	mutex_enter(&fjp->fj_lock);
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 1);
22717c478bd9Sstevel@tonic-gate 	fdp->d_media_state = fd_get_media_state(fjp, unit);
22727c478bd9Sstevel@tonic-gate 	fdp->d_media_timeout = drv_usectohz(fd_check_media_time);
22737c478bd9Sstevel@tonic-gate 
22747c478bd9Sstevel@tonic-gate 	while (fdp->d_media_state == state) {
22757c478bd9Sstevel@tonic-gate 		/* release the controller and drive */
22767c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate 		/* turn on timer */
22797c478bd9Sstevel@tonic-gate 		fdp->d_media_timeout_id = timeout(fd_media_watch,
22807c478bd9Sstevel@tonic-gate 		    (void *)dev, fdp->d_media_timeout);
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&fdp->d_statecv, &fjp->fj_lock) == 0) {
22837c478bd9Sstevel@tonic-gate 			fdp->d_media_timeout = 0;
22847c478bd9Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
22857c478bd9Sstevel@tonic-gate 			return (EINTR);
22867c478bd9Sstevel@tonic-gate 		}
22877c478bd9Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
22887c478bd9Sstevel@tonic-gate 		fdp->d_media_state = fd_get_media_state(fjp, unit);
22897c478bd9Sstevel@tonic-gate 	}
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	if (fdp->d_media_state == DKIO_INSERTED) {
22927c478bd9Sstevel@tonic-gate 		err = fdgetlabel(fjp, unit);
22937c478bd9Sstevel@tonic-gate 		if (err) {
22947c478bd9Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
22957c478bd9Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
22967c478bd9Sstevel@tonic-gate 			return (EIO);
22977c478bd9Sstevel@tonic-gate 		}
22987c478bd9Sstevel@tonic-gate 	}
22997c478bd9Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 0);
23007c478bd9Sstevel@tonic-gate 	mutex_exit(&fjp->fj_lock);
23017c478bd9Sstevel@tonic-gate 	return (0);
23027c478bd9Sstevel@tonic-gate }
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate /*
23057c478bd9Sstevel@tonic-gate  * fd_get_media_info :
23067c478bd9Sstevel@tonic-gate  * 	Collects medium information for
23077c478bd9Sstevel@tonic-gate  *	DKIOCGMEDIAINFO ioctl.
23087c478bd9Sstevel@tonic-gate  */
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate static int
23117c478bd9Sstevel@tonic-gate fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag)
23127c478bd9Sstevel@tonic-gate {
23137c478bd9Sstevel@tonic-gate 	struct dk_minfo media_info;
23147c478bd9Sstevel@tonic-gate 	int err = 0;
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	media_info.dki_media_type = DK_FLOPPY;
23177c478bd9Sstevel@tonic-gate 	media_info.dki_lbsize = fjp->fj_chars->fdc_sec_size;
23187c478bd9Sstevel@tonic-gate 	media_info.dki_capacity = fjp->fj_chars->fdc_ncyl *
23197c478bd9Sstevel@tonic-gate 	    fjp->fj_chars->fdc_secptrack * fjp->fj_chars->fdc_nhead;
23207c478bd9Sstevel@tonic-gate 
23217c478bd9Sstevel@tonic-gate 	if (ddi_copyout(&media_info, buf, sizeof (struct dk_minfo), flag))
23227c478bd9Sstevel@tonic-gate 		err = EFAULT;
23237c478bd9Sstevel@tonic-gate 	return (err);
23247c478bd9Sstevel@tonic-gate }
2325