xref: /onnv-gate/usr/src/uts/common/io/fd.c (revision 8258:1bbdbab2965d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57656SSherry.Moore@Sun.COM  * Common Development and Distribution License (the "License").
67656SSherry.Moore@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
227656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Floppy Disk driver
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * Set CMOS feature:
330Sstevel@tonic-gate  *	CMOS_CONF_MEM:	CMOS memory contains configuration info
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate #define	CMOS_CONF_MEM
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/systm.h>
400Sstevel@tonic-gate #include <sys/buf.h>
410Sstevel@tonic-gate #include <sys/file.h>
420Sstevel@tonic-gate #include <sys/open.h>
430Sstevel@tonic-gate #include <sys/ioctl.h>
440Sstevel@tonic-gate #include <sys/uio.h>
450Sstevel@tonic-gate #include <sys/conf.h>
460Sstevel@tonic-gate #include <sys/stat.h>
470Sstevel@tonic-gate #include <sys/autoconf.h>
480Sstevel@tonic-gate #include <sys/vtoc.h>
490Sstevel@tonic-gate #include <sys/dkio.h>
500Sstevel@tonic-gate #include <sys/ddi.h>
510Sstevel@tonic-gate #include <sys/sunddi.h>
520Sstevel@tonic-gate #include <sys/kstat.h>
530Sstevel@tonic-gate #include <sys/kmem.h>
540Sstevel@tonic-gate #include <sys/ddidmareq.h>
550Sstevel@tonic-gate #include <sys/fdio.h>
560Sstevel@tonic-gate #include <sys/fdc.h>
570Sstevel@tonic-gate #include <sys/fd_debug.h>
580Sstevel@tonic-gate #include <sys/fdmedia.h>
590Sstevel@tonic-gate #include <sys/debug.h>
600Sstevel@tonic-gate #include <sys/modctl.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate  * Local Function Prototypes
640Sstevel@tonic-gate  */
650Sstevel@tonic-gate static int fd_unit_is_open(struct fdisk *);
660Sstevel@tonic-gate static int fdgetlabel(struct fcu_obj *, int);
670Sstevel@tonic-gate static void fdstart(struct fcu_obj *);
680Sstevel@tonic-gate static int fd_build_label_vtoc(struct fcu_obj *, struct fdisk *,
690Sstevel@tonic-gate     struct vtoc *, struct dk_label *);
700Sstevel@tonic-gate static void fd_build_user_vtoc(struct fcu_obj *, struct fdisk *,
710Sstevel@tonic-gate     struct vtoc *);
720Sstevel@tonic-gate static int fd_rawioctl(struct fcu_obj *, int, caddr_t, int);
730Sstevel@tonic-gate static void fd_media_watch(void *);
740Sstevel@tonic-gate 
750Sstevel@tonic-gate static int fd_open(dev_t *, int, int, cred_t *);
760Sstevel@tonic-gate static int fd_close(dev_t, int, int, cred_t *);
770Sstevel@tonic-gate static int fd_strategy(struct buf *);
780Sstevel@tonic-gate static int fd_read(dev_t, struct uio *, cred_t *);
790Sstevel@tonic-gate static int fd_write(dev_t, struct uio *, cred_t *);
800Sstevel@tonic-gate static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
810Sstevel@tonic-gate static int fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
820Sstevel@tonic-gate     caddr_t, int *);
830Sstevel@tonic-gate static int fd_check_media(dev_t dev, enum dkio_state state);
840Sstevel@tonic-gate static int fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static struct cb_ops fd_cb_ops = {
870Sstevel@tonic-gate 	fd_open,		/* open */
880Sstevel@tonic-gate 	fd_close,		/* close */
890Sstevel@tonic-gate 	fd_strategy,		/* strategy */
900Sstevel@tonic-gate 	nodev,			/* print */
910Sstevel@tonic-gate 	nodev,			/* dump */
920Sstevel@tonic-gate 	fd_read,		/* read */
930Sstevel@tonic-gate 	fd_write,		/* write */
940Sstevel@tonic-gate 	fd_ioctl,		/* ioctl */
950Sstevel@tonic-gate 	nodev,			/* devmap */
960Sstevel@tonic-gate 	nodev,			/* mmap */
970Sstevel@tonic-gate 	nodev,			/* segmap */
980Sstevel@tonic-gate 	nochpoll,		/* poll */
990Sstevel@tonic-gate 	fd_prop_op,		/* cb_prop_op */
1000Sstevel@tonic-gate 	0,			/* streamtab  */
1010Sstevel@tonic-gate 	D_NEW | D_MP		/* Driver compatibility flag */
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate static int fd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
1050Sstevel@tonic-gate static int fd_probe(dev_info_t *);
1060Sstevel@tonic-gate static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
1070Sstevel@tonic-gate static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate static struct dev_ops fd_ops = {
1100Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1110Sstevel@tonic-gate 	0,			/* refcnt  */
1120Sstevel@tonic-gate 	fd_getinfo,		/* getinfo */
1130Sstevel@tonic-gate 	nulldev,		/* identify */
1140Sstevel@tonic-gate 	fd_probe,		/* probe */
1150Sstevel@tonic-gate 	fd_attach,		/* attach */
1160Sstevel@tonic-gate 	fd_detach,		/* detach */
1170Sstevel@tonic-gate 	nodev,			/* reset */
1180Sstevel@tonic-gate 	&fd_cb_ops,		/* driver operations */
1197656SSherry.Moore@Sun.COM 	(struct bus_ops *)0,	/* bus operations */
1207656SSherry.Moore@Sun.COM 	NULL,			/* power */
1217656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
1220Sstevel@tonic-gate };
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * static data
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate static void *fd_state_head;		/* opaque handle top of state structs */
1290Sstevel@tonic-gate static int fd_check_media_time = 5000000;	/* 5 second state check */
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*
1320Sstevel@tonic-gate  * error handling
1330Sstevel@tonic-gate  *
1340Sstevel@tonic-gate  * for debugging,
1350Sstevel@tonic-gate  *		set fderrlevel to 1
1360Sstevel@tonic-gate  *		set fderrmask  to 224  or 644
1370Sstevel@tonic-gate  */
1380Sstevel@tonic-gate #ifdef DEBUG
1390Sstevel@tonic-gate static uint_t fderrmask = FDEM_ALL;
1400Sstevel@tonic-gate #endif
1410Sstevel@tonic-gate static int fderrlevel = 5;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate #define	KIOSP	KSTAT_IO_PTR(fdp->d_iostat)
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate static struct driver_minor_data {
1460Sstevel@tonic-gate 	char	*name;
1470Sstevel@tonic-gate 	int	minor;
1480Sstevel@tonic-gate 	int	type;
1490Sstevel@tonic-gate } fd_minor [] = {
1500Sstevel@tonic-gate 	{ "a", 0, S_IFBLK},
1510Sstevel@tonic-gate 	{ "b", 1, S_IFBLK},
1520Sstevel@tonic-gate 	{ "c", 2, S_IFBLK},
1530Sstevel@tonic-gate 	{ "a,raw", 0, S_IFCHR},
1540Sstevel@tonic-gate 	{ "b,raw", 1, S_IFCHR},
1550Sstevel@tonic-gate 	{ "c,raw", 2, S_IFCHR},
1560Sstevel@tonic-gate 	{0}
1570Sstevel@tonic-gate };
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate static struct modldrv modldrv = {
1600Sstevel@tonic-gate 	&mod_driverops,		/* Type of module. This one is a driver */
1617656SSherry.Moore@Sun.COM 	"Floppy Disk driver",	/* Name of the module. */
1620Sstevel@tonic-gate 	&fd_ops,		/* driver ops */
1630Sstevel@tonic-gate };
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate static struct modlinkage modlinkage = {
1660Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
1670Sstevel@tonic-gate };
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate int
_init(void)1710Sstevel@tonic-gate _init(void)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate 	int retval;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if ((retval = ddi_soft_state_init(&fd_state_head,
1760Sstevel@tonic-gate 	    sizeof (struct fdisk) + sizeof (struct fd_drive) +
1770Sstevel@tonic-gate 	    sizeof (struct fd_char) + sizeof (struct fdattr), 0)) != 0)
1780Sstevel@tonic-gate 		return (retval);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if ((retval = mod_install(&modlinkage)) != 0)
1810Sstevel@tonic-gate 		ddi_soft_state_fini(&fd_state_head);
1820Sstevel@tonic-gate 	return (retval);
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate int
_fini(void)1860Sstevel@tonic-gate _fini(void)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	int retval;
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	if ((retval = mod_remove(&modlinkage)) != 0)
1910Sstevel@tonic-gate 		return (retval);
1920Sstevel@tonic-gate 	ddi_soft_state_fini(&fd_state_head);
1930Sstevel@tonic-gate 	return (retval);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1970Sstevel@tonic-gate _info(struct modinfo *modinfop)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate static int
fd_getdrive(dev_t dev,struct fcu_obj ** fjpp,struct fdisk ** fdpp)2040Sstevel@tonic-gate fd_getdrive(dev_t dev, struct fcu_obj **fjpp, struct fdisk **fdpp)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	if (fdpp) {
2070Sstevel@tonic-gate 		*fdpp = ddi_get_soft_state(fd_state_head, DRIVE(dev));
2080Sstevel@tonic-gate 		if (*fdpp && fjpp) {
2090Sstevel@tonic-gate 			*fjpp = (*fdpp)->d_obj;
2100Sstevel@tonic-gate 			if (*fjpp)
2110Sstevel@tonic-gate 				return ((*fjpp)->fj_unit);
2120Sstevel@tonic-gate 		}
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 	return (-1);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate /*ARGSUSED*/
2180Sstevel@tonic-gate static int
fd_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)2190Sstevel@tonic-gate fd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	dev_t dev = (dev_t)arg;
2220Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
2230Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
2240Sstevel@tonic-gate 	int rval;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	switch (cmd) {
2270Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2280Sstevel@tonic-gate 		(void) fd_getdrive(dev, &fjp, &fdp);
2290Sstevel@tonic-gate 		/*
2300Sstevel@tonic-gate 		 * Ignoring return value because success is checked by
2310Sstevel@tonic-gate 		 * verifying fjp and fdp and returned unit value is not used.
2320Sstevel@tonic-gate 		 */
2330Sstevel@tonic-gate 		if (fjp && fdp) {
2340Sstevel@tonic-gate 			*result = fjp->fj_dip;
2350Sstevel@tonic-gate 			rval = DDI_SUCCESS;
2360Sstevel@tonic-gate 		} else
2370Sstevel@tonic-gate 			rval = DDI_FAILURE;
2380Sstevel@tonic-gate 		break;
2390Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2400Sstevel@tonic-gate 		*result = (void *)(uintptr_t)DRIVE(dev);
2410Sstevel@tonic-gate 		rval = DDI_SUCCESS;
2420Sstevel@tonic-gate 		break;
2430Sstevel@tonic-gate 	default:
2440Sstevel@tonic-gate 		rval = DDI_FAILURE;
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	return (rval);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2500Sstevel@tonic-gate #define	CMOS_ADDR	0x70
2510Sstevel@tonic-gate #define	CMOS_DATA	0x71
2520Sstevel@tonic-gate #define	CMOS_FDRV	0x10
2530Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate static int
fd_probe(dev_info_t * dip)2560Sstevel@tonic-gate fd_probe(dev_info_t *dip)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2590Sstevel@tonic-gate 	int cmos;
2600Sstevel@tonic-gate 	int drive_type;
2610Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
2620Sstevel@tonic-gate 	int debug[2];
2630Sstevel@tonic-gate 	int drive_size;
2640Sstevel@tonic-gate 	int len;
2650Sstevel@tonic-gate 	int unit_num;
2660Sstevel@tonic-gate 	char density[8];
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	len = sizeof (debug);
2690Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
2700Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) ==
2710Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
2720Sstevel@tonic-gate 		fderrlevel = debug[0];
2730Sstevel@tonic-gate #ifdef DEBUG
2740Sstevel@tonic-gate 		fderrmask = (uint_t)debug[1];
2750Sstevel@tonic-gate #endif
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 	len = sizeof (unit_num);
2780Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
2790Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
2800Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
2810Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_ATTA,
2820Sstevel@tonic-gate 		    (CE_WARN, "fd_probe failed: dip %p", (void *)dip));
2830Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
2840Sstevel@tonic-gate 	}
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2870Sstevel@tonic-gate 	/* get the cmos memory values quick and dirty */
2880Sstevel@tonic-gate 	outb(CMOS_ADDR, CMOS_FDRV);
2890Sstevel@tonic-gate 	cmos = drive_type = (int)inb(CMOS_DATA);
2900Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	switch (unit_num) {
2930Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
2940Sstevel@tonic-gate 	case 0:
2950Sstevel@tonic-gate 		drive_type = drive_type >> 4;
2960Sstevel@tonic-gate 		/* FALLTHROUGH */
2970Sstevel@tonic-gate 	case 1:
2980Sstevel@tonic-gate 		if (cmos && (drive_type & 0x0F)) {
2990Sstevel@tonic-gate 			break;
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 		/*
3020Sstevel@tonic-gate 		 * Some enhanced floppy-disk controller adaptor cards
3030Sstevel@tonic-gate 		 * require NO drives defined in the CMOS configuration
3040Sstevel@tonic-gate 		 * memory.
3050Sstevel@tonic-gate 		 * So fall through
3060Sstevel@tonic-gate 		 */
3070Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3080Sstevel@tonic-gate 	default:		/* need to check conf file */
3090Sstevel@tonic-gate 		len = sizeof (density);
3100Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
3110Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "density", (caddr_t)&density, &len) !=
3120Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
3130Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
3140Sstevel@tonic-gate 			    (CE_WARN,
3150Sstevel@tonic-gate 			    "fd_probe failed density: dip %p unit %d",
3160Sstevel@tonic-gate 			    (void *)dip, unit_num));
3170Sstevel@tonic-gate 			return (DDI_PROBE_FAILURE);
3180Sstevel@tonic-gate 		}
3190Sstevel@tonic-gate 		len = sizeof (drive_size);
3200Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
3210Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "size", (caddr_t)&drive_size, &len) !=
3220Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
3230Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
3240Sstevel@tonic-gate 			    (CE_WARN, "fd_probe failed size: dip %p unit %d",
3250Sstevel@tonic-gate 			    (void *)dip, unit_num));
3260Sstevel@tonic-gate 			return (DDI_PROBE_FAILURE);
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 	FDERRPRINT(FDEP_L3, FDEM_ATTA,
3300Sstevel@tonic-gate 	    (CE_WARN, "fd_probe dip %p unit %d", (void *)dip, unit_num));
3310Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate /* ARGSUSED */
3360Sstevel@tonic-gate static int
fd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3370Sstevel@tonic-gate fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate 	struct fcu_obj *fjp;
3400Sstevel@tonic-gate 	struct fdisk *fdp;
3410Sstevel@tonic-gate 	struct driver_minor_data *dmdp;
3420Sstevel@tonic-gate 	int mode_3D;
3430Sstevel@tonic-gate 	int drive_num, drive_size, drive_type;
3440Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
3450Sstevel@tonic-gate 	int cmos;
3460Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3470Sstevel@tonic-gate 	int len, sig_minor;
3480Sstevel@tonic-gate 	int unit_num;
3490Sstevel@tonic-gate 	char density[8];
3500Sstevel@tonic-gate 	char name[MAXNAMELEN];
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	switch (cmd) {
3530Sstevel@tonic-gate 	case DDI_ATTACH:
3540Sstevel@tonic-gate 		len = sizeof (unit_num);
3550Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
3560Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
3570Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
3580Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
3590Sstevel@tonic-gate 			    (CE_WARN, "fd_attach failed: dip %p", (void *)dip));
3600Sstevel@tonic-gate 			return (DDI_FAILURE);
3610Sstevel@tonic-gate 		}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
3640Sstevel@tonic-gate 		outb(CMOS_ADDR, CMOS_FDRV);
3650Sstevel@tonic-gate 		cmos = drive_type = (int)inb(CMOS_DATA);
3660Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		switch (unit_num) {
3690Sstevel@tonic-gate #ifdef CMOS_CONF_MEM
3700Sstevel@tonic-gate 		case 0:
3710Sstevel@tonic-gate 			drive_type = drive_type >> 4;
3720Sstevel@tonic-gate 			/* FALLTHROUGH */
3730Sstevel@tonic-gate 		case 1:
3740Sstevel@tonic-gate 			drive_type = drive_type & 0x0F;
3750Sstevel@tonic-gate 			if (cmos)
3760Sstevel@tonic-gate 				break;
3770Sstevel@tonic-gate 			/*
3780Sstevel@tonic-gate 			 * Some enhanced floppy-disk controller adaptor cards
3790Sstevel@tonic-gate 			 * require NO drives defined in the CMOS configuration
3800Sstevel@tonic-gate 			 * memory.
3810Sstevel@tonic-gate 			 * So fall through
3820Sstevel@tonic-gate 			 */
3830Sstevel@tonic-gate #endif	/* CMOS_CONF_MEM */
3840Sstevel@tonic-gate 		default:		/* need to check .conf file */
3850Sstevel@tonic-gate 			drive_type = 0;
3860Sstevel@tonic-gate 			len = sizeof (density);
3870Sstevel@tonic-gate 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
3880Sstevel@tonic-gate 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "density",
3890Sstevel@tonic-gate 			    (caddr_t)&density, &len) != DDI_PROP_SUCCESS)
3900Sstevel@tonic-gate 				density[0] = '\0';
3910Sstevel@tonic-gate 			len = sizeof (drive_size);
3920Sstevel@tonic-gate 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
3930Sstevel@tonic-gate 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "size",
3940Sstevel@tonic-gate 			    (caddr_t)&drive_size, &len) != DDI_PROP_SUCCESS)
3950Sstevel@tonic-gate 				drive_size = 0;
3960Sstevel@tonic-gate 			if (strcmp(density, "DSDD") == 0) {
3970Sstevel@tonic-gate 				if (drive_size == 5)
3980Sstevel@tonic-gate 					drive_type = 1;
3990Sstevel@tonic-gate 				else if (drive_size == 3)
4000Sstevel@tonic-gate 					drive_type = 3;
4010Sstevel@tonic-gate 			} else if (strcmp(density, "DSHD") == 0) {
4020Sstevel@tonic-gate 				if (drive_size == 5)
4030Sstevel@tonic-gate 					drive_type = 2;
4040Sstevel@tonic-gate 				else if (drive_size == 3)
4050Sstevel@tonic-gate 					drive_type = 4;
4060Sstevel@tonic-gate 			} else if (strcmp(density, "DSED") == 0 &&
4070Sstevel@tonic-gate 			    drive_size == 3) {
4080Sstevel@tonic-gate 				drive_type = 6;
4090Sstevel@tonic-gate 			}
4100Sstevel@tonic-gate 			break;
4110Sstevel@tonic-gate 		}
4120Sstevel@tonic-gate 		if (drive_type == 0) {
4130Sstevel@tonic-gate 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
4140Sstevel@tonic-gate 			    (CE_WARN, "fd_attach failed type: dip %p unit %d",
4150Sstevel@tonic-gate 			    (void *)dip, unit_num));
4160Sstevel@tonic-gate 			return (DDI_FAILURE);
4170Sstevel@tonic-gate 		}
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		drive_num = ddi_get_instance(dip);
4200Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(fd_state_head, drive_num) != 0)
4210Sstevel@tonic-gate 			return (DDI_FAILURE);
4220Sstevel@tonic-gate 		fdp = ddi_get_soft_state(fd_state_head, drive_num);
4230Sstevel@tonic-gate 		fjp = fdp->d_obj = ddi_get_driver_private(dip);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 		mutex_init(&fjp->fj_lock, NULL, MUTEX_DRIVER, *fjp->fj_iblock);
4260Sstevel@tonic-gate 		sema_init(&fdp->d_ocsem, 1, NULL, SEMA_DRIVER, NULL);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 		fjp->fj_drive = (struct fd_drive *)(fdp + 1);
4290Sstevel@tonic-gate 		fjp->fj_chars = (struct fd_char *)(fjp->fj_drive + 1);
4300Sstevel@tonic-gate 		fjp->fj_attr = (struct fdattr *)(fjp->fj_chars + 1);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 		/*
4330Sstevel@tonic-gate 		 * set default floppy drive characteristics & geometry
4340Sstevel@tonic-gate 		 */
4350Sstevel@tonic-gate 		switch (drive_type) {	/* assume doubled sided */
4360Sstevel@tonic-gate 		case 2:			/* 5.25 high density */
4370Sstevel@tonic-gate 			*fjp->fj_drive = dfd_525HD;
4380Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_5H | 1<<FMT_5D9 | 1<<FMT_5D8 |
4390Sstevel@tonic-gate 			    1<<FMT_5D4 | 1<<FMT_5D16;
4400Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_5H;
4410Sstevel@tonic-gate 			break;
4420Sstevel@tonic-gate 		case 4:			/* 3.5 high density */
4430Sstevel@tonic-gate 			*fjp->fj_drive = dfd_350HD;
4440Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_3H | 1<<FMT_3I | 1<<FMT_3D;
4450Sstevel@tonic-gate 			len = sizeof (mode_3D);
4460Sstevel@tonic-gate 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
4470Sstevel@tonic-gate 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "mode_3D",
4480Sstevel@tonic-gate 			    (caddr_t)&mode_3D, &len) != DDI_PROP_SUCCESS)
4490Sstevel@tonic-gate 				mode_3D = 0;
4500Sstevel@tonic-gate 			if (mode_3D && (fjp->fj_fdc->c_flags & FCFLG_3DMODE))
4510Sstevel@tonic-gate 				/*
4520Sstevel@tonic-gate 				 * 3D mode should be enabled only if a dual-
4530Sstevel@tonic-gate 				 * speed 3.5" high-density drive and a
4540Sstevel@tonic-gate 				 * supported floppy controller are installed.
4550Sstevel@tonic-gate 				 */
4560Sstevel@tonic-gate 				fdp->d_media |= 1 << FMT_3M;
4570Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3H;
4580Sstevel@tonic-gate 			break;
4590Sstevel@tonic-gate 		case 1:			/* 5.25 double density */
4600Sstevel@tonic-gate 			*fjp->fj_drive = dfd_525DD;
4610Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_5D9 | 1<<FMT_5D8 | 1<<FMT_5D4 |
4620Sstevel@tonic-gate 			    1<<FMT_5D16;
4630Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_5D9;
4640Sstevel@tonic-gate 			break;
4650Sstevel@tonic-gate 		case 3:			/* 3.5 double density */
4660Sstevel@tonic-gate 			*fjp->fj_drive = dfd_350HD;
4670Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_3D;
4680Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3D;
4690Sstevel@tonic-gate 			break;
4700Sstevel@tonic-gate 		case 5:			/* 3.5 extended density */
4710Sstevel@tonic-gate 		case 6:
4720Sstevel@tonic-gate 		case 7:
4730Sstevel@tonic-gate 			*fjp->fj_drive = dfd_350ED;
4740Sstevel@tonic-gate 			fdp->d_media = 1<<FMT_3E | 1<<FMT_3H | 1<<FMT_3I |
4750Sstevel@tonic-gate 			    1<<FMT_3D;
4760Sstevel@tonic-gate 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3E;
4770Sstevel@tonic-gate 			break;
4780Sstevel@tonic-gate 		case 0:			/* no drive defined */
4790Sstevel@tonic-gate 		default:
4800Sstevel@tonic-gate 			goto no_attach;
4810Sstevel@tonic-gate 		}
4820Sstevel@tonic-gate 		*fjp->fj_chars = *defchar[fdp->d_deffdtype];
4830Sstevel@tonic-gate 		*fjp->fj_attr = fdtypes[fdp->d_deffdtype];
4840Sstevel@tonic-gate 		bcopy(fdparts[fdp->d_deffdtype], fdp->d_part,
4850Sstevel@tonic-gate 		    sizeof (struct partition) * NDKMAP);
4860Sstevel@tonic-gate 		fjp->fj_rotspd = fdtypes[fdp->d_deffdtype].fda_rotatespd;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 		sig_minor = drive_num << 3;
4890Sstevel@tonic-gate 		for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
4900Sstevel@tonic-gate 			if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
4910Sstevel@tonic-gate 			    sig_minor | dmdp->minor, DDI_NT_FD, NULL)
4920Sstevel@tonic-gate 			    == DDI_FAILURE) {
4930Sstevel@tonic-gate 				ddi_remove_minor_node(dip, NULL);
4940Sstevel@tonic-gate 				goto no_attach;
4950Sstevel@tonic-gate 			}
4960Sstevel@tonic-gate 		}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_ATTA,
4990Sstevel@tonic-gate 		    (CE_WARN, "fd_attach: dip %p unit %d",
5000Sstevel@tonic-gate 		    (void *)dip, unit_num));
5010Sstevel@tonic-gate 		(void) sprintf(name, "fd%d", drive_num);
5020Sstevel@tonic-gate 		fdp->d_iostat = kstat_create("fd", drive_num, name, "disk",
5030Sstevel@tonic-gate 		    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
5040Sstevel@tonic-gate 		if (fdp->d_iostat) {
5050Sstevel@tonic-gate 			fdp->d_iostat->ks_lock = &fjp->fj_lock;
5060Sstevel@tonic-gate 			kstat_install(fdp->d_iostat);
5070Sstevel@tonic-gate 		}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		fjp->fj_data = (caddr_t)fdp;
5100Sstevel@tonic-gate 		fjp->fj_flags |= FUNIT_DRVATCH;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 		/*
5130Sstevel@tonic-gate 		 * Add a zero-length attribute to tell the world we support
5140Sstevel@tonic-gate 		 * kernel ioctls (for layered drivers)
5150Sstevel@tonic-gate 		 */
5160Sstevel@tonic-gate 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
5170Sstevel@tonic-gate 		    DDI_KERNEL_IOCTL, NULL, 0);
518*8258Sgdamore@opensolaris.org 
519*8258Sgdamore@opensolaris.org 		/*
520*8258Sgdamore@opensolaris.org 		 * We want to get suspend/resume events, so that we can
521*8258Sgdamore@opensolaris.org 		 * refuse to suspend when pcfs is mounted.
522*8258Sgdamore@opensolaris.org 		 */
523*8258Sgdamore@opensolaris.org 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
524*8258Sgdamore@opensolaris.org 		    "pm-hardware-state", "needs-suspend-resume");
525*8258Sgdamore@opensolaris.org 
5260Sstevel@tonic-gate 		/*
5270Sstevel@tonic-gate 		 * Ignoring return value because, for passed arguments, only
5280Sstevel@tonic-gate 		 * DDI_SUCCESS is returned.
5290Sstevel@tonic-gate 		 */
5300Sstevel@tonic-gate 		ddi_report_dev(dip);
5310Sstevel@tonic-gate 		return (DDI_SUCCESS);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	case DDI_RESUME:
534*8258Sgdamore@opensolaris.org 		/* nothing for us to do */
5350Sstevel@tonic-gate 		return (DDI_SUCCESS);
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	default:
5380Sstevel@tonic-gate 		return (DDI_FAILURE);
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate no_attach:
5410Sstevel@tonic-gate 	fjp->fj_drive = NULL;
5420Sstevel@tonic-gate 	fjp->fj_chars = NULL;
5430Sstevel@tonic-gate 	fjp->fj_attr = NULL;
5440Sstevel@tonic-gate 	mutex_destroy(&fjp->fj_lock);
5450Sstevel@tonic-gate 	sema_destroy(&fdp->d_ocsem);
5460Sstevel@tonic-gate 	ddi_soft_state_free(fd_state_head, drive_num);
5470Sstevel@tonic-gate 	FDERRPRINT(FDEP_L3, FDEM_ATTA,
5480Sstevel@tonic-gate 	    (CE_WARN, "fd_attach failed: dip %p unit %d",
5490Sstevel@tonic-gate 	    (void *)dip, unit_num));
5500Sstevel@tonic-gate 	return (DDI_FAILURE);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /* ARGSUSED */
5550Sstevel@tonic-gate static int
fd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)5560Sstevel@tonic-gate fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate 	struct fcu_obj *fjp;
5590Sstevel@tonic-gate 	struct fdisk *fdp;
5600Sstevel@tonic-gate 	int drive_num;
5610Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	FDERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fd_detach dip %p",
5647656SSherry.Moore@Sun.COM 	    (void *)dip));
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	drive_num = ddi_get_instance(dip);
5670Sstevel@tonic-gate 	if (!(fdp = ddi_get_soft_state(fd_state_head, drive_num)))
5680Sstevel@tonic-gate 		return (rval);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	switch (cmd) {
5710Sstevel@tonic-gate 	case DDI_DETACH:
5720Sstevel@tonic-gate 		if (fd_unit_is_open(fdp)) {
573*8258Sgdamore@opensolaris.org 			rval = DDI_FAILURE;
5740Sstevel@tonic-gate 			break;
5750Sstevel@tonic-gate 		}
5760Sstevel@tonic-gate 		kstat_delete(fdp->d_iostat);
5770Sstevel@tonic-gate 		fdp->d_iostat = NULL;
5780Sstevel@tonic-gate 		fjp = (struct fcu_obj *)fdp->d_obj;
579*8258Sgdamore@opensolaris.org 		fjp->fj_flags &= ~FUNIT_DRVATCH;
5800Sstevel@tonic-gate 		fjp->fj_data = NULL;
5810Sstevel@tonic-gate 		fjp->fj_drive = NULL;
5820Sstevel@tonic-gate 		fjp->fj_chars = NULL;
5830Sstevel@tonic-gate 		fjp->fj_attr = NULL;
5840Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
5850Sstevel@tonic-gate 		mutex_destroy(&fjp->fj_lock);
5860Sstevel@tonic-gate 		sema_destroy(&fdp->d_ocsem);
5870Sstevel@tonic-gate 		ddi_soft_state_free(fd_state_head, drive_num);
5880Sstevel@tonic-gate 		break;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	case DDI_SUSPEND:
591*8258Sgdamore@opensolaris.org 		/*
592*8258Sgdamore@opensolaris.org 		 * Bad, bad, bad things will happen if someone
593*8258Sgdamore@opensolaris.org 		 * *changes* the disk in the drive while it is mounted
594*8258Sgdamore@opensolaris.org 		 * and the system is suspended.  We have no way to
595*8258Sgdamore@opensolaris.org 		 * detect that.  (Undetected filesystem corruption.
596*8258Sgdamore@opensolaris.org 		 * Its akin to changing the boot disk while the system
597*8258Sgdamore@opensolaris.org 		 * is suspended.  Don't do it!)
598*8258Sgdamore@opensolaris.org 		 *
599*8258Sgdamore@opensolaris.org 		 * So we refuse to suspend if there is a mounted filesystem.
600*8258Sgdamore@opensolaris.org 		 * (We guess this by looking for a block open.  Character
601*8258Sgdamore@opensolaris.org 		 * opens are fine.)  This limits some of the usability of
602*8258Sgdamore@opensolaris.org 		 * suspend/resume, but it certainly avoids this
603*8258Sgdamore@opensolaris.org 		 * potential filesytem corruption from pilot error.
604*8258Sgdamore@opensolaris.org 		 * Given the decreasing popularity of floppy media, we
605*8258Sgdamore@opensolaris.org 		 * don't see this as much of a limitation.
606*8258Sgdamore@opensolaris.org 		 */
607*8258Sgdamore@opensolaris.org 		if (fdp->d_regopen[OTYP_BLK]) {
608*8258Sgdamore@opensolaris.org 			cmn_err(CE_NOTE,
609*8258Sgdamore@opensolaris.org 			    "Unable to suspend while floppy is in use.");
610*8258Sgdamore@opensolaris.org 			rval = DDI_FAILURE;
6110Sstevel@tonic-gate 		}
6120Sstevel@tonic-gate 		break;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	default:
615*8258Sgdamore@opensolaris.org 		rval = DDI_FAILURE;
6160Sstevel@tonic-gate 		break;
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 	return (rval);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate static int
fd_part_is_open(struct fdisk * fdp,int part)6230Sstevel@tonic-gate fd_part_is_open(struct fdisk *fdp, int part)
6240Sstevel@tonic-gate {
6250Sstevel@tonic-gate 	int i;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	for (i = 0; i < (OTYPCNT - 1); i++)
6280Sstevel@tonic-gate 		if (fdp->d_regopen[i] & (1 << part))
6290Sstevel@tonic-gate 			return (1);
6300Sstevel@tonic-gate 	return (0);
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate static int
fd_unit_is_open(struct fdisk * fdp)6340Sstevel@tonic-gate fd_unit_is_open(struct fdisk *fdp)
6350Sstevel@tonic-gate {
6360Sstevel@tonic-gate 	int i;
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++)
6390Sstevel@tonic-gate 		if (fdp->d_lyropen[i])
6400Sstevel@tonic-gate 			return (1);
6410Sstevel@tonic-gate 	for (i = 0; i < (OTYPCNT - 1); i++)
6420Sstevel@tonic-gate 		if (fdp->d_regopen[i])
6430Sstevel@tonic-gate 			return (1);
6440Sstevel@tonic-gate 	return (0);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate /*ARGSUSED*/
6480Sstevel@tonic-gate static int
fd_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)6490Sstevel@tonic-gate fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
6500Sstevel@tonic-gate {
6510Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
6520Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
6530Sstevel@tonic-gate 	struct partition *pp;
6540Sstevel@tonic-gate 	dev_t dev;
6550Sstevel@tonic-gate 	int part, unit;
6560Sstevel@tonic-gate 	int part_is_open;
6570Sstevel@tonic-gate 	int rval;
6580Sstevel@tonic-gate 	uint_t pbit;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	dev = *devp;
6610Sstevel@tonic-gate 	unit = fd_getdrive(dev, &fjp, &fdp);
6620Sstevel@tonic-gate 	if (!fjp || !fdp)
6630Sstevel@tonic-gate 		return (ENXIO);
6640Sstevel@tonic-gate 	part = PARTITION(dev);
6650Sstevel@tonic-gate 	pbit = 1 << part;
6660Sstevel@tonic-gate 	pp = &fdp->d_part[part];
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	/*
6690Sstevel@tonic-gate 	 * Serialize opens/closes
6700Sstevel@tonic-gate 	 */
6710Sstevel@tonic-gate 	sema_p(&fdp->d_ocsem);
6720Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
6730Sstevel@tonic-gate 	    (CE_CONT, "fd_open: fd%d part %d flag %x otype %x\n", DRIVE(dev),
6740Sstevel@tonic-gate 	    part, flag, otyp));
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/*
6770Sstevel@tonic-gate 	 * Check for previous exclusive open, or trying to exclusive open
6780Sstevel@tonic-gate 	 * An "exclusive open" on any partition is not guaranteed to
6790Sstevel@tonic-gate 	 * protect against opens on another partition that overlaps it.
6800Sstevel@tonic-gate 	 */
6810Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
6820Sstevel@tonic-gate 		part_is_open = (fdp->d_lyropen[part] != 0);
6830Sstevel@tonic-gate 	} else {
6840Sstevel@tonic-gate 		part_is_open = fd_part_is_open(fdp, part);
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 	if ((fdp->d_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
6870Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_OPEN, (CE_CONT,
6880Sstevel@tonic-gate 		    "fd_open: exclparts %lx openparts %lx lyrcnt %lx pbit %x\n",
6890Sstevel@tonic-gate 		    fdp->d_exclmask, fdp->d_regopen[otyp], fdp->d_lyropen[part],
6900Sstevel@tonic-gate 		    pbit));
6910Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
6920Sstevel@tonic-gate 		return (EBUSY);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/*
6960Sstevel@tonic-gate 	 * Ensure that drive is recalibrated on first open of new diskette.
6970Sstevel@tonic-gate 	 */
6980Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 1);
6990Sstevel@tonic-gate 	if (fjp->fj_ops->fco_getchng(fjp, unit) != 0) {
7000Sstevel@tonic-gate 		if (fjp->fj_ops->fco_rcseek(fjp, unit, -1, 0)) {
7010Sstevel@tonic-gate 			FDERRPRINT(FDEP_L2, FDEM_OPEN,
7020Sstevel@tonic-gate 			    (CE_NOTE, "fd_open fd%d: not ready", DRIVE(dev)));
7030Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
7040Sstevel@tonic-gate 			sema_v(&fdp->d_ocsem);
7050Sstevel@tonic-gate 			return (ENXIO);
7060Sstevel@tonic-gate 		}
7070Sstevel@tonic-gate 		fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 	if (flag & (FNDELAY | FNONBLOCK)) {
7100Sstevel@tonic-gate 		/* don't attempt access, just return successfully */
7110Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
7120Sstevel@tonic-gate 		goto out;
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/*
7160Sstevel@tonic-gate 	 * auto-sense the density/format of the diskette
7170Sstevel@tonic-gate 	 */
7180Sstevel@tonic-gate 	rval = fdgetlabel(fjp, unit);
7190Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 0);
7200Sstevel@tonic-gate 	if (rval) {
7210Sstevel@tonic-gate 		/* didn't find label (couldn't read anything) */
7220Sstevel@tonic-gate 		FDERRPRINT(FDEP_L2, FDEM_OPEN,
7230Sstevel@tonic-gate 		    (CE_NOTE, "fd%d: drive not ready", DRIVE(dev)));
7240Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
7250Sstevel@tonic-gate 		return (EIO);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 	/* check partition */
7280Sstevel@tonic-gate 	if (pp->p_size == 0) {
7290Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
7300Sstevel@tonic-gate 		return (ENXIO);
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 	/*
7330Sstevel@tonic-gate 	 * if opening for writing, check write protect on diskette
7340Sstevel@tonic-gate 	 */
7350Sstevel@tonic-gate 	if ((flag & FWRITE) && (fdp->d_obj->fj_flags & FUNIT_WPROT)) {
7360Sstevel@tonic-gate 		sema_v(&fdp->d_ocsem);
7370Sstevel@tonic-gate 		return (EROFS);
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate out:
7410Sstevel@tonic-gate 	/*
7420Sstevel@tonic-gate 	 * mark open as having succeeded
7430Sstevel@tonic-gate 	 */
7440Sstevel@tonic-gate 	if (flag & FEXCL)
7450Sstevel@tonic-gate 		fdp->d_exclmask |= pbit;
7460Sstevel@tonic-gate 	if (otyp == OTYP_LYR)
7470Sstevel@tonic-gate 		fdp->d_lyropen[part]++;
7480Sstevel@tonic-gate 	else
7490Sstevel@tonic-gate 		fdp->d_regopen[otyp] |= 1 << part;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	sema_v(&fdp->d_ocsem);
7520Sstevel@tonic-gate 	return (0);
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate /*
7560Sstevel@tonic-gate  * fdgetlabel - read the SunOS label off the diskette
7570Sstevel@tonic-gate  *	if it can read a valid label it does so, else it will use a
7580Sstevel@tonic-gate  *	default.  If it can`t read the diskette - that is an error.
7590Sstevel@tonic-gate  *
7600Sstevel@tonic-gate  * RETURNS: 0 for ok - meaning that it could at least read the device,
7610Sstevel@tonic-gate  *	!0 for error XXX TBD NYD error codes
7620Sstevel@tonic-gate  */
7630Sstevel@tonic-gate static int
fdgetlabel(struct fcu_obj * fjp,int unit)7640Sstevel@tonic-gate fdgetlabel(struct fcu_obj *fjp, int unit)
7650Sstevel@tonic-gate {
7660Sstevel@tonic-gate 	struct dk_label *label;
7670Sstevel@tonic-gate 	struct fdisk *fdp;
7680Sstevel@tonic-gate 	char *newlabel;
7690Sstevel@tonic-gate 	short *sp;
7700Sstevel@tonic-gate 	short count;
7710Sstevel@tonic-gate 	short xsum;
7720Sstevel@tonic-gate 	int tries, try_this;
7730Sstevel@tonic-gate 	uint_t nexttype;
7740Sstevel@tonic-gate 	int rval;
7750Sstevel@tonic-gate 	short oldlvl;
7760Sstevel@tonic-gate 	int i;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_GETL,
7790Sstevel@tonic-gate 	    (CE_CONT, "fdgetlabel fd unit %d\n", unit));
7800Sstevel@tonic-gate 	fdp = (struct fdisk *)fjp->fj_data;
7810Sstevel@tonic-gate 	fjp->fj_flags &= ~(FUNIT_UNLABELED);
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	/*
7840Sstevel@tonic-gate 	 * get some space to play with the label
7850Sstevel@tonic-gate 	 */
7860Sstevel@tonic-gate 	label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
7870Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_GETL, (CE_CONT,
7880Sstevel@tonic-gate 	    "fdgetlabel fd unit %d kmem_zalloc: ptr = %p, size = %lx\n",
7890Sstevel@tonic-gate 	    unit, (void *)label, (size_t)sizeof (struct dk_label)));
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/*
7920Sstevel@tonic-gate 	 * read block 0 (0/0/1) to find the label
7930Sstevel@tonic-gate 	 * (disk is potentially not present or unformatted)
7940Sstevel@tonic-gate 	 */
7950Sstevel@tonic-gate 	/* noerrprint since this is a private cmd */
7960Sstevel@tonic-gate 	oldlvl = fderrlevel;
7970Sstevel@tonic-gate 	fderrlevel = FDEP_LMAX;
7980Sstevel@tonic-gate 	/*
7990Sstevel@tonic-gate 	 * try different characteristics (ie densities)
8000Sstevel@tonic-gate 	 *
8010Sstevel@tonic-gate 	 * if fdp->d_curfdtype is -1 then the current characteristics
8020Sstevel@tonic-gate 	 * were set by ioctl and need to try it as well as everything
8030Sstevel@tonic-gate 	 * in the table
8040Sstevel@tonic-gate 	 */
8050Sstevel@tonic-gate 	nexttype = fdp->d_deffdtype;
8060Sstevel@tonic-gate 	try_this = 1;		/* always try the current characteristics */
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	for (tries = nfdtypes; tries; tries--) {
8090Sstevel@tonic-gate 		if (try_this) {
8100Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHAROK;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 			/* try reading last sector of cyl 1, head 0 */
8130Sstevel@tonic-gate 			if (!(rval = fjp->fj_ops->fco_rw(fjp, unit,
8140Sstevel@tonic-gate 			    FDREAD, 1, 0, fjp->fj_chars->fdc_secptrack,
8150Sstevel@tonic-gate 			    (caddr_t)label,
8160Sstevel@tonic-gate 			    sizeof (struct dk_label))) &&
8170Sstevel@tonic-gate 			    /* and last sector plus 1 of cylinder 1 */
8180Sstevel@tonic-gate 			    fjp->fj_ops->fco_rw(fjp, unit, FDREAD, 1,
8190Sstevel@tonic-gate 			    0, fjp->fj_chars->fdc_secptrack + 1,
8200Sstevel@tonic-gate 			    (caddr_t)label,
8210Sstevel@tonic-gate 			    sizeof (struct dk_label)) &&
8220Sstevel@tonic-gate 			    /* and label sector on cylinder 0 */
8230Sstevel@tonic-gate 			    !(rval = fjp->fj_ops->fco_rw(fjp, unit,
8240Sstevel@tonic-gate 			    FDREAD, 0, 0, 1, (caddr_t)label,
8250Sstevel@tonic-gate 			    sizeof (struct dk_label))))
8260Sstevel@tonic-gate 				break;
8270Sstevel@tonic-gate 			if (rval == ENXIO)
8280Sstevel@tonic-gate 				break;
8290Sstevel@tonic-gate 		}
8300Sstevel@tonic-gate 		/*
8310Sstevel@tonic-gate 		 * try the next entry in the characteristics tbl
8320Sstevel@tonic-gate 		 */
8330Sstevel@tonic-gate 		fdp->d_curfdtype = (signed char)nexttype;
8340Sstevel@tonic-gate 		nexttype = (nexttype + 1) % nfdtypes;
8350Sstevel@tonic-gate 		if ((1 << fdp->d_curfdtype) & fdp->d_media) {
8360Sstevel@tonic-gate 			*fjp->fj_chars = *defchar[fdp->d_curfdtype];
8370Sstevel@tonic-gate 			*fjp->fj_attr = fdtypes[fdp->d_curfdtype];
8380Sstevel@tonic-gate 			bcopy(fdparts[fdp->d_curfdtype], fdp->d_part,
8390Sstevel@tonic-gate 			    sizeof (struct partition) * NDKMAP);
8400Sstevel@tonic-gate 			/*
8410Sstevel@tonic-gate 			 * check for a double_density diskette
8420Sstevel@tonic-gate 			 * in a high_density 5.25" drive
8430Sstevel@tonic-gate 			 */
8440Sstevel@tonic-gate 			if (fjp->fj_chars->fdc_transfer_rate == 250 &&
8450Sstevel@tonic-gate 			    fjp->fj_rotspd > fjp->fj_attr->fda_rotatespd) {
8460Sstevel@tonic-gate 				/*
8470Sstevel@tonic-gate 				 * yes - adjust transfer rate since we don't
8480Sstevel@tonic-gate 				 * know if we have a 5.25" dual-speed drive
8490Sstevel@tonic-gate 				 */
8500Sstevel@tonic-gate 				fjp->fj_attr->fda_rotatespd = 360;
8510Sstevel@tonic-gate 				fjp->fj_chars->fdc_transfer_rate = 300;
8520Sstevel@tonic-gate 				fjp->fj_chars->fdc_medium = 5;
8530Sstevel@tonic-gate 			}
8540Sstevel@tonic-gate 			if ((2 * fjp->fj_chars->fdc_ncyl) ==
8550Sstevel@tonic-gate 			    defchar[fdp->d_deffdtype]->fdc_ncyl) {
8560Sstevel@tonic-gate 				/* yes - adjust steps per cylinder */
8570Sstevel@tonic-gate 				fjp->fj_chars->fdc_steps = 2;
8580Sstevel@tonic-gate 			} else
8590Sstevel@tonic-gate 				fjp->fj_chars->fdc_steps = 1;
8600Sstevel@tonic-gate 			try_this = 1;
8610Sstevel@tonic-gate 		} else
8620Sstevel@tonic-gate 			try_this = 0;
8630Sstevel@tonic-gate 	}
8640Sstevel@tonic-gate 	fderrlevel = oldlvl;	/* print errors again */
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	if (rval) {
8670Sstevel@tonic-gate 		fdp->d_curfdtype = fdp->d_deffdtype;
8680Sstevel@tonic-gate 		goto out;			/* couldn't read anything */
8690Sstevel@tonic-gate 	}
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_GETL,
8720Sstevel@tonic-gate 	    (CE_CONT,
8730Sstevel@tonic-gate 	    "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n",
8740Sstevel@tonic-gate 	    unit, fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_secptrack,
8750Sstevel@tonic-gate 	    fjp->fj_chars->fdc_steps, fjp->fj_attr->fda_rotatespd,
8760Sstevel@tonic-gate 	    fjp->fj_attr->fda_intrlv));
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/*
8790Sstevel@tonic-gate 	 * _something_ was read  -  look for unixtype label
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 	if (label->dkl_magic != DKL_MAGIC ||
8820Sstevel@tonic-gate 	    label->dkl_vtoc.v_sanity != VTOC_SANE) {
8830Sstevel@tonic-gate 		/* not a label - no magic number */
8840Sstevel@tonic-gate 		goto nolabel;	/* no errors, but no label */
8850Sstevel@tonic-gate 	}
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	count = sizeof (struct dk_label) / sizeof (short);
8880Sstevel@tonic-gate 	sp = (short *)label;
8890Sstevel@tonic-gate 	xsum = 0;
8900Sstevel@tonic-gate 	while (count--)
8910Sstevel@tonic-gate 		xsum ^= *sp++;	/* should add up to 0 */
8920Sstevel@tonic-gate 	if (xsum) {
8930Sstevel@tonic-gate 		/* not a label - checksum didn't compute */
8940Sstevel@tonic-gate 		goto nolabel;	/* no errors, but no label */
8950Sstevel@tonic-gate 	}
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	/*
8980Sstevel@tonic-gate 	 * the SunOS label overrides current diskette characteristics
8990Sstevel@tonic-gate 	 */
9000Sstevel@tonic-gate 	fjp->fj_chars->fdc_ncyl = label->dkl_pcyl;
9010Sstevel@tonic-gate 	fjp->fj_chars->fdc_nhead = label->dkl_nhead;
9020Sstevel@tonic-gate 	fjp->fj_chars->fdc_secptrack = (label->dkl_nsect * DEV_BSIZE) /
9030Sstevel@tonic-gate 	    fjp->fj_chars->fdc_sec_size;
9040Sstevel@tonic-gate 	if (defchar[fdp->d_deffdtype]->fdc_ncyl == 2 * fjp->fj_chars->fdc_ncyl)
9050Sstevel@tonic-gate 		fjp->fj_chars->fdc_steps = 2;
9060Sstevel@tonic-gate 	else
9070Sstevel@tonic-gate 		fjp->fj_chars->fdc_steps = 1;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	fjp->fj_attr->fda_rotatespd = label->dkl_rpm;
9100Sstevel@tonic-gate 	fjp->fj_attr->fda_intrlv = label->dkl_intrlv;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	fdp->d_vtoc_version = label->dkl_vtoc.v_version;
9130Sstevel@tonic-gate 	bcopy(label->dkl_vtoc.v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
9140Sstevel@tonic-gate 	bcopy(label->dkl_vtoc.v_asciilabel,
9150Sstevel@tonic-gate 	    fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
9160Sstevel@tonic-gate 	/*
9170Sstevel@tonic-gate 	 * logical partitions
9180Sstevel@tonic-gate 	 */
9190Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
9200Sstevel@tonic-gate 		fdp->d_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag;
9210Sstevel@tonic-gate 		fdp->d_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag;
9220Sstevel@tonic-gate 		fdp->d_part[i].p_start = label->dkl_vtoc.v_part[i].p_start;
9230Sstevel@tonic-gate 		fdp->d_part[i].p_size = label->dkl_vtoc.v_part[i].p_size;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 		fdp->d_vtoc_timestamp[i] = label->dkl_vtoc.timestamp[i];
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	fjp->fj_flags |= FUNIT_LABELOK;
9290Sstevel@tonic-gate 	goto out;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate nolabel:
9320Sstevel@tonic-gate 	/*
9330Sstevel@tonic-gate 	 * if not found, fill in label info from default (mark default used)
9340Sstevel@tonic-gate 	 */
9350Sstevel@tonic-gate 	if (fdp->d_media & (1<<FMT_3D))
9360Sstevel@tonic-gate 		newlabel = deflabel_35;
9370Sstevel@tonic-gate 	else /* if (fdp->d_media & (1<<FMT_5D9)) */
9380Sstevel@tonic-gate 		newlabel = deflabel_525;
9390Sstevel@tonic-gate 	bzero(fdp->d_vtoc_volume, LEN_DKL_VVOL);
9400Sstevel@tonic-gate 	(void) sprintf(fdp->d_vtoc_asciilabel, newlabel,
9410Sstevel@tonic-gate 	    fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_nhead,
9420Sstevel@tonic-gate 	    fjp->fj_chars->fdc_secptrack);
9430Sstevel@tonic-gate 	fjp->fj_flags |= FUNIT_UNLABELED;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate out:
9460Sstevel@tonic-gate 	kmem_free(label, sizeof (struct dk_label));
9470Sstevel@tonic-gate 	return (rval);
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate /*ARGSUSED*/
9520Sstevel@tonic-gate static int
fd_close(dev_t dev,int flag,int otyp,cred_t * cred_p)9530Sstevel@tonic-gate fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
9540Sstevel@tonic-gate {
9550Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
9560Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
9570Sstevel@tonic-gate 	int part, part_is_closed;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate #ifdef DEBUG
9600Sstevel@tonic-gate 	int unit;
9610Sstevel@tonic-gate #define	DEBUG_ASSIGN	unit=
9620Sstevel@tonic-gate #else
9630Sstevel@tonic-gate #define	DEBUG_ASSIGN	(void)
9640Sstevel@tonic-gate #endif
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	DEBUG_ASSIGN fd_getdrive(dev, &fjp, &fdp);
9670Sstevel@tonic-gate 	/*
9680Sstevel@tonic-gate 	 * Ignoring return in non DEBUG mode because success is checked by
9690Sstevel@tonic-gate 	 * verifying fjp and fdp and returned unit value is not used.
9700Sstevel@tonic-gate 	 */
9710Sstevel@tonic-gate 	if (!fjp || !fdp)
9720Sstevel@tonic-gate 		return (ENXIO);
9730Sstevel@tonic-gate 	part = PARTITION(dev);
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	sema_p(&fdp->d_ocsem);
9760Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_CLOS,
9770Sstevel@tonic-gate 	    (CE_CONT, "fd_close: fd unit %d part %d otype %x\n",
9780Sstevel@tonic-gate 	    unit, part, otyp));
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	if (otyp == OTYP_LYR) {
9810Sstevel@tonic-gate 		if (fdp->d_lyropen[part])
9820Sstevel@tonic-gate 			fdp->d_lyropen[part]--;
9830Sstevel@tonic-gate 		part_is_closed = (fdp->d_lyropen[part] == 0);
9840Sstevel@tonic-gate 	} else {
9850Sstevel@tonic-gate 		fdp->d_regopen[otyp] &= ~(1<<part);
9860Sstevel@tonic-gate 		part_is_closed = 1;
9870Sstevel@tonic-gate 	}
9880Sstevel@tonic-gate 	if (part_is_closed) {
9890Sstevel@tonic-gate 		if (part == 2 && fdp->d_exclmask&(1<<part))
9900Sstevel@tonic-gate 			fdp->d_exclmask = 0;
9910Sstevel@tonic-gate 		else
9920Sstevel@tonic-gate 			fdp->d_exclmask &= ~(1<<part);
9930Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_CLOS,
9940Sstevel@tonic-gate 		    (CE_CONT,
9950Sstevel@tonic-gate 		    "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n",
9960Sstevel@tonic-gate 		    fdp->d_exclmask, fdp->d_regopen[otyp],
9970Sstevel@tonic-gate 		    fdp->d_lyropen[part]));
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 		if (fd_unit_is_open(fdp) == 0)
10000Sstevel@tonic-gate 			fdp->d_obj->fj_flags &= ~FUNIT_CHANGED;
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 	sema_v(&fdp->d_ocsem);
10030Sstevel@tonic-gate 	return (0);
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate /* ARGSUSED */
10070Sstevel@tonic-gate static int
fd_read(dev_t dev,struct uio * uio,cred_t * cred_p)10080Sstevel@tonic-gate fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
10090Sstevel@tonic-gate {
10100Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate /* ARGSUSED */
10140Sstevel@tonic-gate static int
fd_write(dev_t dev,struct uio * uio,cred_t * cred_p)10150Sstevel@tonic-gate fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate 	return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate /*
10210Sstevel@tonic-gate  * fd_strategy
10220Sstevel@tonic-gate  *	checks operation, hangs buf struct off fdcntlr, calls fdstart
10230Sstevel@tonic-gate  *	if not already busy.  Note that if we call start, then the operation
10240Sstevel@tonic-gate  *	will already be done on return (start sleeps).
10250Sstevel@tonic-gate  */
10260Sstevel@tonic-gate static int
fd_strategy(struct buf * bp)10270Sstevel@tonic-gate fd_strategy(struct buf *bp)
10280Sstevel@tonic-gate {
10290Sstevel@tonic-gate 	struct fcu_obj *fjp;
10300Sstevel@tonic-gate 	struct fdisk *fdp;
10310Sstevel@tonic-gate 	struct partition *pp;
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_STRA,
10340Sstevel@tonic-gate 	    (CE_CONT, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
10350Sstevel@tonic-gate 	    (void *)bp, bp->b_edev));
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	(void) fd_getdrive(bp->b_edev, &fjp, &fdp);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	/*
10400Sstevel@tonic-gate 	 * Ignoring return because device exist.
10410Sstevel@tonic-gate 	 * Returned unit value is not used.
10420Sstevel@tonic-gate 	 */
10430Sstevel@tonic-gate 	pp = &fdp->d_part[PARTITION(bp->b_edev)];
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	if (fjp->fj_chars->fdc_sec_size > NBPSCTR && (bp->b_blkno & 1))  {
10460Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
10470Sstevel@tonic-gate 		    (CE_WARN, "fd%d: block %ld is not start of sector!",
10480Sstevel@tonic-gate 		    DRIVE(bp->b_edev), (long)bp->b_blkno));
10490Sstevel@tonic-gate 		bp->b_error = EINVAL;
10500Sstevel@tonic-gate 		goto bad;
10510Sstevel@tonic-gate 	}
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	if ((bp->b_blkno > pp->p_size)) {
10540Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
10550Sstevel@tonic-gate 		    (CE_WARN, "fd%d: block %ld is past the end! (nblk=%ld)",
10560Sstevel@tonic-gate 		    DRIVE(bp->b_edev), (long)bp->b_blkno, pp->p_size));
10570Sstevel@tonic-gate 		bp->b_error = ENOSPC;
10580Sstevel@tonic-gate 		goto bad;
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	/* if at end of file, skip out now */
10620Sstevel@tonic-gate 	if (bp->b_blkno == pp->p_size) {
10630Sstevel@tonic-gate 		if ((bp->b_flags & B_READ) == 0) {
10640Sstevel@tonic-gate 			/* a write needs to get an error! */
10650Sstevel@tonic-gate 			bp->b_error = ENOSPC;
10660Sstevel@tonic-gate 			goto bad;
10670Sstevel@tonic-gate 		}
10680Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
10690Sstevel@tonic-gate 		biodone(bp);
10700Sstevel@tonic-gate 		return (0);
10710Sstevel@tonic-gate 	}
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	/* if operation not a multiple of sector size, is error! */
10740Sstevel@tonic-gate 	if (bp->b_bcount % fjp->fj_chars->fdc_sec_size)  {
10750Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_STRA,
10760Sstevel@tonic-gate 		    (CE_WARN, "fd%d: count %ld must be a multiple of %d",
10770Sstevel@tonic-gate 		    DRIVE(bp->b_edev), bp->b_bcount,
10780Sstevel@tonic-gate 		    fjp->fj_chars->fdc_sec_size));
10790Sstevel@tonic-gate 		bp->b_error = EINVAL;
10800Sstevel@tonic-gate 		goto bad;
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	/*
10840Sstevel@tonic-gate 	 * Put the buf request in the drive's queue, FIFO.
10850Sstevel@tonic-gate 	 */
10860Sstevel@tonic-gate 	bp->av_forw = 0;
10870Sstevel@tonic-gate 	mutex_enter(&fjp->fj_lock);
10880Sstevel@tonic-gate 	if (fdp->d_iostat)
10890Sstevel@tonic-gate 		kstat_waitq_enter(KIOSP);
10900Sstevel@tonic-gate 	if (fdp->d_actf)
10910Sstevel@tonic-gate 		fdp->d_actl->av_forw = bp;
10920Sstevel@tonic-gate 	else
10930Sstevel@tonic-gate 		fdp->d_actf = bp;
10940Sstevel@tonic-gate 	fdp->d_actl = bp;
10950Sstevel@tonic-gate 	if (!(fjp->fj_flags & FUNIT_BUSY)) {
10960Sstevel@tonic-gate 		fdstart(fjp);
10970Sstevel@tonic-gate 	}
10980Sstevel@tonic-gate 	mutex_exit(&fjp->fj_lock);
10990Sstevel@tonic-gate 	return (0);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate bad:
11020Sstevel@tonic-gate 	bp->b_resid = bp->b_bcount;
11030Sstevel@tonic-gate 	bp->b_flags |= B_ERROR;
11040Sstevel@tonic-gate 	biodone(bp);
11050Sstevel@tonic-gate 	return (0);
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate /*
11090Sstevel@tonic-gate  * fdstart
11100Sstevel@tonic-gate  *	called from fd_strategy() or from fdXXXX() to setup and
11110Sstevel@tonic-gate  *	start operations of read or write only (using buf structs).
11120Sstevel@tonic-gate  *	Because the chip doesn't handle crossing cylinder boundaries on
11130Sstevel@tonic-gate  *	the fly, this takes care of those boundary conditions.  Note that
11140Sstevel@tonic-gate  *	it sleeps until the operation is done *within fdstart* - so that
11150Sstevel@tonic-gate  *	when fdstart returns, the operation is already done.
11160Sstevel@tonic-gate  */
11170Sstevel@tonic-gate static void
fdstart(struct fcu_obj * fjp)11180Sstevel@tonic-gate fdstart(struct fcu_obj *fjp)
11190Sstevel@tonic-gate {
11200Sstevel@tonic-gate 	struct buf *bp;
11210Sstevel@tonic-gate 	struct fdisk *fdp = (struct fdisk *)fjp->fj_data;
11220Sstevel@tonic-gate 	struct fd_char *chp;
11230Sstevel@tonic-gate 	struct partition *pp;
11240Sstevel@tonic-gate 	uint_t ptend;
11250Sstevel@tonic-gate 	uint_t bincyl;		/* (the number of the desired) block in cyl. */
11260Sstevel@tonic-gate 	uint_t blk, len, tlen;
11270Sstevel@tonic-gate 	uint_t secpcyl;		/* number of sectors per cylinder */
11280Sstevel@tonic-gate 	int cyl, head, sect;
11290Sstevel@tonic-gate 	int sctrshft, unit;
11300Sstevel@tonic-gate 	caddr_t	addr;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fjp->fj_lock));
11330Sstevel@tonic-gate 	fjp->fj_flags |= FUNIT_BUSY;
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	while ((bp = fdp->d_actf) != NULL) {
11360Sstevel@tonic-gate 		fdp->d_actf = bp->av_forw;
11370Sstevel@tonic-gate 		fdp->d_current = bp;
11380Sstevel@tonic-gate 		if (fdp->d_iostat) {
11390Sstevel@tonic-gate 			kstat_waitq_to_runq(KIOSP);
11400Sstevel@tonic-gate 		}
11410Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_STRT,
11440Sstevel@tonic-gate 		    (CE_CONT, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n",
11450Sstevel@tonic-gate 		    (void *)bp, (long)bp->b_blkno, bp->b_bcount));
11460Sstevel@tonic-gate 		bp->b_flags &= ~B_ERROR;
11470Sstevel@tonic-gate 		bp->b_error = 0;
11480Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;	/* init resid */
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 		ASSERT(DRIVE(bp->b_edev) == ddi_get_instance(fjp->fj_dip));
11510Sstevel@tonic-gate 		unit = fjp->fj_unit;
11520Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 		bp_mapin(bp);			/* map in buffers */
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 		pp = &fdp->d_part[PARTITION(bp->b_edev)];
11570Sstevel@tonic-gate 		/* starting blk adjusted for the partition */
11580Sstevel@tonic-gate 		blk = bp->b_blkno + pp->p_start;
11590Sstevel@tonic-gate 		ptend = pp->p_start + pp->p_size;   /* end of the partition */
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		chp = fjp->fj_chars;
11620Sstevel@tonic-gate 		secpcyl = chp->fdc_nhead * chp->fdc_secptrack;
11630Sstevel@tonic-gate 		switch (chp->fdc_sec_size) {
11640Sstevel@tonic-gate 		/* convert logical block numbers to sector numbers */
11650Sstevel@tonic-gate 		case 1024:
11660Sstevel@tonic-gate 			sctrshft = SCTRSHFT + 1;
11670Sstevel@tonic-gate 			blk >>= 1;
11680Sstevel@tonic-gate 			ptend >>= 1;
11690Sstevel@tonic-gate 			break;
11700Sstevel@tonic-gate 		default:
11710Sstevel@tonic-gate 		case NBPSCTR:
11720Sstevel@tonic-gate 			sctrshft = SCTRSHFT;
11730Sstevel@tonic-gate 			break;
11740Sstevel@tonic-gate 		case 256:
11750Sstevel@tonic-gate 			sctrshft = SCTRSHFT - 1;
11760Sstevel@tonic-gate 			blk <<= 1;
11770Sstevel@tonic-gate 			ptend <<= 1;
11780Sstevel@tonic-gate 			break;
11790Sstevel@tonic-gate 		}
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 		/*
11820Sstevel@tonic-gate 		 * If off the end, limit to actual amount that
11830Sstevel@tonic-gate 		 * can be transferred.
11840Sstevel@tonic-gate 		 */
11850Sstevel@tonic-gate 		if ((blk + (bp->b_bcount >> sctrshft)) > ptend)
11860Sstevel@tonic-gate 			/* to end of partition */
11870Sstevel@tonic-gate 			len = (ptend - blk) << sctrshft;
11880Sstevel@tonic-gate 		else
11890Sstevel@tonic-gate 			len = bp->b_bcount;
11900Sstevel@tonic-gate 		addr = bp->b_un.b_addr;		/* data buffer address */
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 		/*
11930Sstevel@tonic-gate 		 * now we have the real start blk, addr and len for xfer op
11940Sstevel@tonic-gate 		 */
11950Sstevel@tonic-gate 		while (len != 0) {
11960Sstevel@tonic-gate 			/* start cyl of req */
11970Sstevel@tonic-gate 			cyl = blk / secpcyl;
11980Sstevel@tonic-gate 			bincyl = blk % secpcyl;
11990Sstevel@tonic-gate 			/* start head of req */
12000Sstevel@tonic-gate 			head = bincyl / chp->fdc_secptrack;
12010Sstevel@tonic-gate 			/* start sector of req */
12020Sstevel@tonic-gate 			sect = (bincyl % chp->fdc_secptrack) + 1;
12030Sstevel@tonic-gate 			/*
12040Sstevel@tonic-gate 			 * If the desired block and length will go beyond the
12050Sstevel@tonic-gate 			 * cylinder end, then limit it to the cylinder end.
12060Sstevel@tonic-gate 			 */
12070Sstevel@tonic-gate 			if (bp->b_flags & B_READ) {
12080Sstevel@tonic-gate 				if (len > ((secpcyl - bincyl) << sctrshft))
12090Sstevel@tonic-gate 					tlen = (secpcyl - bincyl) << sctrshft;
12100Sstevel@tonic-gate 				else
12110Sstevel@tonic-gate 					tlen = len;
12120Sstevel@tonic-gate 			} else {
12130Sstevel@tonic-gate 				if (len >
12140Sstevel@tonic-gate 				    ((chp->fdc_secptrack - sect + 1) <<
12150Sstevel@tonic-gate 				    sctrshft))
12160Sstevel@tonic-gate 					tlen =
12170Sstevel@tonic-gate 					    (chp->fdc_secptrack - sect + 1) <<
12180Sstevel@tonic-gate 					    sctrshft;
12190Sstevel@tonic-gate 				else
12200Sstevel@tonic-gate 					tlen = len;
12210Sstevel@tonic-gate 			}
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 			FDERRPRINT(FDEP_L0, FDEM_STRT, (CE_CONT,
12240Sstevel@tonic-gate 			    "  blk 0x%x addr 0x%p len 0x%x "
12250Sstevel@tonic-gate 			    "cyl %d head %d sec %d\n  resid 0x%lx, tlen %d\n",
12260Sstevel@tonic-gate 			    blk, (void *)addr, len, cyl, head, sect,
12270Sstevel@tonic-gate 			    bp->b_resid, tlen));
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 			/*
12300Sstevel@tonic-gate 			 * (try to) do the operation - failure returns an errno
12310Sstevel@tonic-gate 			 */
12320Sstevel@tonic-gate 			bp->b_error = fjp->fj_ops->fco_rw(fjp, unit,
12330Sstevel@tonic-gate 			    bp->b_flags & B_READ, cyl, head, sect, addr, tlen);
12340Sstevel@tonic-gate 			if (bp->b_error != 0) {
12350Sstevel@tonic-gate 				FDERRPRINT(FDEP_L3, FDEM_STRT, (CE_WARN,
12360Sstevel@tonic-gate 				    "fdstart: bad exec of bp: 0x%p, err=%d",
12370Sstevel@tonic-gate 				    (void *)bp, bp->b_error));
12380Sstevel@tonic-gate 				bp->b_flags |= B_ERROR;
12390Sstevel@tonic-gate 				break;
12400Sstevel@tonic-gate 			}
12410Sstevel@tonic-gate 			blk += tlen >> sctrshft;
12420Sstevel@tonic-gate 			len -= tlen;
12430Sstevel@tonic-gate 			addr += tlen;
12440Sstevel@tonic-gate 			bp->b_resid -= tlen;
12450Sstevel@tonic-gate 		}
12460Sstevel@tonic-gate 		FDERRPRINT(FDEP_L0, FDEM_STRT,
12470Sstevel@tonic-gate 		    (CE_CONT, "fdstart done: b_resid %lu, b_count %lu\n",
12480Sstevel@tonic-gate 		    bp->b_resid, bp->b_bcount));
12490Sstevel@tonic-gate 		if (fdp->d_iostat) {
12500Sstevel@tonic-gate 			if (bp->b_flags & B_READ) {
12510Sstevel@tonic-gate 				KIOSP->reads++;
12520Sstevel@tonic-gate 				KIOSP->nread += (bp->b_bcount - bp->b_resid);
12530Sstevel@tonic-gate 			} else {
12540Sstevel@tonic-gate 				KIOSP->writes++;
12550Sstevel@tonic-gate 				KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
12560Sstevel@tonic-gate 			}
12570Sstevel@tonic-gate 			kstat_runq_exit(KIOSP);
12580Sstevel@tonic-gate 		}
12590Sstevel@tonic-gate 		bp_mapout(bp);
12600Sstevel@tonic-gate 		biodone(bp);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
12630Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
12640Sstevel@tonic-gate 		fdp->d_current = 0;
12650Sstevel@tonic-gate 	}
12660Sstevel@tonic-gate 	fjp->fj_flags ^= FUNIT_BUSY;
12670Sstevel@tonic-gate }
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate /* ARGSUSED */
12700Sstevel@tonic-gate static int
fd_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)12710Sstevel@tonic-gate fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
12720Sstevel@tonic-gate 	int *rval_p)
12730Sstevel@tonic-gate {
12740Sstevel@tonic-gate 	union {
12750Sstevel@tonic-gate 		struct dk_cinfo dki;
12760Sstevel@tonic-gate 		struct dk_geom dkg;
12770Sstevel@tonic-gate 		struct dk_allmap dka;
12780Sstevel@tonic-gate 		struct fd_char fdchar;
12790Sstevel@tonic-gate 		struct fd_drive drvchar;
12800Sstevel@tonic-gate 		int	temp;
12810Sstevel@tonic-gate 	} cpy;
12820Sstevel@tonic-gate 	struct vtoc vtoc;
12830Sstevel@tonic-gate 	struct fcu_obj *fjp = NULL;
12840Sstevel@tonic-gate 	struct fdisk *fdp = NULL;
12850Sstevel@tonic-gate 	struct dk_map *dmp;
12860Sstevel@tonic-gate 	struct dk_label *label;
12870Sstevel@tonic-gate 	int nblks, part, unit;
12880Sstevel@tonic-gate 	int rval = 0;
12890Sstevel@tonic-gate 	enum dkio_state state;
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	unit = fd_getdrive(dev, &fjp, &fdp);
12920Sstevel@tonic-gate 	if (!fjp || !fdp)
12930Sstevel@tonic-gate 		return (ENXIO);
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
12960Sstevel@tonic-gate 	    (CE_CONT, "fd_ioctl fd unit %d: cmd %x, arg %lx\n",
12970Sstevel@tonic-gate 	    unit, cmd, arg));
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	switch (cmd) {
13000Sstevel@tonic-gate 	case DKIOCINFO:
13010Sstevel@tonic-gate 		fjp->fj_ops->fco_dkinfo(fjp, &cpy.dki);
13020Sstevel@tonic-gate 		cpy.dki.dki_cnum = FDCTLR(fjp->fj_unit);
13030Sstevel@tonic-gate 		cpy.dki.dki_unit = FDUNIT(fjp->fj_unit);
13040Sstevel@tonic-gate 		cpy.dki.dki_partition = PARTITION(dev);
13050Sstevel@tonic-gate 		if (ddi_copyout(&cpy.dki, (void *)arg, sizeof (cpy.dki), flag))
13060Sstevel@tonic-gate 			rval = EFAULT;
13070Sstevel@tonic-gate 		break;
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	case DKIOCG_PHYGEOM:
13100Sstevel@tonic-gate 	case DKIOCG_VIRTGEOM:
13110Sstevel@tonic-gate 		cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
13120Sstevel@tonic-gate 		goto get_geom;
13130Sstevel@tonic-gate 	case DKIOCGGEOM:
13140Sstevel@tonic-gate 		if (fjp->fj_flags & FUNIT_LABELOK)
13150Sstevel@tonic-gate 			cpy.dkg.dkg_nsect = (fjp->fj_chars->fdc_secptrack *
13160Sstevel@tonic-gate 			    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
13170Sstevel@tonic-gate 		else
13180Sstevel@tonic-gate 			cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
13190Sstevel@tonic-gate get_geom:
13200Sstevel@tonic-gate 		cpy.dkg.dkg_pcyl = fjp->fj_chars->fdc_ncyl;
13210Sstevel@tonic-gate 		cpy.dkg.dkg_ncyl = fjp->fj_chars->fdc_ncyl;
13220Sstevel@tonic-gate 		cpy.dkg.dkg_nhead = fjp->fj_chars->fdc_nhead;
13230Sstevel@tonic-gate 		cpy.dkg.dkg_intrlv = fjp->fj_attr->fda_intrlv;
13240Sstevel@tonic-gate 		cpy.dkg.dkg_rpm = fjp->fj_attr->fda_rotatespd;
13250Sstevel@tonic-gate 		cpy.dkg.dkg_read_reinstruct =
13260Sstevel@tonic-gate 		    (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
13270Sstevel@tonic-gate 		cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
13280Sstevel@tonic-gate 		if (ddi_copyout(&cpy.dkg, (void *)arg, sizeof (cpy.dkg), flag))
13290Sstevel@tonic-gate 			rval = EFAULT;
13300Sstevel@tonic-gate 		break;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	case DKIOCSGEOM:
13330Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.dkg,
13340Sstevel@tonic-gate 		    sizeof (struct dk_geom), flag)) {
13350Sstevel@tonic-gate 			rval = EFAULT;
13360Sstevel@tonic-gate 			break;
13370Sstevel@tonic-gate 		}
13380Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
13390Sstevel@tonic-gate 		fjp->fj_chars->fdc_ncyl = cpy.dkg.dkg_ncyl;
13400Sstevel@tonic-gate 		fjp->fj_chars->fdc_nhead = cpy.dkg.dkg_nhead;
13410Sstevel@tonic-gate 		fjp->fj_chars->fdc_secptrack = cpy.dkg.dkg_nsect;
13420Sstevel@tonic-gate 		fjp->fj_attr->fda_intrlv = cpy.dkg.dkg_intrlv;
13430Sstevel@tonic-gate 		fjp->fj_attr->fda_rotatespd = cpy.dkg.dkg_rpm;
13440Sstevel@tonic-gate 		fdp->d_curfdtype = -1;
13450Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
13460Sstevel@tonic-gate 		break;
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	/*
13490Sstevel@tonic-gate 	 * return the map of all logical partitions
13500Sstevel@tonic-gate 	 */
13510Sstevel@tonic-gate 	case DKIOCGAPART:
13520Sstevel@tonic-gate 		/*
13530Sstevel@tonic-gate 		 * Note the conversion from starting sector number
13540Sstevel@tonic-gate 		 * to starting cylinder number.
13550Sstevel@tonic-gate 		 * Return error if division results in a remainder.
13560Sstevel@tonic-gate 		 */
13570Sstevel@tonic-gate 		nblks = fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack;
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
13600Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
13610Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
13620Sstevel@tonic-gate 		{
13630Sstevel@tonic-gate 			struct dk_allmap32 dka32;
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 			for (part = 0; part < NDKMAP; part++) {
13660Sstevel@tonic-gate 				if ((fdp->d_part[part].p_start % nblks) != 0)
13670Sstevel@tonic-gate 					return (EINVAL);
13680Sstevel@tonic-gate 				dka32.dka_map[part].dkl_cylno =
13690Sstevel@tonic-gate 				    fdp->d_part[part].p_start / nblks;
13700Sstevel@tonic-gate 				dka32.dka_map[part].dkl_nblk =
13710Sstevel@tonic-gate 				    fdp->d_part[part].p_size;
13720Sstevel@tonic-gate 			}
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 			if (ddi_copyout(&dka32, (void *)arg,
13750Sstevel@tonic-gate 			    sizeof (struct dk_allmap32), flag))
13760Sstevel@tonic-gate 				rval = EFAULT;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 			break;
13790Sstevel@tonic-gate 		}
13800Sstevel@tonic-gate 		case DDI_MODEL_NONE:
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 			dmp = (struct dk_map *)&cpy.dka;
13850Sstevel@tonic-gate 			for (part = 0; part < NDKMAP; part++) {
13860Sstevel@tonic-gate 				if ((fdp->d_part[part].p_start % nblks) != 0)
13870Sstevel@tonic-gate 					return (EINVAL);
13880Sstevel@tonic-gate 				dmp->dkl_cylno =
13890Sstevel@tonic-gate 				    fdp->d_part[part].p_start / nblks;
13900Sstevel@tonic-gate 				dmp->dkl_nblk = fdp->d_part[part].p_size;
13910Sstevel@tonic-gate 				dmp++;
13920Sstevel@tonic-gate 			}
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 			if (ddi_copyout(&cpy.dka, (void *)arg,
13950Sstevel@tonic-gate 			    sizeof (struct dk_allmap), flag))
13960Sstevel@tonic-gate 				rval = EFAULT;
13970Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
13980Sstevel@tonic-gate 			break;
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 		}
14010Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 		break;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	/*
14060Sstevel@tonic-gate 	 * Set the map of all logical partitions
14070Sstevel@tonic-gate 	 */
14080Sstevel@tonic-gate 	case DKIOCSAPART:
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
14110Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
14120Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
14130Sstevel@tonic-gate 		{
14140Sstevel@tonic-gate 			struct dk_allmap32 dka32;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &dka32,
14170Sstevel@tonic-gate 			    sizeof (dka32), flag)) {
14180Sstevel@tonic-gate 				rval = EFAULT;
14190Sstevel@tonic-gate 				break;
14200Sstevel@tonic-gate 			}
14210Sstevel@tonic-gate 			for (part = 0; part < NDKMAP; part++) {
14220Sstevel@tonic-gate 				cpy.dka.dka_map[part].dkl_cylno =
14230Sstevel@tonic-gate 				    dka32.dka_map[part].dkl_cylno;
14240Sstevel@tonic-gate 				cpy.dka.dka_map[part].dkl_nblk =
14250Sstevel@tonic-gate 				    dka32.dka_map[part].dkl_nblk;
14260Sstevel@tonic-gate 			}
14270Sstevel@tonic-gate 			break;
14280Sstevel@tonic-gate 		}
14290Sstevel@tonic-gate 		case DDI_MODEL_NONE:
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14320Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.dka, sizeof (cpy.dka), flag))
14330Sstevel@tonic-gate 			rval = EFAULT;
14340Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 			break;
14370Sstevel@tonic-gate 		}
14380Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 		if (rval != 0)
14410Sstevel@tonic-gate 			break;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 		dmp = (struct dk_map *)&cpy.dka;
14440Sstevel@tonic-gate 		nblks = fjp->fj_chars->fdc_nhead *
14450Sstevel@tonic-gate 		    fjp->fj_chars->fdc_secptrack;
14460Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
14470Sstevel@tonic-gate 		/*
14480Sstevel@tonic-gate 		 * Note the conversion from starting cylinder number
14490Sstevel@tonic-gate 		 * to starting sector number.
14500Sstevel@tonic-gate 		 */
14510Sstevel@tonic-gate 		for (part = 0; part < NDKMAP; part++) {
14520Sstevel@tonic-gate 			fdp->d_part[part].p_start = dmp->dkl_cylno *
14530Sstevel@tonic-gate 			    nblks;
14540Sstevel@tonic-gate 			fdp->d_part[part].p_size = dmp->dkl_nblk;
14550Sstevel@tonic-gate 			dmp++;
14560Sstevel@tonic-gate 		}
14570Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 		break;
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	case DKIOCGVTOC:
14620Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 		/*
14650Sstevel@tonic-gate 		 * Exit if the diskette has no label.
14660Sstevel@tonic-gate 		 * Also, get the label to make sure the correct one is
14670Sstevel@tonic-gate 		 * being used since the diskette may have changed
14680Sstevel@tonic-gate 		 */
14690Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
14700Sstevel@tonic-gate 		rval = fdgetlabel(fjp, unit);
14710Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
14720Sstevel@tonic-gate 		if (rval) {
14730Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
14740Sstevel@tonic-gate 			rval = EINVAL;
14750Sstevel@tonic-gate 			break;
14760Sstevel@tonic-gate 		}
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 		fd_build_user_vtoc(fjp, fdp, &vtoc);
14790Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
14820Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
14830Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
14840Sstevel@tonic-gate 		{
14850Sstevel@tonic-gate 			struct vtoc32	vtoc32;
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 			vtoctovtoc32(vtoc, vtoc32);
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 			if (ddi_copyout(&vtoc32, (void *)arg,
14900Sstevel@tonic-gate 			    sizeof (vtoc32), flag))
14910Sstevel@tonic-gate 				rval = EFAULT;
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 			break;
14940Sstevel@tonic-gate 		}
14950Sstevel@tonic-gate 		case DDI_MODEL_NONE:
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
14980Sstevel@tonic-gate 			if (ddi_copyout(&vtoc, (void *)arg,
14990Sstevel@tonic-gate 			    sizeof (vtoc), flag))
15000Sstevel@tonic-gate 				rval = EFAULT;
15010Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15020Sstevel@tonic-gate 			break;
15030Sstevel@tonic-gate 		}
15040Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 		break;
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 	case DKIOCSVTOC:
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15110Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
15120Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
15130Sstevel@tonic-gate 		{
15140Sstevel@tonic-gate 			struct vtoc32	vtoc32;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &vtoc32,
15170Sstevel@tonic-gate 			    sizeof (vtoc32), flag)) {
15180Sstevel@tonic-gate 				rval = EFAULT;
15190Sstevel@tonic-gate 				break;
15200Sstevel@tonic-gate 			}
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 			vtoc32tovtoc(vtoc32, vtoc);
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 			break;
15250Sstevel@tonic-gate 		}
15260Sstevel@tonic-gate 		case DDI_MODEL_NONE:
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
15290Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &vtoc, sizeof (vtoc), flag))
15300Sstevel@tonic-gate 				rval = EFAULT;
15310Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15320Sstevel@tonic-gate 			break;
15330Sstevel@tonic-gate 		}
15340Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 		if (rval != 0)
15370Sstevel@tonic-gate 			break;
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 		label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 		if ((rval = fd_build_label_vtoc(fjp, fdp, &vtoc, label)) == 0) {
15450Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 1);
15460Sstevel@tonic-gate 			rval = fjp->fj_ops->fco_rw(fjp, unit, FDWRITE,
15470Sstevel@tonic-gate 			    0, 0, 1, (caddr_t)label, sizeof (struct dk_label));
15480Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
15490Sstevel@tonic-gate 		}
15500Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
15510Sstevel@tonic-gate 		kmem_free(label, sizeof (struct dk_label));
15520Sstevel@tonic-gate 		break;
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	case DKIOCSTATE:
15550Sstevel@tonic-gate 		FDERRPRINT(FDEP_L1, FDEM_IOCT,
15560Sstevel@tonic-gate 		    (CE_CONT, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit));
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) {
15590Sstevel@tonic-gate 			rval = EFAULT;
15600Sstevel@tonic-gate 			break;
15610Sstevel@tonic-gate 		}
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 		rval = fd_check_media(dev, state);
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 		if (ddi_copyout(&fdp->d_media_state, (void *)arg,
15660Sstevel@tonic-gate 		    sizeof (int), flag))
15670Sstevel@tonic-gate 			rval = EFAULT;
15680Sstevel@tonic-gate 		break;
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	case FDIOGCHAR:
15710Sstevel@tonic-gate 		if (ddi_copyout(fjp->fj_chars, (void *)arg,
15720Sstevel@tonic-gate 		    sizeof (struct fd_char), flag))
15730Sstevel@tonic-gate 			rval = EFAULT;
15740Sstevel@tonic-gate 		break;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	case FDIOSCHAR:
15770Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.fdchar,
15780Sstevel@tonic-gate 		    sizeof (struct fd_char), flag)) {
15790Sstevel@tonic-gate 			rval = EFAULT;
15800Sstevel@tonic-gate 			break;
15810Sstevel@tonic-gate 		}
15820Sstevel@tonic-gate 		switch (cpy.fdchar.fdc_transfer_rate) {
15830Sstevel@tonic-gate 		case 417:
15840Sstevel@tonic-gate 			if ((fdp->d_media & (1 << FMT_3M)) == 0) {
15850Sstevel@tonic-gate 				cmn_err(CE_CONT,
15860Sstevel@tonic-gate 				    "fdioschar:Medium density not supported\n");
15870Sstevel@tonic-gate 				rval = EINVAL;
15880Sstevel@tonic-gate 				break;
15890Sstevel@tonic-gate 			}
15900Sstevel@tonic-gate 			mutex_enter(&fjp->fj_lock);
15910Sstevel@tonic-gate 			fjp->fj_attr->fda_rotatespd = 360;
15920Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
15930Sstevel@tonic-gate 			/* cpy.fdchar.fdc_transfer_rate = 500; */
15940Sstevel@tonic-gate 			/* FALLTHROUGH */
15950Sstevel@tonic-gate 		case 1000:
15960Sstevel@tonic-gate 		case 500:
15970Sstevel@tonic-gate 		case 300:
15980Sstevel@tonic-gate 		case 250:
15990Sstevel@tonic-gate 			mutex_enter(&fjp->fj_lock);
16000Sstevel@tonic-gate 			*(fjp->fj_chars) = cpy.fdchar;
16010Sstevel@tonic-gate 			fdp->d_curfdtype = -1;
16020Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHAROK;
16030Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 			break;
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 		default:
16080Sstevel@tonic-gate 			FDERRPRINT(FDEP_L4, FDEM_IOCT,
16090Sstevel@tonic-gate 			    (CE_WARN, "fd_ioctl fd unit %d: FDIOSCHAR odd "
16107656SSherry.Moore@Sun.COM 			    "xfer rate %dkbs",
16117656SSherry.Moore@Sun.COM 			    unit, cpy.fdchar.fdc_transfer_rate));
16120Sstevel@tonic-gate 			rval = EINVAL;
16130Sstevel@tonic-gate 			break;
16140Sstevel@tonic-gate 		}
16150Sstevel@tonic-gate 		break;
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	/*
16180Sstevel@tonic-gate 	 * set all characteristics and geometry to the defaults
16190Sstevel@tonic-gate 	 */
16200Sstevel@tonic-gate 	case FDDEFGEOCHAR:
16210Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
16220Sstevel@tonic-gate 		fdp->d_curfdtype = fdp->d_deffdtype;
16230Sstevel@tonic-gate 		*fjp->fj_chars = *defchar[fdp->d_curfdtype];
16240Sstevel@tonic-gate 		*fjp->fj_attr = fdtypes[fdp->d_curfdtype];
16250Sstevel@tonic-gate 		bcopy(fdparts[fdp->d_curfdtype],
16260Sstevel@tonic-gate 		    fdp->d_part, sizeof (struct partition) * NDKMAP);
16270Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHAROK;
16280Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
16290Sstevel@tonic-gate 		break;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	case FDEJECT:  /* eject disk */
16320Sstevel@tonic-gate 	case DKIOCEJECT:
16330Sstevel@tonic-gate 		fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
16340Sstevel@tonic-gate 		rval = ENOSYS;
16350Sstevel@tonic-gate 		break;
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	case FDGETCHANGE: /* disk changed */
16380Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.temp, sizeof (int), flag)) {
16390Sstevel@tonic-gate 			rval = EFAULT;
16400Sstevel@tonic-gate 			break;
16410Sstevel@tonic-gate 		}
16420Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
16430Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 		if (fjp->fj_flags & FUNIT_CHANGED)
16460Sstevel@tonic-gate 			cpy.temp |= FDGC_HISTORY;
16470Sstevel@tonic-gate 		else
16480Sstevel@tonic-gate 			cpy.temp &= ~FDGC_HISTORY;
16490Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHANGED;
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 		if (fjp->fj_ops->fco_getchng(fjp, unit)) {
16520Sstevel@tonic-gate 			cpy.temp |= FDGC_DETECTED;
16530Sstevel@tonic-gate 			fjp->fj_ops->fco_resetchng(fjp, unit);
16540Sstevel@tonic-gate 			/*
16550Sstevel@tonic-gate 			 * check diskette again only if it was removed
16560Sstevel@tonic-gate 			 */
16570Sstevel@tonic-gate 			if (fjp->fj_ops->fco_getchng(fjp, unit)) {
16580Sstevel@tonic-gate 				/*
16590Sstevel@tonic-gate 				 * no diskette is present
16600Sstevel@tonic-gate 				 */
16610Sstevel@tonic-gate 				cpy.temp |= FDGC_CURRENT;
16620Sstevel@tonic-gate 				if (fjp->fj_flags & FUNIT_CHGDET)
16630Sstevel@tonic-gate 					/*
16640Sstevel@tonic-gate 					 * again no diskette; not a new change
16650Sstevel@tonic-gate 					 */
16660Sstevel@tonic-gate 					cpy.temp ^= FDGC_DETECTED;
16670Sstevel@tonic-gate 				else
16680Sstevel@tonic-gate 					fjp->fj_flags |= FUNIT_CHGDET;
16690Sstevel@tonic-gate 			} else {
16700Sstevel@tonic-gate 				/*
16710Sstevel@tonic-gate 				 * a new diskette is present
16720Sstevel@tonic-gate 				 */
16730Sstevel@tonic-gate 				cpy.temp &= ~FDGC_CURRENT;
16740Sstevel@tonic-gate 				fjp->fj_flags &= ~FUNIT_CHGDET;
16750Sstevel@tonic-gate 			}
16760Sstevel@tonic-gate 		} else {
16770Sstevel@tonic-gate 			cpy.temp &= ~(FDGC_DETECTED | FDGC_CURRENT);
16780Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHGDET;
16790Sstevel@tonic-gate 		}
16800Sstevel@tonic-gate 		/*
16810Sstevel@tonic-gate 		 * also get state of write protection
16820Sstevel@tonic-gate 		 */
16830Sstevel@tonic-gate 		if (fjp->fj_flags & FUNIT_WPROT) {
16840Sstevel@tonic-gate 			cpy.temp |= FDGC_CURWPROT;
16850Sstevel@tonic-gate 		} else {
16860Sstevel@tonic-gate 			cpy.temp &= ~FDGC_CURWPROT;
16870Sstevel@tonic-gate 		}
16880Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
16890Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 		if (ddi_copyout(&cpy.temp, (void *)arg, sizeof (int), flag))
16920Sstevel@tonic-gate 			rval = EFAULT;
16930Sstevel@tonic-gate 		break;
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	case FDGETDRIVECHAR:
16960Sstevel@tonic-gate 		if (ddi_copyout(fjp->fj_drive, (void *)arg,
16970Sstevel@tonic-gate 		    sizeof (struct fd_drive), flag))
16980Sstevel@tonic-gate 			rval = EFAULT;
16990Sstevel@tonic-gate 		break;
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 	case FDSETDRIVECHAR:
17020Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &cpy.drvchar,
17030Sstevel@tonic-gate 		    sizeof (struct fd_drive), flag)) {
17040Sstevel@tonic-gate 			rval = EFAULT;
17050Sstevel@tonic-gate 			break;
17060Sstevel@tonic-gate 		}
17070Sstevel@tonic-gate 		mutex_enter(&fjp->fj_lock);
17080Sstevel@tonic-gate 		*(fjp->fj_drive) = cpy.drvchar;
17090Sstevel@tonic-gate 		fdp->d_curfdtype = -1;
17100Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHAROK;
17110Sstevel@tonic-gate 		mutex_exit(&fjp->fj_lock);
17120Sstevel@tonic-gate 		break;
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	case DKIOCREMOVABLE: {
17150Sstevel@tonic-gate 		int	i = 1;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 		/* no brainer: floppies are always removable */
17180Sstevel@tonic-gate 		if (ddi_copyout(&i, (void *)arg, sizeof (int), flag)) {
17190Sstevel@tonic-gate 			rval = EFAULT;
17200Sstevel@tonic-gate 		}
17210Sstevel@tonic-gate 		break;
17220Sstevel@tonic-gate 	}
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 	case DKIOCGMEDIAINFO:
17250Sstevel@tonic-gate 		rval = fd_get_media_info(fjp, (caddr_t)arg, flag);
17260Sstevel@tonic-gate 		break;
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	case FDIOCMD:
17290Sstevel@tonic-gate 	{
17300Sstevel@tonic-gate 		struct fd_cmd fc;
17310Sstevel@tonic-gate 		int cyl, head, spc, spt;
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
17340Sstevel@tonic-gate 		switch (ddi_model_convert_from(flag & FMODELS)) {
17350Sstevel@tonic-gate 		case DDI_MODEL_ILP32:
17360Sstevel@tonic-gate 		{
17370Sstevel@tonic-gate 			struct fd_cmd32 fc32;
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &fc32,
17400Sstevel@tonic-gate 			    sizeof (fc32), flag)) {
17410Sstevel@tonic-gate 				rval = EFAULT;
17420Sstevel@tonic-gate 				break;
17430Sstevel@tonic-gate 			}
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 			fc.fdc_cmd = fc32.fdc_cmd;
17460Sstevel@tonic-gate 			fc.fdc_flags = fc32.fdc_flags;
17470Sstevel@tonic-gate 			fc.fdc_blkno = fc32.fdc_blkno;
17480Sstevel@tonic-gate 			fc.fdc_secnt = fc32.fdc_secnt;
17490Sstevel@tonic-gate 			fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
17500Sstevel@tonic-gate 			fc.fdc_buflen = fc32.fdc_buflen;
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 			break;
17530Sstevel@tonic-gate 		}
17540Sstevel@tonic-gate 		case DDI_MODEL_NONE:
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 			if (ddi_copyin((void *)arg, &fc, sizeof (fc), flag)) {
17590Sstevel@tonic-gate 				rval = EFAULT;
17600Sstevel@tonic-gate 				break;
17610Sstevel@tonic-gate 			}
17620Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
17630Sstevel@tonic-gate 			break;
17640Sstevel@tonic-gate 		}
17650Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 		if (rval != 0)
17680Sstevel@tonic-gate 			break;
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
17710Sstevel@tonic-gate 			auto struct iovec aiov;
17720Sstevel@tonic-gate 			auto struct uio auio;
17730Sstevel@tonic-gate 			struct uio *uio = &auio;
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 			spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 			bzero(&auio, sizeof (struct uio));
17780Sstevel@tonic-gate 			bzero(&aiov, sizeof (struct iovec));
17790Sstevel@tonic-gate 			aiov.iov_base = fc.fdc_bufaddr;
17800Sstevel@tonic-gate 			aiov.iov_len = (uint_t)fc.fdc_secnt *
17810Sstevel@tonic-gate 			    fjp->fj_chars->fdc_sec_size;
17820Sstevel@tonic-gate 			uio->uio_iov = &aiov;
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 			uio->uio_iovcnt = 1;
17850Sstevel@tonic-gate 			uio->uio_resid = aiov.iov_len;
17860Sstevel@tonic-gate 			uio->uio_segflg = UIO_USERSPACE;
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 			rval = physio(fd_strategy, (struct buf *)0, dev,
17890Sstevel@tonic-gate 			    spc, minphys, uio);
17900Sstevel@tonic-gate 			break;
17910Sstevel@tonic-gate 		} else if (fc.fdc_cmd == FDCMD_FORMAT_TRACK) {
17920Sstevel@tonic-gate 			spt = fjp->fj_chars->fdc_secptrack;	/* sec/trk */
17930Sstevel@tonic-gate 			spc = fjp->fj_chars->fdc_nhead * spt;	/* sec/cyl */
17940Sstevel@tonic-gate 			cyl = fc.fdc_blkno / spc;
17950Sstevel@tonic-gate 			head = (fc.fdc_blkno % spc) / spt;
17960Sstevel@tonic-gate 			if ((cyl | head) == 0)
17970Sstevel@tonic-gate 				fjp->fj_flags &=
17980Sstevel@tonic-gate 				    ~(FUNIT_LABELOK | FUNIT_UNLABELED);
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 			FDERRPRINT(FDEP_L0, FDEM_FORM,
18010Sstevel@tonic-gate 			    (CE_CONT, "fd_format cyl %d, hd %d\n", cyl, head));
18020Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 1);
18030Sstevel@tonic-gate 			rval = fjp->fj_ops->fco_format(fjp, unit, cyl, head,
18040Sstevel@tonic-gate 			    (int)fc.fdc_flags);
18050Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 			break;
18080Sstevel@tonic-gate 		}
18090Sstevel@tonic-gate 		FDERRPRINT(FDEP_L4, FDEM_IOCT,
18100Sstevel@tonic-gate 		    (CE_WARN, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete",
18110Sstevel@tonic-gate 		    unit));
18120Sstevel@tonic-gate 		rval = EINVAL;
18130Sstevel@tonic-gate 		break;
18140Sstevel@tonic-gate 	}
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 	case FDRAW:
18170Sstevel@tonic-gate 		rval = fd_rawioctl(fjp, unit, (caddr_t)arg, flag);
18180Sstevel@tonic-gate 		break;
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 	default:
18210Sstevel@tonic-gate 		FDERRPRINT(FDEP_L4, FDEM_IOCT,
18220Sstevel@tonic-gate 		    (CE_WARN, "fd_ioctl fd unit %d: invalid ioctl 0x%x",
18230Sstevel@tonic-gate 		    unit, cmd));
18240Sstevel@tonic-gate 		rval = ENOTTY;
18250Sstevel@tonic-gate 		break;
18260Sstevel@tonic-gate 	}
18270Sstevel@tonic-gate 	return (rval);
18280Sstevel@tonic-gate }
18290Sstevel@tonic-gate 
18300Sstevel@tonic-gate static void
fd_build_user_vtoc(struct fcu_obj * fjp,struct fdisk * fdp,struct vtoc * vtocp)18310Sstevel@tonic-gate fd_build_user_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp)
18320Sstevel@tonic-gate {
18330Sstevel@tonic-gate 	struct partition *vpart;
18340Sstevel@tonic-gate 	int	i;
18350Sstevel@tonic-gate 	int	xblk;
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	/*
18380Sstevel@tonic-gate 	 * Return vtoc structure fields in the provided VTOC area, addressed
18390Sstevel@tonic-gate 	 * by *vtocp.
18400Sstevel@tonic-gate 	 *
18410Sstevel@tonic-gate 	 */
18420Sstevel@tonic-gate 	bzero(vtocp, sizeof (struct vtoc));
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_bootinfo,
18450Sstevel@tonic-gate 	    vtocp->v_bootinfo, sizeof (vtocp->v_bootinfo));
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	vtocp->v_sanity = VTOC_SANE;
18480Sstevel@tonic-gate 	vtocp->v_version = fdp->d_vtoc_version;
18490Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_volume, vtocp->v_volume, LEN_DKL_VVOL);
18500Sstevel@tonic-gate 	if (fjp->fj_flags & FUNIT_LABELOK) {
18510Sstevel@tonic-gate 		vtocp->v_sectorsz = DEV_BSIZE;
18520Sstevel@tonic-gate 		xblk = 1;
18530Sstevel@tonic-gate 	} else {
18540Sstevel@tonic-gate 		vtocp->v_sectorsz = fjp->fj_chars->fdc_sec_size;
18550Sstevel@tonic-gate 		xblk = vtocp->v_sectorsz / DEV_BSIZE;
18560Sstevel@tonic-gate 	}
18570Sstevel@tonic-gate 	vtocp->v_nparts = 3;	/* <= NDKMAP;	*/
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	/*
18600Sstevel@tonic-gate 	 * Copy partitioning information.
18610Sstevel@tonic-gate 	 */
18620Sstevel@tonic-gate 	bcopy(fdp->d_part, vtocp->v_part, sizeof (struct partition) * NDKMAP);
18630Sstevel@tonic-gate 	for (i = NDKMAP, vpart = vtocp->v_part; i && (xblk > 1); i--, vpart++) {
18640Sstevel@tonic-gate 		/* correct partition info if sector size > 512 bytes */
18650Sstevel@tonic-gate 		vpart->p_start /= xblk;
18660Sstevel@tonic-gate 		vpart->p_size /= xblk;
18670Sstevel@tonic-gate 	}
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_timestamp,
18700Sstevel@tonic-gate 	    vtocp->timestamp, sizeof (fdp->d_vtoc_timestamp));
18710Sstevel@tonic-gate 	bcopy(fdp->d_vtoc_asciilabel, vtocp->v_asciilabel, LEN_DKL_ASCII);
18720Sstevel@tonic-gate }
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate static int
fd_build_label_vtoc(struct fcu_obj * fjp,struct fdisk * fdp,struct vtoc * vtocp,struct dk_label * labelp)18760Sstevel@tonic-gate fd_build_label_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp,
18770Sstevel@tonic-gate     struct dk_label *labelp)
18780Sstevel@tonic-gate {
18790Sstevel@tonic-gate 	struct partition *vpart;
18800Sstevel@tonic-gate 	int	i;
18810Sstevel@tonic-gate 	int	nblks;
18820Sstevel@tonic-gate 	int	ncyl;
18830Sstevel@tonic-gate 	ushort_t sum, *sp;
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	/*
18870Sstevel@tonic-gate 	 * Sanity-check the vtoc
18880Sstevel@tonic-gate 	 */
18890Sstevel@tonic-gate 	if (vtocp->v_sanity != VTOC_SANE ||
18900Sstevel@tonic-gate 	    vtocp->v_nparts > NDKMAP || vtocp->v_nparts <= 0) {
18910Sstevel@tonic-gate 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
18920Sstevel@tonic-gate 		    (CE_WARN, "fd_build_label:  sanity check on vtoc failed"));
18930Sstevel@tonic-gate 		return (EINVAL);
18940Sstevel@tonic-gate 	}
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	/*
18970Sstevel@tonic-gate 	 * before copying the vtoc, the partition information in it should be
18980Sstevel@tonic-gate 	 * checked against the information the driver already has on the
18990Sstevel@tonic-gate 	 * diskette.
19000Sstevel@tonic-gate 	 */
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	nblks = (fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack *
19037656SSherry.Moore@Sun.COM 	    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
19040Sstevel@tonic-gate 	if (nblks == 0 || fjp->fj_chars->fdc_ncyl == 0)
19050Sstevel@tonic-gate 		return (EFAULT);
19060Sstevel@tonic-gate 	vpart = vtocp->v_part;
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	/*
19090Sstevel@tonic-gate 	 * Check the partition information in the vtoc.  The starting sectors
19100Sstevel@tonic-gate 	 * must lie along cylinder boundaries. (NDKMAP entries are checked
19110Sstevel@tonic-gate 	 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
19120Sstevel@tonic-gate 	 * is less than NDKMAP)
19130Sstevel@tonic-gate 	 */
19140Sstevel@tonic-gate 	for (i = NDKMAP; i; i--) {
19150Sstevel@tonic-gate 		if ((vpart->p_start % nblks) != 0) {
19160Sstevel@tonic-gate 			return (EINVAL);
19170Sstevel@tonic-gate 		}
19180Sstevel@tonic-gate 		ncyl = vpart->p_start / nblks;
19190Sstevel@tonic-gate 		ncyl += vpart->p_size / nblks;
19200Sstevel@tonic-gate 		if ((vpart->p_size % nblks) != 0)
19210Sstevel@tonic-gate 			ncyl++;
19220Sstevel@tonic-gate 		if (ncyl > (long)fjp->fj_chars->fdc_ncyl) {
19230Sstevel@tonic-gate 			return (EINVAL);
19240Sstevel@tonic-gate 		}
19250Sstevel@tonic-gate 		vpart++;
19260Sstevel@tonic-gate 	}
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	bcopy(vtocp->v_bootinfo, fdp->d_vtoc_bootinfo,
19300Sstevel@tonic-gate 	    sizeof (vtocp->v_bootinfo));
19310Sstevel@tonic-gate 	fdp->d_vtoc_version = vtocp->v_version;
19320Sstevel@tonic-gate 	bcopy(vtocp->v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	/*
19350Sstevel@tonic-gate 	 * Copy partitioning information.
19360Sstevel@tonic-gate 	 */
19370Sstevel@tonic-gate 	bcopy(vtocp->v_part, fdp->d_part, sizeof (struct partition) * NDKMAP);
19380Sstevel@tonic-gate 	bcopy(vtocp->timestamp, fdp->d_vtoc_timestamp,
19390Sstevel@tonic-gate 	    sizeof (fdp->d_vtoc_timestamp));
19400Sstevel@tonic-gate 	bcopy(vtocp->v_asciilabel, fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	/*
19430Sstevel@tonic-gate 	 * construct the diskette label in supplied buffer
19440Sstevel@tonic-gate 	 */
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	/* Put appropriate vtoc structure fields into the disk label */
19470Sstevel@tonic-gate 	labelp->dkl_vtoc.v_bootinfo[0] = (uint32_t)vtocp->v_bootinfo[0];
19480Sstevel@tonic-gate 	labelp->dkl_vtoc.v_bootinfo[1] = (uint32_t)vtocp->v_bootinfo[1];
19490Sstevel@tonic-gate 	labelp->dkl_vtoc.v_bootinfo[2] = (uint32_t)vtocp->v_bootinfo[2];
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	labelp->dkl_vtoc.v_sanity = vtocp->v_sanity;
19520Sstevel@tonic-gate 	labelp->dkl_vtoc.v_version = vtocp->v_version;
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 	bcopy(vtocp->v_volume, labelp->dkl_vtoc.v_volume, LEN_DKL_VVOL);
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	labelp->dkl_vtoc.v_nparts = vtocp->v_nparts;
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 	bcopy(vtocp->v_reserved, labelp->dkl_vtoc.v_reserved,
19590Sstevel@tonic-gate 	    sizeof (labelp->dkl_vtoc.v_reserved));
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	for (i = 0; i < (int)vtocp->v_nparts; i++) {
19620Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_tag  = vtocp->v_part[i].p_tag;
19630Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_flag  = vtocp->v_part[i].p_flag;
19640Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_start  = vtocp->v_part[i].p_start;
19650Sstevel@tonic-gate 		labelp->dkl_vtoc.v_part[i].p_size  = vtocp->v_part[i].p_size;
19660Sstevel@tonic-gate 	}
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 	for (i = 0; i < NDKMAP; i++) {
19690Sstevel@tonic-gate 		labelp->dkl_vtoc.v_timestamp[i] = vtocp->timestamp[i];
19700Sstevel@tonic-gate 	}
19710Sstevel@tonic-gate 	bcopy(vtocp->v_asciilabel, labelp->dkl_asciilabel, LEN_DKL_ASCII);
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	labelp->dkl_pcyl = fjp->fj_chars->fdc_ncyl;
19750Sstevel@tonic-gate 	labelp->dkl_ncyl = fjp->fj_chars->fdc_ncyl;
19760Sstevel@tonic-gate 	labelp->dkl_nhead = fjp->fj_chars->fdc_nhead;
19770Sstevel@tonic-gate 	/*
19780Sstevel@tonic-gate 	 * The fdc_secptrack field of the fd_char structure is the number
19790Sstevel@tonic-gate 	 * of sectors per track where the sectors are fdc_sec_size.
19800Sstevel@tonic-gate 	 * The dkl_nsect field of the dk_label structure is the number of
19810Sstevel@tonic-gate 	 * DEV_BSIZE (512) byte sectors per track.
19820Sstevel@tonic-gate 	 */
19830Sstevel@tonic-gate 	labelp->dkl_nsect = (fjp->fj_chars->fdc_secptrack *
19840Sstevel@tonic-gate 	    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
19850Sstevel@tonic-gate 	labelp->dkl_intrlv = fjp->fj_attr->fda_intrlv;
19860Sstevel@tonic-gate 	labelp->dkl_rpm = fjp->fj_attr->fda_rotatespd;
19870Sstevel@tonic-gate 	labelp->dkl_read_reinstruct =
19880Sstevel@tonic-gate 	    (int)(labelp->dkl_nsect * labelp->dkl_rpm * 4) / 60000;
19890Sstevel@tonic-gate 	labelp->dkl_write_reinstruct = labelp->dkl_read_reinstruct;
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 	labelp->dkl_magic = DKL_MAGIC;
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate 	sum = 0;
19940Sstevel@tonic-gate 	labelp->dkl_cksum = 0;
19950Sstevel@tonic-gate 	sp = (ushort_t *)labelp;
19960Sstevel@tonic-gate 	while (sp < &(labelp->dkl_cksum)) {
19970Sstevel@tonic-gate 		sum ^= *sp++;
19980Sstevel@tonic-gate 	}
19990Sstevel@tonic-gate 	labelp->dkl_cksum = sum;
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate 	return (0);
20020Sstevel@tonic-gate }
20030Sstevel@tonic-gate 
20040Sstevel@tonic-gate static int
fd_rawioctl(struct fcu_obj * fjp,int unit,caddr_t arg,int mode)20050Sstevel@tonic-gate fd_rawioctl(struct fcu_obj *fjp, int unit, caddr_t arg, int mode)
20060Sstevel@tonic-gate {
20070Sstevel@tonic-gate 	struct fd_raw fdr;
20080Sstevel@tonic-gate 	char *arg_result = NULL;
20090Sstevel@tonic-gate 	int flag = B_READ;
20100Sstevel@tonic-gate 	int rval = 0;
20110Sstevel@tonic-gate 	caddr_t	uaddr;
20120Sstevel@tonic-gate 	uint_t ucount;
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
20150Sstevel@tonic-gate 	    (CE_CONT, "fd_rawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	if (fjp->fj_chars->fdc_medium != 3 && fjp->fj_chars->fdc_medium != 5) {
20180Sstevel@tonic-gate 		cmn_err(CE_CONT, "fd_rawioctl: Medium density not supported\n");
20190Sstevel@tonic-gate 		return (ENXIO);
20200Sstevel@tonic-gate 	}
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20230Sstevel@tonic-gate 	switch (ddi_model_convert_from(mode & FMODELS)) {
20240Sstevel@tonic-gate 	case DDI_MODEL_ILP32:
20250Sstevel@tonic-gate 	{
20260Sstevel@tonic-gate 		struct fd_raw32 fdr32;
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 		if (ddi_copyin(arg, &fdr32, sizeof (fdr32), mode))
20290Sstevel@tonic-gate 			return (EFAULT);
20300Sstevel@tonic-gate 
20310Sstevel@tonic-gate 		bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
20320Sstevel@tonic-gate 		fdr.fdr_cnum = fdr32.fdr_cnum;
20330Sstevel@tonic-gate 		fdr.fdr_nbytes = fdr32.fdr_nbytes;
20340Sstevel@tonic-gate 		fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
20350Sstevel@tonic-gate 		arg_result = ((struct fd_raw32 *)arg)->fdr_result;
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate 		break;
20380Sstevel@tonic-gate 	}
20390Sstevel@tonic-gate 	case DDI_MODEL_NONE:
20400Sstevel@tonic-gate #endif /* ! _MULTI_DATAMODEL */
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 		if (ddi_copyin(arg, &fdr, sizeof (fdr), mode))
20430Sstevel@tonic-gate 			return (EFAULT);
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 		arg_result = ((struct fd_raw *)arg)->fdr_result;
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
20480Sstevel@tonic-gate 		break;
20490Sstevel@tonic-gate 	}
20500Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate 	/*
20550Sstevel@tonic-gate 	 * copy user address & nbytes from raw_req so that we can
20560Sstevel@tonic-gate 	 * put kernel address in req structure
20570Sstevel@tonic-gate 	 */
20580Sstevel@tonic-gate 	uaddr = fdr.fdr_addr;
20590Sstevel@tonic-gate 	ucount = (uint_t)fdr.fdr_nbytes;
20600Sstevel@tonic-gate 	unit &= 3;
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	switch (fdr.fdr_cmd[0] & 0x0f) {
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 	case FDRAW_FORMAT:
20650Sstevel@tonic-gate 		ucount += 16;
20660Sstevel@tonic-gate 		fdr.fdr_addr = kmem_zalloc(ucount, KM_SLEEP);
20670Sstevel@tonic-gate 		if (ddi_copyin(uaddr, fdr.fdr_addr,
20680Sstevel@tonic-gate 		    (size_t)fdr.fdr_nbytes, mode)) {
20690Sstevel@tonic-gate 			kmem_free(fdr.fdr_addr, ucount);
20700Sstevel@tonic-gate 			return (EFAULT);
20710Sstevel@tonic-gate 		}
20720Sstevel@tonic-gate 		if ((*fdr.fdr_addr | fdr.fdr_addr[1]) == 0)
20730Sstevel@tonic-gate 			fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
20740Sstevel@tonic-gate 		flag = B_WRITE;
20750Sstevel@tonic-gate 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
20760Sstevel@tonic-gate 		break;
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	case FDRAW_WRCMD:
20790Sstevel@tonic-gate 	case FDRAW_WRITEDEL:
20800Sstevel@tonic-gate 		flag = B_WRITE;
20810Sstevel@tonic-gate 		/* FALLTHROUGH */
20820Sstevel@tonic-gate 	case FDRAW_RDCMD:
20830Sstevel@tonic-gate 	case FDRAW_READDEL:
20840Sstevel@tonic-gate 	case FDRAW_READTRACK:
20850Sstevel@tonic-gate 		if (ucount) {
20860Sstevel@tonic-gate 			/*
20870Sstevel@tonic-gate 			 * In SunOS 4.X, we used to as_fault things in.
20880Sstevel@tonic-gate 			 * We really cannot do this in 5.0/SVr4. Unless
20890Sstevel@tonic-gate 			 * someone really believes that speed is of the
20900Sstevel@tonic-gate 			 * essence here, it is just much simpler to do
20910Sstevel@tonic-gate 			 * this in kernel space and use copyin/copyout.
20920Sstevel@tonic-gate 			 */
20930Sstevel@tonic-gate 			fdr.fdr_addr = kmem_alloc((size_t)ucount, KM_SLEEP);
20940Sstevel@tonic-gate 			if (flag == B_WRITE) {
20950Sstevel@tonic-gate 				if (ddi_copyin(uaddr, fdr.fdr_addr, ucount,
20960Sstevel@tonic-gate 				    mode)) {
20970Sstevel@tonic-gate 					kmem_free(fdr.fdr_addr, ucount);
20980Sstevel@tonic-gate 					return (EFAULT);
20990Sstevel@tonic-gate 				}
21000Sstevel@tonic-gate 			}
21010Sstevel@tonic-gate 		} else
21020Sstevel@tonic-gate 			return (EINVAL);
21030Sstevel@tonic-gate 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
21040Sstevel@tonic-gate 		break;
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	case FDRAW_READID:
21070Sstevel@tonic-gate 	case FDRAW_REZERO:
21080Sstevel@tonic-gate 	case FDRAW_SEEK:
21090Sstevel@tonic-gate 	case FDRAW_SENSE_DRV:
21100Sstevel@tonic-gate 		ucount = 0;
21110Sstevel@tonic-gate 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
21120Sstevel@tonic-gate 		break;
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate 	case FDRAW_SPECIFY:
21150Sstevel@tonic-gate 		fdr.fdr_cmd[2] &= 0xfe;	/* keep NoDMA bit clear */
21160Sstevel@tonic-gate 		/* FALLTHROUGH */
21170Sstevel@tonic-gate 	case FDRAW_SENSE_INT:
21180Sstevel@tonic-gate 		ucount = 0;
21190Sstevel@tonic-gate 		break;
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 	default:
21220Sstevel@tonic-gate 		return (EINVAL);
21230Sstevel@tonic-gate 	}
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 	/*
21260Sstevel@tonic-gate 	 * Note that we ignore any error returns from controller
21270Sstevel@tonic-gate 	 * This is the way the driver has been, and it may be
21280Sstevel@tonic-gate 	 * that the raw ioctl senders simply don't want to
21290Sstevel@tonic-gate 	 * see any errors returned in this fashion.
21300Sstevel@tonic-gate 	 */
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 1);
21330Sstevel@tonic-gate 	rval = fjp->fj_ops->fco_rwioctl(fjp, unit, (caddr_t)&fdr);
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 	if (ucount && flag == B_READ && rval == 0) {
21360Sstevel@tonic-gate 		if (ddi_copyout(fdr.fdr_addr, uaddr, ucount, mode)) {
21370Sstevel@tonic-gate 			rval = EFAULT;
21380Sstevel@tonic-gate 		}
21390Sstevel@tonic-gate 	}
21400Sstevel@tonic-gate 	if (ddi_copyout(fdr.fdr_result, arg_result, sizeof (fdr.fdr_cmd), mode))
21410Sstevel@tonic-gate 		rval = EFAULT;
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 0);
21440Sstevel@tonic-gate 	if (ucount)
21450Sstevel@tonic-gate 		kmem_free(fdr.fdr_addr, ucount);
21460Sstevel@tonic-gate 
21470Sstevel@tonic-gate 	return (rval);
21480Sstevel@tonic-gate }
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate /*
21510Sstevel@tonic-gate  * property operation routine.  return the number of blocks for the partition
21520Sstevel@tonic-gate  * in question or forward the request to the property facilities.
21530Sstevel@tonic-gate  */
21540Sstevel@tonic-gate static int
fd_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)21550Sstevel@tonic-gate fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
21560Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
21570Sstevel@tonic-gate {
21580Sstevel@tonic-gate 	struct fcu_obj	*fjp = NULL;
21590Sstevel@tonic-gate 	struct fdisk	*fdp = NULL;
21600Sstevel@tonic-gate 	uint64_t	nblocks64;
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 	FDERRPRINT(FDEP_L1, FDEM_PROP,
21630Sstevel@tonic-gate 	    (CE_CONT, "fd_prop_op: dip %p %s\n", (void *)dip, name));
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	/*
21660Sstevel@tonic-gate 	 * Our dynamic properties are all device specific and size oriented.
21670Sstevel@tonic-gate 	 * Requests issued under conditions where size is valid are passed
21680Sstevel@tonic-gate 	 * to ddi_prop_op_nblocks with the size information, otherwise the
21690Sstevel@tonic-gate 	 * request is passed to ddi_prop_op.
21700Sstevel@tonic-gate 	 */
21710Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY) {
21720Sstevel@tonic-gate pass:  		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
21730Sstevel@tonic-gate 		    name, valuep, lengthp));
21740Sstevel@tonic-gate 	} else {
21750Sstevel@tonic-gate 		/*
21760Sstevel@tonic-gate 		 * Ignoring return value because success is checked by
21770Sstevel@tonic-gate 		 * verifying fjp and fdp and returned unit value is not used.
21780Sstevel@tonic-gate 		 */
21790Sstevel@tonic-gate 		(void) fd_getdrive(dev, &fjp, &fdp);
21800Sstevel@tonic-gate 		if (!fjp || !fdp)
21810Sstevel@tonic-gate 			goto pass;
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 		/* get nblocks value */
21840Sstevel@tonic-gate 		nblocks64 = (ulong_t)fdp->d_part[PARTITION(dev)].p_size;
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 		return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
21870Sstevel@tonic-gate 		    name, valuep, lengthp, nblocks64));
21880Sstevel@tonic-gate 	}
21890Sstevel@tonic-gate }
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate static void
fd_media_watch(void * arg)21920Sstevel@tonic-gate fd_media_watch(void *arg)
21930Sstevel@tonic-gate {
21940Sstevel@tonic-gate 	struct fcu_obj *fjp;
21950Sstevel@tonic-gate 	struct fdisk *fdp;
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate #ifdef DEBUG
21980Sstevel@tonic-gate 	int	unit;
21990Sstevel@tonic-gate #define	DEBUG_ASSIGN	unit=
22000Sstevel@tonic-gate #else
22010Sstevel@tonic-gate #define	DEBUG_ASSIGN	(void)
22020Sstevel@tonic-gate #endif
22030Sstevel@tonic-gate 	DEBUG_ASSIGN fd_getdrive((dev_t)arg, &fjp, &fdp);
22040Sstevel@tonic-gate 	/*
22050Sstevel@tonic-gate 	 * Ignoring return in non DEBUG mode because device exist.
22060Sstevel@tonic-gate 	 * Returned unit value is not used.
22070Sstevel@tonic-gate 	 */
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_IOCT,
22100Sstevel@tonic-gate 	    (CE_CONT, "fd_media_watch unit %d\n", unit));
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 	/*
22130Sstevel@tonic-gate 	 * fd_get_media_state() cannot be called from this timeout function
22140Sstevel@tonic-gate 	 * because the  floppy drive has to be selected first, and that could
22150Sstevel@tonic-gate 	 * force this function to sleep (while waiting for the select
22160Sstevel@tonic-gate 	 * semaphore).
22170Sstevel@tonic-gate 	 * Instead, just wakeup up driver.
22180Sstevel@tonic-gate 	 */
22190Sstevel@tonic-gate 	mutex_enter(&fjp->fj_lock);
22200Sstevel@tonic-gate 	cv_broadcast(&fdp->d_statecv);
22210Sstevel@tonic-gate 	mutex_exit(&fjp->fj_lock);
22220Sstevel@tonic-gate }
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate enum dkio_state
fd_get_media_state(struct fcu_obj * fjp,int unit)22250Sstevel@tonic-gate fd_get_media_state(struct fcu_obj *fjp, int unit)
22260Sstevel@tonic-gate {
22270Sstevel@tonic-gate 	enum dkio_state state;
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 	if (fjp->fj_ops->fco_getchng(fjp, unit)) {
22300Sstevel@tonic-gate 		/* recheck disk only if DSKCHG "high" */
22310Sstevel@tonic-gate 		fjp->fj_ops->fco_resetchng(fjp, unit);
22320Sstevel@tonic-gate 		if (fjp->fj_ops->fco_getchng(fjp, unit)) {
22330Sstevel@tonic-gate 			if (fjp->fj_flags & FUNIT_CHGDET) {
22340Sstevel@tonic-gate 				/*
22350Sstevel@tonic-gate 				 * again no diskette; not a new change
22360Sstevel@tonic-gate 				 */
22370Sstevel@tonic-gate 				state = DKIO_NONE;
22380Sstevel@tonic-gate 			} else {
22390Sstevel@tonic-gate 				/*
22400Sstevel@tonic-gate 				 * a new change; diskette was ejected
22410Sstevel@tonic-gate 				 */
22420Sstevel@tonic-gate 				fjp->fj_flags |= FUNIT_CHGDET;
22430Sstevel@tonic-gate 				state = DKIO_EJECTED;
22440Sstevel@tonic-gate 			}
22450Sstevel@tonic-gate 		} else {
22460Sstevel@tonic-gate 			fjp->fj_flags &= ~FUNIT_CHGDET;
22470Sstevel@tonic-gate 			state = DKIO_INSERTED;
22480Sstevel@tonic-gate 		}
22490Sstevel@tonic-gate 	} else {
22500Sstevel@tonic-gate 		fjp->fj_flags &= ~FUNIT_CHGDET;
22510Sstevel@tonic-gate 		state = DKIO_INSERTED;
22520Sstevel@tonic-gate 	}
22530Sstevel@tonic-gate 	FDERRPRINT(FDEP_L0, FDEM_IOCT,
22540Sstevel@tonic-gate 	    (CE_CONT, "fd_get_media_state unit %d: state %x\n", unit, state));
22550Sstevel@tonic-gate 	return (state);
22560Sstevel@tonic-gate }
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate static int
fd_check_media(dev_t dev,enum dkio_state state)22590Sstevel@tonic-gate fd_check_media(dev_t dev, enum dkio_state state)
22600Sstevel@tonic-gate {
22610Sstevel@tonic-gate 	struct fcu_obj *fjp;
22620Sstevel@tonic-gate 	struct fdisk *fdp;
22630Sstevel@tonic-gate 	int	unit;
22640Sstevel@tonic-gate 	int	err;
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 	unit = fd_getdrive(dev, &fjp, &fdp);
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate 	mutex_enter(&fjp->fj_lock);
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 1);
22710Sstevel@tonic-gate 	fdp->d_media_state = fd_get_media_state(fjp, unit);
22720Sstevel@tonic-gate 	fdp->d_media_timeout = drv_usectohz(fd_check_media_time);
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 	while (fdp->d_media_state == state) {
22750Sstevel@tonic-gate 		/* release the controller and drive */
22760Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 0);
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 		/* turn on timer */
22790Sstevel@tonic-gate 		fdp->d_media_timeout_id = timeout(fd_media_watch,
22807656SSherry.Moore@Sun.COM 		    (void *)dev, fdp->d_media_timeout);
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 		if (cv_wait_sig(&fdp->d_statecv, &fjp->fj_lock) == 0) {
22830Sstevel@tonic-gate 			fdp->d_media_timeout = 0;
22840Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
22850Sstevel@tonic-gate 			return (EINTR);
22860Sstevel@tonic-gate 		}
22870Sstevel@tonic-gate 		fjp->fj_ops->fco_select(fjp, unit, 1);
22880Sstevel@tonic-gate 		fdp->d_media_state = fd_get_media_state(fjp, unit);
22890Sstevel@tonic-gate 	}
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	if (fdp->d_media_state == DKIO_INSERTED) {
22920Sstevel@tonic-gate 		err = fdgetlabel(fjp, unit);
22930Sstevel@tonic-gate 		if (err) {
22940Sstevel@tonic-gate 			fjp->fj_ops->fco_select(fjp, unit, 0);
22950Sstevel@tonic-gate 			mutex_exit(&fjp->fj_lock);
22960Sstevel@tonic-gate 			return (EIO);
22970Sstevel@tonic-gate 		}
22980Sstevel@tonic-gate 	}
22990Sstevel@tonic-gate 	fjp->fj_ops->fco_select(fjp, unit, 0);
23000Sstevel@tonic-gate 	mutex_exit(&fjp->fj_lock);
23010Sstevel@tonic-gate 	return (0);
23020Sstevel@tonic-gate }
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate /*
23050Sstevel@tonic-gate  * fd_get_media_info :
23060Sstevel@tonic-gate  * 	Collects medium information for
23070Sstevel@tonic-gate  *	DKIOCGMEDIAINFO ioctl.
23080Sstevel@tonic-gate  */
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate static int
fd_get_media_info(struct fcu_obj * fjp,caddr_t buf,int flag)23110Sstevel@tonic-gate fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag)
23120Sstevel@tonic-gate {
23130Sstevel@tonic-gate 	struct dk_minfo media_info;
23140Sstevel@tonic-gate 	int err = 0;
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	media_info.dki_media_type = DK_FLOPPY;
23170Sstevel@tonic-gate 	media_info.dki_lbsize = fjp->fj_chars->fdc_sec_size;
23180Sstevel@tonic-gate 	media_info.dki_capacity = fjp->fj_chars->fdc_ncyl *
23197656SSherry.Moore@Sun.COM 	    fjp->fj_chars->fdc_secptrack * fjp->fj_chars->fdc_nhead;
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	if (ddi_copyout(&media_info, buf, sizeof (struct dk_minfo), flag))
23220Sstevel@tonic-gate 		err = EFAULT;
23230Sstevel@tonic-gate 	return (err);
23240Sstevel@tonic-gate }
2325