Home | History | Annotate | Download | only in io
      1     0   stevel /*
      2     0   stevel  * CDDL HEADER START
      3     0   stevel  *
      4     0   stevel  * The contents of this file are subject to the terms of the
      5  7656   Sherry  * Common Development and Distribution License (the "License").
      6  7656   Sherry  * You may not use this file except in compliance with the License.
      7     0   stevel  *
      8     0   stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0   stevel  * or http://www.opensolaris.org/os/licensing.
     10     0   stevel  * See the License for the specific language governing permissions
     11     0   stevel  * and limitations under the License.
     12     0   stevel  *
     13     0   stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0   stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0   stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0   stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0   stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0   stevel  *
     19     0   stevel  * CDDL HEADER END
     20     0   stevel  */
     21     0   stevel /*
     22  7656   Sherry  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23     0   stevel  * Use is subject to license terms.
     24     0   stevel  */
     25     0   stevel 
     26     0   stevel 
     27     0   stevel /*
     28     0   stevel  * Floppy Disk driver
     29     0   stevel  */
     30     0   stevel 
     31     0   stevel /*
     32     0   stevel  * Set CMOS feature:
     33     0   stevel  *	CMOS_CONF_MEM:	CMOS memory contains configuration info
     34     0   stevel  */
     35     0   stevel #define	CMOS_CONF_MEM
     36     0   stevel 
     37     0   stevel #include <sys/types.h>
     38     0   stevel #include <sys/param.h>
     39     0   stevel #include <sys/systm.h>
     40     0   stevel #include <sys/buf.h>
     41     0   stevel #include <sys/file.h>
     42     0   stevel #include <sys/open.h>
     43     0   stevel #include <sys/ioctl.h>
     44     0   stevel #include <sys/uio.h>
     45     0   stevel #include <sys/conf.h>
     46     0   stevel #include <sys/stat.h>
     47     0   stevel #include <sys/autoconf.h>
     48     0   stevel #include <sys/vtoc.h>
     49     0   stevel #include <sys/dkio.h>
     50     0   stevel #include <sys/ddi.h>
     51     0   stevel #include <sys/sunddi.h>
     52     0   stevel #include <sys/kstat.h>
     53     0   stevel #include <sys/kmem.h>
     54     0   stevel #include <sys/ddidmareq.h>
     55     0   stevel #include <sys/fdio.h>
     56     0   stevel #include <sys/fdc.h>
     57     0   stevel #include <sys/fd_debug.h>
     58     0   stevel #include <sys/fdmedia.h>
     59     0   stevel #include <sys/debug.h>
     60     0   stevel #include <sys/modctl.h>
     61     0   stevel 
     62     0   stevel /*
     63     0   stevel  * Local Function Prototypes
     64     0   stevel  */
     65     0   stevel static int fd_unit_is_open(struct fdisk *);
     66     0   stevel static int fdgetlabel(struct fcu_obj *, int);
     67     0   stevel static void fdstart(struct fcu_obj *);
     68     0   stevel static int fd_build_label_vtoc(struct fcu_obj *, struct fdisk *,
     69     0   stevel     struct vtoc *, struct dk_label *);
     70     0   stevel static void fd_build_user_vtoc(struct fcu_obj *, struct fdisk *,
     71     0   stevel     struct vtoc *);
     72     0   stevel static int fd_rawioctl(struct fcu_obj *, int, caddr_t, int);
     73     0   stevel static void fd_media_watch(void *);
     74     0   stevel 
     75     0   stevel static int fd_open(dev_t *, int, int, cred_t *);
     76     0   stevel static int fd_close(dev_t, int, int, cred_t *);
     77     0   stevel static int fd_strategy(struct buf *);
     78     0   stevel static int fd_read(dev_t, struct uio *, cred_t *);
     79     0   stevel static int fd_write(dev_t, struct uio *, cred_t *);
     80     0   stevel static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
     81     0   stevel static int fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
     82     0   stevel     caddr_t, int *);
     83     0   stevel static int fd_check_media(dev_t dev, enum dkio_state state);
     84     0   stevel static int fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag);
     85     0   stevel 
     86     0   stevel static struct cb_ops fd_cb_ops = {
     87     0   stevel 	fd_open,		/* open */
     88     0   stevel 	fd_close,		/* close */
     89     0   stevel 	fd_strategy,		/* strategy */
     90     0   stevel 	nodev,			/* print */
     91     0   stevel 	nodev,			/* dump */
     92     0   stevel 	fd_read,		/* read */
     93     0   stevel 	fd_write,		/* write */
     94     0   stevel 	fd_ioctl,		/* ioctl */
     95     0   stevel 	nodev,			/* devmap */
     96     0   stevel 	nodev,			/* mmap */
     97     0   stevel 	nodev,			/* segmap */
     98     0   stevel 	nochpoll,		/* poll */
     99     0   stevel 	fd_prop_op,		/* cb_prop_op */
    100     0   stevel 	0,			/* streamtab  */
    101     0   stevel 	D_NEW | D_MP		/* Driver compatibility flag */
    102     0   stevel };
    103     0   stevel 
    104     0   stevel static int fd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
    105     0   stevel static int fd_probe(dev_info_t *);
    106     0   stevel static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
    107     0   stevel static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
    108     0   stevel 
    109     0   stevel static struct dev_ops fd_ops = {
    110     0   stevel 	DEVO_REV,		/* devo_rev, */
    111     0   stevel 	0,			/* refcnt  */
    112     0   stevel 	fd_getinfo,		/* getinfo */
    113     0   stevel 	nulldev,		/* identify */
    114     0   stevel 	fd_probe,		/* probe */
    115     0   stevel 	fd_attach,		/* attach */
    116     0   stevel 	fd_detach,		/* detach */
    117     0   stevel 	nodev,			/* reset */
    118     0   stevel 	&fd_cb_ops,		/* driver operations */
    119  7656   Sherry 	(struct bus_ops *)0,	/* bus operations */
    120  7656   Sherry 	NULL,			/* power */
    121  7656   Sherry 	ddi_quiesce_not_supported,	/* devo_quiesce */
    122     0   stevel };
    123     0   stevel 
    124     0   stevel 
    125     0   stevel /*
    126     0   stevel  * static data
    127     0   stevel  */
    128     0   stevel static void *fd_state_head;		/* opaque handle top of state structs */
    129     0   stevel static int fd_check_media_time = 5000000;	/* 5 second state check */
    130     0   stevel 
    131     0   stevel /*
    132     0   stevel  * error handling
    133     0   stevel  *
    134     0   stevel  * for debugging,
    135     0   stevel  *		set fderrlevel to 1
    136     0   stevel  *		set fderrmask  to 224  or 644
    137     0   stevel  */
    138     0   stevel #ifdef DEBUG
    139     0   stevel static uint_t fderrmask = FDEM_ALL;
    140     0   stevel #endif
    141     0   stevel static int fderrlevel = 5;
    142     0   stevel 
    143     0   stevel #define	KIOSP	KSTAT_IO_PTR(fdp->d_iostat)
    144     0   stevel 
    145     0   stevel static struct driver_minor_data {
    146     0   stevel 	char	*name;
    147     0   stevel 	int	minor;
    148     0   stevel 	int	type;
    149     0   stevel } fd_minor [] = {
    150     0   stevel 	{ "a", 0, S_IFBLK},
    151     0   stevel 	{ "b", 1, S_IFBLK},
    152     0   stevel 	{ "c", 2, S_IFBLK},
    153     0   stevel 	{ "a,raw", 0, S_IFCHR},
    154     0   stevel 	{ "b,raw", 1, S_IFCHR},
    155     0   stevel 	{ "c,raw", 2, S_IFCHR},
    156     0   stevel 	{0}
    157     0   stevel };
    158     0   stevel 
    159     0   stevel static struct modldrv modldrv = {
    160     0   stevel 	&mod_driverops,		/* Type of module. This one is a driver */
    161  7656   Sherry 	"Floppy Disk driver",	/* Name of the module. */
    162     0   stevel 	&fd_ops,		/* driver ops */
    163     0   stevel };
    164     0   stevel 
    165     0   stevel static struct modlinkage modlinkage = {
    166     0   stevel 	MODREV_1, (void *)&modldrv, NULL
    167     0   stevel };
    168     0   stevel 
    169     0   stevel 
    170     0   stevel int
    171     0   stevel _init(void)
    172     0   stevel {
    173     0   stevel 	int retval;
    174     0   stevel 
    175     0   stevel 	if ((retval = ddi_soft_state_init(&fd_state_head,
    176     0   stevel 	    sizeof (struct fdisk) + sizeof (struct fd_drive) +
    177     0   stevel 	    sizeof (struct fd_char) + sizeof (struct fdattr), 0)) != 0)
    178     0   stevel 		return (retval);
    179     0   stevel 
    180     0   stevel 	if ((retval = mod_install(&modlinkage)) != 0)
    181     0   stevel 		ddi_soft_state_fini(&fd_state_head);
    182     0   stevel 	return (retval);
    183     0   stevel }
    184     0   stevel 
    185     0   stevel int
    186     0   stevel _fini(void)
    187     0   stevel {
    188     0   stevel 	int retval;
    189     0   stevel 
    190     0   stevel 	if ((retval = mod_remove(&modlinkage)) != 0)
    191     0   stevel 		return (retval);
    192     0   stevel 	ddi_soft_state_fini(&fd_state_head);
    193     0   stevel 	return (retval);
    194     0   stevel }
    195     0   stevel 
    196     0   stevel int
    197     0   stevel _info(struct modinfo *modinfop)
    198     0   stevel {
    199     0   stevel 	return (mod_info(&modlinkage, modinfop));
    200     0   stevel }
    201     0   stevel 
    202     0   stevel 
    203     0   stevel static int
    204     0   stevel fd_getdrive(dev_t dev, struct fcu_obj **fjpp, struct fdisk **fdpp)
    205     0   stevel {
    206     0   stevel 	if (fdpp) {
    207     0   stevel 		*fdpp = ddi_get_soft_state(fd_state_head, DRIVE(dev));
    208     0   stevel 		if (*fdpp && fjpp) {
    209     0   stevel 			*fjpp = (*fdpp)->d_obj;
    210     0   stevel 			if (*fjpp)
    211     0   stevel 				return ((*fjpp)->fj_unit);
    212     0   stevel 		}
    213     0   stevel 	}
    214     0   stevel 	return (-1);
    215     0   stevel }
    216     0   stevel 
    217     0   stevel /*ARGSUSED*/
    218     0   stevel static int
    219     0   stevel fd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
    220     0   stevel {
    221     0   stevel 	dev_t dev = (dev_t)arg;
    222     0   stevel 	struct fcu_obj *fjp = NULL;
    223     0   stevel 	struct fdisk *fdp = NULL;
    224     0   stevel 	int rval;
    225     0   stevel 
    226     0   stevel 	switch (cmd) {
    227     0   stevel 	case DDI_INFO_DEVT2DEVINFO:
    228     0   stevel 		(void) fd_getdrive(dev, &fjp, &fdp);
    229     0   stevel 		/*
    230     0   stevel 		 * Ignoring return value because success is checked by
    231     0   stevel 		 * verifying fjp and fdp and returned unit value is not used.
    232     0   stevel 		 */
    233     0   stevel 		if (fjp && fdp) {
    234     0   stevel 			*result = fjp->fj_dip;
    235     0   stevel 			rval = DDI_SUCCESS;
    236     0   stevel 		} else
    237     0   stevel 			rval = DDI_FAILURE;
    238     0   stevel 		break;
    239     0   stevel 	case DDI_INFO_DEVT2INSTANCE:
    240     0   stevel 		*result = (void *)(uintptr_t)DRIVE(dev);
    241     0   stevel 		rval = DDI_SUCCESS;
    242     0   stevel 		break;
    243     0   stevel 	default:
    244     0   stevel 		rval = DDI_FAILURE;
    245     0   stevel 	}
    246     0   stevel 	return (rval);
    247     0   stevel }
    248     0   stevel 
    249     0   stevel #ifdef CMOS_CONF_MEM
    250     0   stevel #define	CMOS_ADDR	0x70
    251     0   stevel #define	CMOS_DATA	0x71
    252     0   stevel #define	CMOS_FDRV	0x10
    253     0   stevel #endif	/* CMOS_CONF_MEM */
    254     0   stevel 
    255     0   stevel static int
    256     0   stevel fd_probe(dev_info_t *dip)
    257     0   stevel {
    258     0   stevel #ifdef CMOS_CONF_MEM
    259     0   stevel 	int cmos;
    260     0   stevel 	int drive_type;
    261     0   stevel #endif	/* CMOS_CONF_MEM */
    262     0   stevel 	int debug[2];
    263     0   stevel 	int drive_size;
    264     0   stevel 	int len;
    265     0   stevel 	int unit_num;
    266     0   stevel 	char density[8];
    267     0   stevel 
    268     0   stevel 	len = sizeof (debug);
    269     0   stevel 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
    270     0   stevel 	    DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) ==
    271     0   stevel 	    DDI_PROP_SUCCESS) {
    272     0   stevel 		fderrlevel = debug[0];
    273     0   stevel #ifdef DEBUG
    274     0   stevel 		fderrmask = (uint_t)debug[1];
    275     0   stevel #endif
    276     0   stevel 	}
    277     0   stevel 	len = sizeof (unit_num);
    278     0   stevel 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
    279     0   stevel 	    DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
    280     0   stevel 	    DDI_PROP_SUCCESS) {
    281     0   stevel 		FDERRPRINT(FDEP_L3, FDEM_ATTA,
    282     0   stevel 		    (CE_WARN, "fd_probe failed: dip %p", (void *)dip));
    283     0   stevel 		return (DDI_PROBE_FAILURE);
    284     0   stevel 	}
    285     0   stevel 
    286     0   stevel #ifdef CMOS_CONF_MEM
    287     0   stevel 	/* get the cmos memory values quick and dirty */
    288     0   stevel 	outb(CMOS_ADDR, CMOS_FDRV);
    289     0   stevel 	cmos = drive_type = (int)inb(CMOS_DATA);
    290     0   stevel #endif	/* CMOS_CONF_MEM */
    291     0   stevel 
    292     0   stevel 	switch (unit_num) {
    293     0   stevel #ifdef CMOS_CONF_MEM
    294     0   stevel 	case 0:
    295     0   stevel 		drive_type = drive_type >> 4;
    296     0   stevel 		/* FALLTHROUGH */
    297     0   stevel 	case 1:
    298     0   stevel 		if (cmos && (drive_type & 0x0F)) {
    299     0   stevel 			break;
    300     0   stevel 		}
    301     0   stevel 		/*
    302     0   stevel 		 * Some enhanced floppy-disk controller adaptor cards
    303     0   stevel 		 * require NO drives defined in the CMOS configuration
    304     0   stevel 		 * memory.
    305     0   stevel 		 * So fall through
    306     0   stevel 		 */
    307     0   stevel #endif	/* CMOS_CONF_MEM */
    308     0   stevel 	default:		/* need to check conf file */
    309     0   stevel 		len = sizeof (density);
    310     0   stevel 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
    311     0   stevel 		    DDI_PROP_DONTPASS, "density", (caddr_t)&density, &len) !=
    312     0   stevel 		    DDI_PROP_SUCCESS) {
    313     0   stevel 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
    314     0   stevel 			    (CE_WARN,
    315     0   stevel 			    "fd_probe failed density: dip %p unit %d",
    316     0   stevel 			    (void *)dip, unit_num));
    317     0   stevel 			return (DDI_PROBE_FAILURE);
    318     0   stevel 		}
    319     0   stevel 		len = sizeof (drive_size);
    320     0   stevel 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
    321     0   stevel 		    DDI_PROP_DONTPASS, "size", (caddr_t)&drive_size, &len) !=
    322     0   stevel 		    DDI_PROP_SUCCESS) {
    323     0   stevel 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
    324     0   stevel 			    (CE_WARN, "fd_probe failed size: dip %p unit %d",
    325     0   stevel 			    (void *)dip, unit_num));
    326     0   stevel 			return (DDI_PROBE_FAILURE);
    327     0   stevel 		}
    328     0   stevel 	}
    329     0   stevel 	FDERRPRINT(FDEP_L3, FDEM_ATTA,
    330     0   stevel 	    (CE_WARN, "fd_probe dip %p unit %d", (void *)dip, unit_num));
    331     0   stevel 	return (DDI_PROBE_SUCCESS);
    332     0   stevel }
    333     0   stevel 
    334     0   stevel 
    335     0   stevel /* ARGSUSED */
    336     0   stevel static int
    337     0   stevel fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    338     0   stevel {
    339     0   stevel 	struct fcu_obj *fjp;
    340     0   stevel 	struct fdisk *fdp;
    341     0   stevel 	struct driver_minor_data *dmdp;
    342     0   stevel 	int mode_3D;
    343     0   stevel 	int drive_num, drive_size, drive_type;
    344     0   stevel #ifdef CMOS_CONF_MEM
    345     0   stevel 	int cmos;
    346     0   stevel #endif	/* CMOS_CONF_MEM */
    347     0   stevel 	int len, sig_minor;
    348     0   stevel 	int unit_num;
    349     0   stevel 	char density[8];
    350     0   stevel 	char name[MAXNAMELEN];
    351     0   stevel 
    352     0   stevel 	switch (cmd) {
    353     0   stevel 	case DDI_ATTACH:
    354     0   stevel 		len = sizeof (unit_num);
    355     0   stevel 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
    356     0   stevel 		    DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
    357     0   stevel 		    DDI_PROP_SUCCESS) {
    358     0   stevel 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
    359     0   stevel 			    (CE_WARN, "fd_attach failed: dip %p", (void *)dip));
    360     0   stevel 			return (DDI_FAILURE);
    361     0   stevel 		}
    362     0   stevel 
    363     0   stevel #ifdef CMOS_CONF_MEM
    364     0   stevel 		outb(CMOS_ADDR, CMOS_FDRV);
    365     0   stevel 		cmos = drive_type = (int)inb(CMOS_DATA);
    366     0   stevel #endif	/* CMOS_CONF_MEM */
    367     0   stevel 
    368     0   stevel 		switch (unit_num) {
    369     0   stevel #ifdef CMOS_CONF_MEM
    370     0   stevel 		case 0:
    371     0   stevel 			drive_type = drive_type >> 4;
    372     0   stevel 			/* FALLTHROUGH */
    373     0   stevel 		case 1:
    374     0   stevel 			drive_type = drive_type & 0x0F;
    375     0   stevel 			if (cmos)
    376     0   stevel 				break;
    377     0   stevel 			/*
    378     0   stevel 			 * Some enhanced floppy-disk controller adaptor cards
    379     0   stevel 			 * require NO drives defined in the CMOS configuration
    380     0   stevel 			 * memory.
    381     0   stevel 			 * So fall through
    382     0   stevel 			 */
    383     0   stevel #endif	/* CMOS_CONF_MEM */
    384     0   stevel 		default:		/* need to check .conf file */
    385     0   stevel 			drive_type = 0;
    386     0   stevel 			len = sizeof (density);
    387     0   stevel 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
    388     0   stevel 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "density",
    389     0   stevel 			    (caddr_t)&density, &len) != DDI_PROP_SUCCESS)
    390     0   stevel 				density[0] = '\0';
    391     0   stevel 			len = sizeof (drive_size);
    392     0   stevel 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
    393     0   stevel 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "size",
    394     0   stevel 			    (caddr_t)&drive_size, &len) != DDI_PROP_SUCCESS)
    395     0   stevel 				drive_size = 0;
    396     0   stevel 			if (strcmp(density, "DSDD") == 0) {
    397     0   stevel 				if (drive_size == 5)
    398     0   stevel 					drive_type = 1;
    399     0   stevel 				else if (drive_size == 3)
    400     0   stevel 					drive_type = 3;
    401     0   stevel 			} else if (strcmp(density, "DSHD") == 0) {
    402     0   stevel 				if (drive_size == 5)
    403     0   stevel 					drive_type = 2;
    404     0   stevel 				else if (drive_size == 3)
    405     0   stevel 					drive_type = 4;
    406     0   stevel 			} else if (strcmp(density, "DSED") == 0 &&
    407     0   stevel 			    drive_size == 3) {
    408     0   stevel 				drive_type = 6;
    409     0   stevel 			}
    410     0   stevel 			break;
    411     0   stevel 		}
    412     0   stevel 		if (drive_type == 0) {
    413     0   stevel 			FDERRPRINT(FDEP_L3, FDEM_ATTA,
    414     0   stevel 			    (CE_WARN, "fd_attach failed type: dip %p unit %d",
    415     0   stevel 			    (void *)dip, unit_num));
    416     0   stevel 			return (DDI_FAILURE);
    417     0   stevel 		}
    418     0   stevel 
    419     0   stevel 		drive_num = ddi_get_instance(dip);
    420     0   stevel 		if (ddi_soft_state_zalloc(fd_state_head, drive_num) != 0)
    421     0   stevel 			return (DDI_FAILURE);
    422     0   stevel 		fdp = ddi_get_soft_state(fd_state_head, drive_num);
    423     0   stevel 		fjp = fdp->d_obj = ddi_get_driver_private(dip);
    424     0   stevel 
    425     0   stevel 		mutex_init(&fjp->fj_lock, NULL, MUTEX_DRIVER, *fjp->fj_iblock);
    426     0   stevel 		sema_init(&fdp->d_ocsem, 1, NULL, SEMA_DRIVER, NULL);
    427     0   stevel 
    428     0   stevel 		fjp->fj_drive = (struct fd_drive *)(fdp + 1);
    429     0   stevel 		fjp->fj_chars = (struct fd_char *)(fjp->fj_drive + 1);
    430     0   stevel 		fjp->fj_attr = (struct fdattr *)(fjp->fj_chars + 1);
    431     0   stevel 
    432     0   stevel 		/*
    433     0   stevel 		 * set default floppy drive characteristics & geometry
    434     0   stevel 		 */
    435     0   stevel 		switch (drive_type) {	/* assume doubled sided */
    436     0   stevel 		case 2:			/* 5.25 high density */
    437     0   stevel 			*fjp->fj_drive = dfd_525HD;
    438     0   stevel 			fdp->d_media = 1<<FMT_5H | 1<<FMT_5D9 | 1<<FMT_5D8 |
    439     0   stevel 			    1<<FMT_5D4 | 1<<FMT_5D16;
    440     0   stevel 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_5H;
    441     0   stevel 			break;
    442     0   stevel 		case 4:			/* 3.5 high density */
    443     0   stevel 			*fjp->fj_drive = dfd_350HD;
    444     0   stevel 			fdp->d_media = 1<<FMT_3H | 1<<FMT_3I | 1<<FMT_3D;
    445     0   stevel 			len = sizeof (mode_3D);
    446     0   stevel 			if (ddi_prop_op(DDI_DEV_T_ANY, dip,
    447     0   stevel 			    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "mode_3D",
    448     0   stevel 			    (caddr_t)&mode_3D, &len) != DDI_PROP_SUCCESS)
    449     0   stevel 				mode_3D = 0;
    450     0   stevel 			if (mode_3D && (fjp->fj_fdc->c_flags & FCFLG_3DMODE))
    451     0   stevel 				/*
    452     0   stevel 				 * 3D mode should be enabled only if a dual-
    453     0   stevel 				 * speed 3.5" high-density drive and a
    454     0   stevel 				 * supported floppy controller are installed.
    455     0   stevel 				 */
    456     0   stevel 				fdp->d_media |= 1 << FMT_3M;
    457     0   stevel 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3H;
    458     0   stevel 			break;
    459     0   stevel 		case 1:			/* 5.25 double density */
    460     0   stevel 			*fjp->fj_drive = dfd_525DD;
    461     0   stevel 			fdp->d_media = 1<<FMT_5D9 | 1<<FMT_5D8 | 1<<FMT_5D4 |
    462     0   stevel 			    1<<FMT_5D16;
    463     0   stevel 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_5D9;
    464     0   stevel 			break;
    465     0   stevel 		case 3:			/* 3.5 double density */
    466     0   stevel 			*fjp->fj_drive = dfd_350HD;
    467     0   stevel 			fdp->d_media = 1<<FMT_3D;
    468     0   stevel 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3D;
    469     0   stevel 			break;
    470     0   stevel 		case 5:			/* 3.5 extended density */
    471     0   stevel 		case 6:
    472     0   stevel 		case 7:
    473     0   stevel 			*fjp->fj_drive = dfd_350ED;
    474     0   stevel 			fdp->d_media = 1<<FMT_3E | 1<<FMT_3H | 1<<FMT_3I |
    475     0   stevel 			    1<<FMT_3D;
    476     0   stevel 			fdp->d_deffdtype = fdp->d_curfdtype = FMT_3E;
    477     0   stevel 			break;
    478     0   stevel 		case 0:			/* no drive defined */
    479     0   stevel 		default:
    480     0   stevel 			goto no_attach;
    481     0   stevel 		}
    482     0   stevel 		*fjp->fj_chars = *defchar[fdp->d_deffdtype];
    483     0   stevel 		*fjp->fj_attr = fdtypes[fdp->d_deffdtype];
    484     0   stevel 		bcopy(fdparts[fdp->d_deffdtype], fdp->d_part,
    485     0   stevel 		    sizeof (struct partition) * NDKMAP);
    486     0   stevel 		fjp->fj_rotspd = fdtypes[fdp->d_deffdtype].fda_rotatespd;
    487     0   stevel 
    488     0   stevel 		sig_minor = drive_num << 3;
    489     0   stevel 		for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
    490     0   stevel 			if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
    491     0   stevel 			    sig_minor | dmdp->minor, DDI_NT_FD, NULL)
    492     0   stevel 			    == DDI_FAILURE) {
    493     0   stevel 				ddi_remove_minor_node(dip, NULL);
    494     0   stevel 				goto no_attach;
    495     0   stevel 			}
    496     0   stevel 		}
    497     0   stevel 
    498     0   stevel 		FDERRPRINT(FDEP_L3, FDEM_ATTA,
    499     0   stevel 		    (CE_WARN, "fd_attach: dip %p unit %d",
    500     0   stevel 		    (void *)dip, unit_num));
    501     0   stevel 		(void) sprintf(name, "fd%d", drive_num);
    502     0   stevel 		fdp->d_iostat = kstat_create("fd", drive_num, name, "disk",
    503     0   stevel 		    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
    504     0   stevel 		if (fdp->d_iostat) {
    505     0   stevel 			fdp->d_iostat->ks_lock = &fjp->fj_lock;
    506     0   stevel 			kstat_install(fdp->d_iostat);
    507     0   stevel 		}
    508     0   stevel 
    509     0   stevel 		fjp->fj_data = (caddr_t)fdp;
    510     0   stevel 		fjp->fj_flags |= FUNIT_DRVATCH;
    511     0   stevel 
    512     0   stevel 		/*
    513     0   stevel 		 * Add a zero-length attribute to tell the world we support
    514     0   stevel 		 * kernel ioctls (for layered drivers)
    515     0   stevel 		 */
    516     0   stevel 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
    517     0   stevel 		    DDI_KERNEL_IOCTL, NULL, 0);
    518  8258  gdamore 
    519  8258  gdamore 		/*
    520  8258  gdamore 		 * We want to get suspend/resume events, so that we can
    521  8258  gdamore 		 * refuse to suspend when pcfs is mounted.
    522  8258  gdamore 		 */
    523  8258  gdamore 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
    524  8258  gdamore 		    "pm-hardware-state", "needs-suspend-resume");
    525  8258  gdamore 
    526     0   stevel 		/*
    527     0   stevel 		 * Ignoring return value because, for passed arguments, only
    528     0   stevel 		 * DDI_SUCCESS is returned.
    529     0   stevel 		 */
    530     0   stevel 		ddi_report_dev(dip);
    531     0   stevel 		return (DDI_SUCCESS);
    532     0   stevel 
    533     0   stevel 	case DDI_RESUME:
    534  8258  gdamore 		/* nothing for us to do */
    535     0   stevel 		return (DDI_SUCCESS);
    536     0   stevel 
    537     0   stevel 	default:
    538     0   stevel 		return (DDI_FAILURE);
    539     0   stevel 	}
    540     0   stevel no_attach:
    541     0   stevel 	fjp->fj_drive = NULL;
    542     0   stevel 	fjp->fj_chars = NULL;
    543     0   stevel 	fjp->fj_attr = NULL;
    544     0   stevel 	mutex_destroy(&fjp->fj_lock);
    545     0   stevel 	sema_destroy(&fdp->d_ocsem);
    546     0   stevel 	ddi_soft_state_free(fd_state_head, drive_num);
    547     0   stevel 	FDERRPRINT(FDEP_L3, FDEM_ATTA,
    548     0   stevel 	    (CE_WARN, "fd_attach failed: dip %p unit %d",
    549     0   stevel 	    (void *)dip, unit_num));
    550     0   stevel 	return (DDI_FAILURE);
    551     0   stevel }
    552     0   stevel 
    553     0   stevel 
    554     0   stevel /* ARGSUSED */
    555     0   stevel static int
    556     0   stevel fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    557     0   stevel {
    558     0   stevel 	struct fcu_obj *fjp;
    559     0   stevel 	struct fdisk *fdp;
    560     0   stevel 	int drive_num;
    561     0   stevel 	int rval = DDI_SUCCESS;
    562     0   stevel 
    563     0   stevel 	FDERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fd_detach dip %p",
    564  7656   Sherry 	    (void *)dip));
    565     0   stevel 
    566     0   stevel 	drive_num = ddi_get_instance(dip);
    567     0   stevel 	if (!(fdp = ddi_get_soft_state(fd_state_head, drive_num)))
    568     0   stevel 		return (rval);
    569     0   stevel 
    570     0   stevel 	switch (cmd) {
    571     0   stevel 	case DDI_DETACH:
    572     0   stevel 		if (fd_unit_is_open(fdp)) {
    573  8258  gdamore 			rval = DDI_FAILURE;
    574     0   stevel 			break;
    575     0   stevel 		}
    576     0   stevel 		kstat_delete(fdp->d_iostat);
    577     0   stevel 		fdp->d_iostat = NULL;
    578     0   stevel 		fjp = (struct fcu_obj *)fdp->d_obj;
    579  8258  gdamore 		fjp->fj_flags &= ~FUNIT_DRVATCH;
    580     0   stevel 		fjp->fj_data = NULL;
    581     0   stevel 		fjp->fj_drive = NULL;
    582     0   stevel 		fjp->fj_chars = NULL;
    583     0   stevel 		fjp->fj_attr = NULL;
    584     0   stevel 		ddi_prop_remove_all(dip);
    585     0   stevel 		mutex_destroy(&fjp->fj_lock);
    586     0   stevel 		sema_destroy(&fdp->d_ocsem);
    587     0   stevel 		ddi_soft_state_free(fd_state_head, drive_num);
    588     0   stevel 		break;
    589     0   stevel 
    590     0   stevel 	case DDI_SUSPEND:
    591  8258  gdamore 		/*
    592  8258  gdamore 		 * Bad, bad, bad things will happen if someone
    593  8258  gdamore 		 * *changes* the disk in the drive while it is mounted
    594  8258  gdamore 		 * and the system is suspended.  We have no way to
    595  8258  gdamore 		 * detect that.  (Undetected filesystem corruption.
    596  8258  gdamore 		 * Its akin to changing the boot disk while the system
    597  8258  gdamore 		 * is suspended.  Don't do it!)
    598  8258  gdamore 		 *
    599  8258  gdamore 		 * So we refuse to suspend if there is a mounted filesystem.
    600  8258  gdamore 		 * (We guess this by looking for a block open.  Character
    601  8258  gdamore 		 * opens are fine.)  This limits some of the usability of
    602  8258  gdamore 		 * suspend/resume, but it certainly avoids this
    603  8258  gdamore 		 * potential filesytem corruption from pilot error.
    604  8258  gdamore 		 * Given the decreasing popularity of floppy media, we
    605  8258  gdamore 		 * don't see this as much of a limitation.
    606  8258  gdamore 		 */
    607  8258  gdamore 		if (fdp->d_regopen[OTYP_BLK]) {
    608  8258  gdamore 			cmn_err(CE_NOTE,
    609  8258  gdamore 			    "Unable to suspend while floppy is in use.");
    610  8258  gdamore 			rval = DDI_FAILURE;
    611     0   stevel 		}
    612     0   stevel 		break;
    613     0   stevel 
    614     0   stevel 	default:
    615  8258  gdamore 		rval = DDI_FAILURE;
    616     0   stevel 		break;
    617     0   stevel 	}
    618     0   stevel 	return (rval);
    619     0   stevel }
    620     0   stevel 
    621     0   stevel 
    622     0   stevel static int
    623     0   stevel fd_part_is_open(struct fdisk *fdp, int part)
    624     0   stevel {
    625     0   stevel 	int i;
    626     0   stevel 
    627     0   stevel 	for (i = 0; i < (OTYPCNT - 1); i++)
    628     0   stevel 		if (fdp->d_regopen[i] & (1 << part))
    629     0   stevel 			return (1);
    630     0   stevel 	return (0);
    631     0   stevel }
    632     0   stevel 
    633     0   stevel static int
    634     0   stevel fd_unit_is_open(struct fdisk *fdp)
    635     0   stevel {
    636     0   stevel 	int i;
    637     0   stevel 
    638     0   stevel 	for (i = 0; i < NDKMAP; i++)
    639     0   stevel 		if (fdp->d_lyropen[i])
    640     0   stevel 			return (1);
    641     0   stevel 	for (i = 0; i < (OTYPCNT - 1); i++)
    642     0   stevel 		if (fdp->d_regopen[i])
    643     0   stevel 			return (1);
    644     0   stevel 	return (0);
    645     0   stevel }
    646     0   stevel 
    647     0   stevel /*ARGSUSED*/
    648     0   stevel static int
    649     0   stevel fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
    650     0   stevel {
    651     0   stevel 	struct fcu_obj *fjp = NULL;
    652     0   stevel 	struct fdisk *fdp = NULL;
    653     0   stevel 	struct partition *pp;
    654     0   stevel 	dev_t dev;
    655     0   stevel 	int part, unit;
    656     0   stevel 	int part_is_open;
    657     0   stevel 	int rval;
    658     0   stevel 	uint_t pbit;
    659     0   stevel 
    660     0   stevel 	dev = *devp;
    661     0   stevel 	unit = fd_getdrive(dev, &fjp, &fdp);
    662     0   stevel 	if (!fjp || !fdp)
    663     0   stevel 		return (ENXIO);
    664     0   stevel 	part = PARTITION(dev);
    665     0   stevel 	pbit = 1 << part;
    666     0   stevel 	pp = &fdp->d_part[part];
    667     0   stevel 
    668     0   stevel 	/*
    669     0   stevel 	 * Serialize opens/closes
    670     0   stevel 	 */
    671     0   stevel 	sema_p(&fdp->d_ocsem);
    672     0   stevel 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
    673     0   stevel 	    (CE_CONT, "fd_open: fd%d part %d flag %x otype %x\n", DRIVE(dev),
    674     0   stevel 	    part, flag, otyp));
    675     0   stevel 
    676     0   stevel 	/*
    677     0   stevel 	 * Check for previous exclusive open, or trying to exclusive open
    678     0   stevel 	 * An "exclusive open" on any partition is not guaranteed to
    679     0   stevel 	 * protect against opens on another partition that overlaps it.
    680     0   stevel 	 */
    681     0   stevel 	if (otyp == OTYP_LYR) {
    682     0   stevel 		part_is_open = (fdp->d_lyropen[part] != 0);
    683     0   stevel 	} else {
    684     0   stevel 		part_is_open = fd_part_is_open(fdp, part);
    685     0   stevel 	}
    686     0   stevel 	if ((fdp->d_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
    687     0   stevel 		FDERRPRINT(FDEP_L0, FDEM_OPEN, (CE_CONT,
    688     0   stevel 		    "fd_open: exclparts %lx openparts %lx lyrcnt %lx pbit %x\n",
    689     0   stevel 		    fdp->d_exclmask, fdp->d_regopen[otyp], fdp->d_lyropen[part],
    690     0   stevel 		    pbit));
    691     0   stevel 		sema_v(&fdp->d_ocsem);
    692     0   stevel 		return (EBUSY);
    693     0   stevel 	}
    694     0   stevel 
    695     0   stevel 	/*
    696     0   stevel 	 * Ensure that drive is recalibrated on first open of new diskette.
    697     0   stevel 	 */
    698     0   stevel 	fjp->fj_ops->fco_select(fjp, unit, 1);
    699     0   stevel 	if (fjp->fj_ops->fco_getchng(fjp, unit) != 0) {
    700     0   stevel 		if (fjp->fj_ops->fco_rcseek(fjp, unit, -1, 0)) {
    701     0   stevel 			FDERRPRINT(FDEP_L2, FDEM_OPEN,
    702     0   stevel 			    (CE_NOTE, "fd_open fd%d: not ready", DRIVE(dev)));
    703     0   stevel 			fjp->fj_ops->fco_select(fjp, unit, 0);
    704     0   stevel 			sema_v(&fdp->d_ocsem);
    705     0   stevel 			return (ENXIO);
    706     0   stevel 		}
    707     0   stevel 		fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
    708     0   stevel 	}
    709     0   stevel 	if (flag & (FNDELAY | FNONBLOCK)) {
    710     0   stevel 		/* don't attempt access, just return successfully */
    711     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 0);
    712     0   stevel 		goto out;
    713     0   stevel 	}
    714     0   stevel 
    715     0   stevel 	/*
    716     0   stevel 	 * auto-sense the density/format of the diskette
    717     0   stevel 	 */
    718     0   stevel 	rval = fdgetlabel(fjp, unit);
    719     0   stevel 	fjp->fj_ops->fco_select(fjp, unit, 0);
    720     0   stevel 	if (rval) {
    721     0   stevel 		/* didn't find label (couldn't read anything) */
    722     0   stevel 		FDERRPRINT(FDEP_L2, FDEM_OPEN,
    723     0   stevel 		    (CE_NOTE, "fd%d: drive not ready", DRIVE(dev)));
    724     0   stevel 		sema_v(&fdp->d_ocsem);
    725     0   stevel 		return (EIO);
    726     0   stevel 	}
    727     0   stevel 	/* check partition */
    728     0   stevel 	if (pp->p_size == 0) {
    729     0   stevel 		sema_v(&fdp->d_ocsem);
    730     0   stevel 		return (ENXIO);
    731     0   stevel 	}
    732     0   stevel 	/*
    733     0   stevel 	 * if opening for writing, check write protect on diskette
    734     0   stevel 	 */
    735     0   stevel 	if ((flag & FWRITE) && (fdp->d_obj->fj_flags & FUNIT_WPROT)) {
    736     0   stevel 		sema_v(&fdp->d_ocsem);
    737     0   stevel 		return (EROFS);
    738     0   stevel 	}
    739     0   stevel 
    740     0   stevel out:
    741     0   stevel 	/*
    742     0   stevel 	 * mark open as having succeeded
    743     0   stevel 	 */
    744     0   stevel 	if (flag & FEXCL)
    745     0   stevel 		fdp->d_exclmask |= pbit;
    746     0   stevel 	if (otyp == OTYP_LYR)
    747     0   stevel 		fdp->d_lyropen[part]++;
    748     0   stevel 	else
    749     0   stevel 		fdp->d_regopen[otyp] |= 1 << part;
    750     0   stevel 
    751     0   stevel 	sema_v(&fdp->d_ocsem);
    752     0   stevel 	return (0);
    753     0   stevel }
    754     0   stevel 
    755     0   stevel /*
    756     0   stevel  * fdgetlabel - read the SunOS label off the diskette
    757     0   stevel  *	if it can read a valid label it does so, else it will use a
    758     0   stevel  *	default.  If it can`t read the diskette - that is an error.
    759     0   stevel  *
    760     0   stevel  * RETURNS: 0 for ok - meaning that it could at least read the device,
    761     0   stevel  *	!0 for error XXX TBD NYD error codes
    762     0   stevel  */
    763     0   stevel static int
    764     0   stevel fdgetlabel(struct fcu_obj *fjp, int unit)
    765     0   stevel {
    766     0   stevel 	struct dk_label *label;
    767     0   stevel 	struct fdisk *fdp;
    768     0   stevel 	char *newlabel;
    769     0   stevel 	short *sp;
    770     0   stevel 	short count;
    771     0   stevel 	short xsum;
    772     0   stevel 	int tries, try_this;
    773     0   stevel 	uint_t nexttype;
    774     0   stevel 	int rval;
    775     0   stevel 	short oldlvl;
    776     0   stevel 	int i;
    777     0   stevel 
    778     0   stevel 	FDERRPRINT(FDEP_L0, FDEM_GETL,
    779     0   stevel 	    (CE_CONT, "fdgetlabel fd unit %d\n", unit));
    780     0   stevel 	fdp = (struct fdisk *)fjp->fj_data;
    781     0   stevel 	fjp->fj_flags &= ~(FUNIT_UNLABELED);
    782     0   stevel 
    783     0   stevel 	/*
    784     0   stevel 	 * get some space to play with the label
    785     0   stevel 	 */
    786     0   stevel 	label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
    787     0   stevel 	FDERRPRINT(FDEP_L0, FDEM_GETL, (CE_CONT,
    788     0   stevel 	    "fdgetlabel fd unit %d kmem_zalloc: ptr = %p, size = %lx\n",
    789     0   stevel 	    unit, (void *)label, (size_t)sizeof (struct dk_label)));
    790     0   stevel 
    791     0   stevel 	/*
    792     0   stevel 	 * read block 0 (0/0/1) to find the label
    793     0   stevel 	 * (disk is potentially not present or unformatted)
    794     0   stevel 	 */
    795     0   stevel 	/* noerrprint since this is a private cmd */
    796     0   stevel 	oldlvl = fderrlevel;
    797     0   stevel 	fderrlevel = FDEP_LMAX;
    798     0   stevel 	/*
    799     0   stevel 	 * try different characteristics (ie densities)
    800     0   stevel 	 *
    801     0   stevel 	 * if fdp->d_curfdtype is -1 then the current characteristics
    802     0   stevel 	 * were set by ioctl and need to try it as well as everything
    803     0   stevel 	 * in the table
    804     0   stevel 	 */
    805     0   stevel 	nexttype = fdp->d_deffdtype;
    806     0   stevel 	try_this = 1;		/* always try the current characteristics */
    807     0   stevel 
    808     0   stevel 	for (tries = nfdtypes; tries; tries--) {
    809     0   stevel 		if (try_this) {
    810     0   stevel 			fjp->fj_flags &= ~FUNIT_CHAROK;
    811     0   stevel 
    812     0   stevel 			/* try reading last sector of cyl 1, head 0 */
    813     0   stevel 			if (!(rval = fjp->fj_ops->fco_rw(fjp, unit,
    814     0   stevel 			    FDREAD, 1, 0, fjp->fj_chars->fdc_secptrack,
    815     0   stevel 			    (caddr_t)label,
    816     0   stevel 			    sizeof (struct dk_label))) &&
    817     0   stevel 			    /* and last sector plus 1 of cylinder 1 */
    818     0   stevel 			    fjp->fj_ops->fco_rw(fjp, unit, FDREAD, 1,
    819     0   stevel 			    0, fjp->fj_chars->fdc_secptrack + 1,
    820     0   stevel 			    (caddr_t)label,
    821     0   stevel 			    sizeof (struct dk_label)) &&
    822     0   stevel 			    /* and label sector on cylinder 0 */
    823     0   stevel 			    !(rval = fjp->fj_ops->fco_rw(fjp, unit,
    824     0   stevel 			    FDREAD, 0, 0, 1, (caddr_t)label,
    825     0   stevel 			    sizeof (struct dk_label))))
    826     0   stevel 				break;
    827     0   stevel 			if (rval == ENXIO)
    828     0   stevel 				break;
    829     0   stevel 		}
    830     0   stevel 		/*
    831     0   stevel 		 * try the next entry in the characteristics tbl
    832     0   stevel 		 */
    833     0   stevel 		fdp->d_curfdtype = (signed char)nexttype;
    834     0   stevel 		nexttype = (nexttype + 1) % nfdtypes;
    835     0   stevel 		if ((1 << fdp->d_curfdtype) & fdp->d_media) {
    836     0   stevel 			*fjp->fj_chars = *defchar[fdp->d_curfdtype];
    837     0   stevel 			*fjp->fj_attr = fdtypes[fdp->d_curfdtype];
    838     0   stevel 			bcopy(fdparts[fdp->d_curfdtype], fdp->d_part,
    839     0   stevel 			    sizeof (struct partition) * NDKMAP);
    840     0   stevel 			/*
    841     0   stevel 			 * check for a double_density diskette
    842     0   stevel 			 * in a high_density 5.25" drive
    843     0   stevel 			 */
    844     0   stevel 			if (fjp->fj_chars->fdc_transfer_rate == 250 &&
    845     0   stevel 			    fjp->fj_rotspd > fjp->fj_attr->fda_rotatespd) {
    846     0   stevel 				/*
    847     0   stevel 				 * yes - adjust transfer rate since we don't
    848     0   stevel 				 * know if we have a 5.25" dual-speed drive
    849     0   stevel 				 */
    850     0   stevel 				fjp->fj_attr->fda_rotatespd = 360;
    851     0   stevel 				fjp->fj_chars->fdc_transfer_rate = 300;
    852     0   stevel 				fjp->fj_chars->fdc_medium = 5;
    853     0   stevel 			}
    854     0   stevel 			if ((2 * fjp->fj_chars->fdc_ncyl) ==
    855     0   stevel 			    defchar[fdp->d_deffdtype]->fdc_ncyl) {
    856     0   stevel 				/* yes - adjust steps per cylinder */
    857     0   stevel 				fjp->fj_chars->fdc_steps = 2;
    858     0   stevel 			} else
    859     0   stevel 				fjp->fj_chars->fdc_steps = 1;
    860     0   stevel 			try_this = 1;
    861     0   stevel 		} else
    862     0   stevel 			try_this = 0;
    863     0   stevel 	}
    864     0   stevel 	fderrlevel = oldlvl;	/* print errors again */
    865     0   stevel 
    866     0   stevel 	if (rval) {
    867     0   stevel 		fdp->d_curfdtype = fdp->d_deffdtype;
    868     0   stevel 		goto out;			/* couldn't read anything */
    869     0   stevel 	}
    870     0   stevel 
    871     0   stevel 	FDERRPRINT(FDEP_L0, FDEM_GETL,
    872     0   stevel 	    (CE_CONT,
    873     0   stevel 	    "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n",
    874     0   stevel 	    unit, fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_secptrack,
    875     0   stevel 	    fjp->fj_chars->fdc_steps, fjp->fj_attr->fda_rotatespd,
    876     0   stevel 	    fjp->fj_attr->fda_intrlv));
    877     0   stevel 
    878     0   stevel 	/*
    879     0   stevel 	 * _something_ was read  -  look for unixtype label
    880     0   stevel 	 */
    881     0   stevel 	if (label->dkl_magic != DKL_MAGIC ||
    882     0   stevel 	    label->dkl_vtoc.v_sanity != VTOC_SANE) {
    883     0   stevel 		/* not a label - no magic number */
    884     0   stevel 		goto nolabel;	/* no errors, but no label */
    885     0   stevel 	}
    886     0   stevel 
    887     0   stevel 	count = sizeof (struct dk_label) / sizeof (short);
    888     0   stevel 	sp = (short *)label;
    889     0   stevel 	xsum = 0;
    890     0   stevel 	while (count--)
    891     0   stevel 		xsum ^= *sp++;	/* should add up to 0 */
    892     0   stevel 	if (xsum) {
    893     0   stevel 		/* not a label - checksum didn't compute */
    894     0   stevel 		goto nolabel;	/* no errors, but no label */
    895     0   stevel 	}
    896     0   stevel 
    897     0   stevel 	/*
    898     0   stevel 	 * the SunOS label overrides current diskette characteristics
    899     0   stevel 	 */
    900     0   stevel 	fjp->fj_chars->fdc_ncyl = label->dkl_pcyl;
    901     0   stevel 	fjp->fj_chars->fdc_nhead = label->dkl_nhead;
    902     0   stevel 	fjp->fj_chars->fdc_secptrack = (label->dkl_nsect * DEV_BSIZE) /
    903     0   stevel 	    fjp->fj_chars->fdc_sec_size;
    904     0   stevel 	if (defchar[fdp->d_deffdtype]->fdc_ncyl == 2 * fjp->fj_chars->fdc_ncyl)
    905     0   stevel 		fjp->fj_chars->fdc_steps = 2;
    906     0   stevel 	else
    907     0   stevel 		fjp->fj_chars->fdc_steps = 1;
    908     0   stevel 
    909     0   stevel 	fjp->fj_attr->fda_rotatespd = label->dkl_rpm;
    910     0   stevel 	fjp->fj_attr->fda_intrlv = label->dkl_intrlv;
    911     0   stevel 
    912     0   stevel 	fdp->d_vtoc_version = label->dkl_vtoc.v_version;
    913     0   stevel 	bcopy(label->dkl_vtoc.v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
    914     0   stevel 	bcopy(label->dkl_vtoc.v_asciilabel,
    915     0   stevel 	    fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
    916     0   stevel 	/*
    917     0   stevel 	 * logical partitions
    918     0   stevel 	 */
    919     0   stevel 	for (i = 0; i < NDKMAP; i++) {
    920     0   stevel 		fdp->d_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag;
    921     0   stevel 		fdp->d_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag;
    922     0   stevel 		fdp->d_part[i].p_start = label->dkl_vtoc.v_part[i].p_start;
    923     0   stevel 		fdp->d_part[i].p_size = label->dkl_vtoc.v_part[i].p_size;
    924     0   stevel 
    925     0   stevel 		fdp->d_vtoc_timestamp[i] = label->dkl_vtoc.timestamp[i];
    926     0   stevel 	}
    927     0   stevel 
    928     0   stevel 	fjp->fj_flags |= FUNIT_LABELOK;
    929     0   stevel 	goto out;
    930     0   stevel 
    931     0   stevel nolabel:
    932     0   stevel 	/*
    933     0   stevel 	 * if not found, fill in label info from default (mark default used)
    934     0   stevel 	 */
    935     0   stevel 	if (fdp->d_media & (1<<FMT_3D))
    936     0   stevel 		newlabel = deflabel_35;
    937     0   stevel 	else /* if (fdp->d_media & (1<<FMT_5D9)) */
    938     0   stevel 		newlabel = deflabel_525;
    939     0   stevel 	bzero(fdp->d_vtoc_volume, LEN_DKL_VVOL);
    940     0   stevel 	(void) sprintf(fdp->d_vtoc_asciilabel, newlabel,
    941     0   stevel 	    fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_nhead,
    942     0   stevel 	    fjp->fj_chars->fdc_secptrack);
    943     0   stevel 	fjp->fj_flags |= FUNIT_UNLABELED;
    944     0   stevel 
    945     0   stevel out:
    946     0   stevel 	kmem_free(label, sizeof (struct dk_label));
    947     0   stevel 	return (rval);
    948     0   stevel }
    949     0   stevel 
    950     0   stevel 
    951     0   stevel /*ARGSUSED*/
    952     0   stevel static int
    953     0   stevel fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
    954     0   stevel {
    955     0   stevel 	struct fcu_obj *fjp = NULL;
    956     0   stevel 	struct fdisk *fdp = NULL;
    957     0   stevel 	int part, part_is_closed;
    958     0   stevel 
    959     0   stevel #ifdef DEBUG
    960     0   stevel 	int unit;
    961     0   stevel #define	DEBUG_ASSIGN	unit=
    962     0   stevel #else
    963     0   stevel #define	DEBUG_ASSIGN	(void)
    964     0   stevel #endif
    965     0   stevel 
    966     0   stevel 	DEBUG_ASSIGN fd_getdrive(dev, &fjp, &fdp);
    967     0   stevel 	/*
    968     0   stevel 	 * Ignoring return in non DEBUG mode because success is checked by
    969     0   stevel 	 * verifying fjp and fdp and returned unit value is not used.
    970     0   stevel 	 */
    971     0   stevel 	if (!fjp || !fdp)
    972     0   stevel 		return (ENXIO);
    973     0   stevel 	part = PARTITION(dev);
    974     0   stevel 
    975     0   stevel 	sema_p(&fdp->d_ocsem);
    976     0   stevel 	FDERRPRINT(FDEP_L1, FDEM_CLOS,
    977     0   stevel 	    (CE_CONT, "fd_close: fd unit %d part %d otype %x\n",
    978     0   stevel 	    unit, part, otyp));
    979     0   stevel 
    980     0   stevel 	if (otyp == OTYP_LYR) {
    981     0   stevel 		if (fdp->d_lyropen[part])
    982     0   stevel 			fdp->d_lyropen[part]--;
    983     0   stevel 		part_is_closed = (fdp->d_lyropen[part] == 0);
    984     0   stevel 	} else {
    985     0   stevel 		fdp->d_regopen[otyp] &= ~(1<<part);
    986     0   stevel 		part_is_closed = 1;
    987     0   stevel 	}
    988     0   stevel 	if (part_is_closed) {
    989     0   stevel 		if (part == 2 && fdp->d_exclmask&(1<<part))
    990     0   stevel 			fdp->d_exclmask = 0;
    991     0   stevel 		else
    992     0   stevel 			fdp->d_exclmask &= ~(1<<part);
    993     0   stevel 		FDERRPRINT(FDEP_L0, FDEM_CLOS,
    994     0   stevel 		    (CE_CONT,
    995     0   stevel 		    "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n",
    996     0   stevel 		    fdp->d_exclmask, fdp->d_regopen[otyp],
    997     0   stevel 		    fdp->d_lyropen[part]));
    998     0   stevel 
    999     0   stevel 		if (fd_unit_is_open(fdp) == 0)
   1000     0   stevel 			fdp->d_obj->fj_flags &= ~FUNIT_CHANGED;
   1001     0   stevel 	}
   1002     0   stevel 	sema_v(&fdp->d_ocsem);
   1003     0   stevel 	return (0);
   1004     0   stevel }
   1005     0   stevel 
   1006     0   stevel /* ARGSUSED */
   1007     0   stevel static int
   1008     0   stevel fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
   1009     0   stevel {
   1010     0   stevel 	return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
   1011     0   stevel }
   1012     0   stevel 
   1013     0   stevel /* ARGSUSED */
   1014     0   stevel static int
   1015     0   stevel fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
   1016     0   stevel {
   1017     0   stevel 	return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
   1018     0   stevel }
   1019     0   stevel 
   1020     0   stevel /*
   1021     0   stevel  * fd_strategy
   1022     0   stevel  *	checks operation, hangs buf struct off fdcntlr, calls fdstart
   1023     0   stevel  *	if not already busy.  Note that if we call start, then the operation
   1024     0   stevel  *	will already be done on return (start sleeps).
   1025     0   stevel  */
   1026     0   stevel static int
   1027     0   stevel fd_strategy(struct buf *bp)
   1028     0   stevel {
   1029     0   stevel 	struct fcu_obj *fjp;
   1030     0   stevel 	struct fdisk *fdp;
   1031     0   stevel 	struct partition *pp;
   1032     0   stevel 
   1033     0   stevel 	FDERRPRINT(FDEP_L1, FDEM_STRA,
   1034     0   stevel 	    (CE_CONT, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
   1035     0   stevel 	    (void *)bp, bp->b_edev));
   1036     0   stevel 
   1037     0   stevel 	(void) fd_getdrive(bp->b_edev, &fjp, &fdp);
   1038     0   stevel 
   1039     0   stevel 	/*
   1040     0   stevel 	 * Ignoring return because device exist.
   1041     0   stevel 	 * Returned unit value is not used.
   1042     0   stevel 	 */
   1043     0   stevel 	pp = &fdp->d_part[PARTITION(bp->b_edev)];
   1044     0   stevel 
   1045     0   stevel 	if (fjp->fj_chars->fdc_sec_size > NBPSCTR && (bp->b_blkno & 1))  {
   1046     0   stevel 		FDERRPRINT(FDEP_L3, FDEM_STRA,
   1047     0   stevel 		    (CE_WARN, "fd%d: block %ld is not start of sector!",
   1048     0   stevel 		    DRIVE(bp->b_edev), (long)bp->b_blkno));
   1049     0   stevel 		bp->b_error = EINVAL;
   1050     0   stevel 		goto bad;
   1051     0   stevel 	}
   1052     0   stevel 
   1053     0   stevel 	if ((bp->b_blkno > pp->p_size)) {
   1054     0   stevel 		FDERRPRINT(FDEP_L3, FDEM_STRA,
   1055     0   stevel 		    (CE_WARN, "fd%d: block %ld is past the end! (nblk=%ld)",
   1056     0   stevel 		    DRIVE(bp->b_edev), (long)bp->b_blkno, pp->p_size));
   1057     0   stevel 		bp->b_error = ENOSPC;
   1058     0   stevel 		goto bad;
   1059     0   stevel 	}
   1060     0   stevel 
   1061     0   stevel 	/* if at end of file, skip out now */
   1062     0   stevel 	if (bp->b_blkno == pp->p_size) {
   1063     0   stevel 		if ((bp->b_flags & B_READ) == 0) {
   1064     0   stevel 			/* a write needs to get an error! */
   1065     0   stevel 			bp->b_error = ENOSPC;
   1066     0   stevel 			goto bad;
   1067     0   stevel 		}
   1068     0   stevel 		bp->b_resid = bp->b_bcount;
   1069     0   stevel 		biodone(bp);
   1070     0   stevel 		return (0);
   1071     0   stevel 	}
   1072     0   stevel 
   1073     0   stevel 	/* if operation not a multiple of sector size, is error! */
   1074     0   stevel 	if (bp->b_bcount % fjp->fj_chars->fdc_sec_size)  {
   1075     0   stevel 		FDERRPRINT(FDEP_L3, FDEM_STRA,
   1076     0   stevel 		    (CE_WARN, "fd%d: count %ld must be a multiple of %d",
   1077     0   stevel 		    DRIVE(bp->b_edev), bp->b_bcount,
   1078     0   stevel 		    fjp->fj_chars->fdc_sec_size));
   1079     0   stevel 		bp->b_error = EINVAL;
   1080     0   stevel 		goto bad;
   1081     0   stevel 	}
   1082     0   stevel 
   1083     0   stevel 	/*
   1084     0   stevel 	 * Put the buf request in the drive's queue, FIFO.
   1085     0   stevel 	 */
   1086     0   stevel 	bp->av_forw = 0;
   1087     0   stevel 	mutex_enter(&fjp->fj_lock);
   1088     0   stevel 	if (fdp->d_iostat)
   1089     0   stevel 		kstat_waitq_enter(KIOSP);
   1090     0   stevel 	if (fdp->d_actf)
   1091     0   stevel 		fdp->d_actl->av_forw = bp;
   1092     0   stevel 	else
   1093     0   stevel 		fdp->d_actf = bp;
   1094     0   stevel 	fdp->d_actl = bp;
   1095     0   stevel 	if (!(fjp->fj_flags & FUNIT_BUSY)) {
   1096     0   stevel 		fdstart(fjp);
   1097     0   stevel 	}
   1098     0   stevel 	mutex_exit(&fjp->fj_lock);
   1099     0   stevel 	return (0);
   1100     0   stevel 
   1101     0   stevel bad:
   1102     0   stevel 	bp->b_resid = bp->b_bcount;
   1103     0   stevel 	bp->b_flags |= B_ERROR;
   1104     0   stevel 	biodone(bp);
   1105     0   stevel 	return (0);
   1106     0   stevel }
   1107     0   stevel 
   1108     0   stevel /*
   1109     0   stevel  * fdstart
   1110     0   stevel  *	called from fd_strategy() or from fdXXXX() to setup and
   1111     0   stevel  *	start operations of read or write only (using buf structs).
   1112     0   stevel  *	Because the chip doesn't handle crossing cylinder boundaries on
   1113     0   stevel  *	the fly, this takes care of those boundary conditions.  Note that
   1114     0   stevel  *	it sleeps until the operation is done *within fdstart* - so that
   1115     0   stevel  *	when fdstart returns, the operation is already done.
   1116     0   stevel  */
   1117     0   stevel static void
   1118     0   stevel fdstart(struct fcu_obj *fjp)
   1119     0   stevel {
   1120     0   stevel 	struct buf *bp;
   1121     0   stevel 	struct fdisk *fdp = (struct fdisk *)fjp->fj_data;
   1122     0   stevel 	struct fd_char *chp;
   1123     0   stevel 	struct partition *pp;
   1124     0   stevel 	uint_t ptend;
   1125     0   stevel 	uint_t bincyl;		/* (the number of the desired) block in cyl. */
   1126     0   stevel 	uint_t blk, len, tlen;
   1127     0   stevel 	uint_t secpcyl;		/* number of sectors per cylinder */
   1128     0   stevel 	int cyl, head, sect;
   1129     0   stevel 	int sctrshft, unit;
   1130     0   stevel 	caddr_t	addr;
   1131     0   stevel 
   1132     0   stevel 	ASSERT(MUTEX_HELD(&fjp->fj_lock));
   1133     0   stevel 	fjp->fj_flags |= FUNIT_BUSY;
   1134     0   stevel 
   1135     0   stevel 	while ((bp = fdp->d_actf) != NULL) {
   1136     0   stevel 		fdp->d_actf = bp->av_forw;
   1137     0   stevel 		fdp->d_current = bp;
   1138     0   stevel 		if (fdp->d_iostat) {
   1139     0   stevel 			kstat_waitq_to_runq(KIOSP);
   1140     0   stevel 		}
   1141     0   stevel 		mutex_exit(&fjp->fj_lock);
   1142     0   stevel 
   1143     0   stevel 		FDERRPRINT(FDEP_L0, FDEM_STRT,
   1144     0   stevel 		    (CE_CONT, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n",
   1145     0   stevel 		    (void *)bp, (long)bp->b_blkno, bp->b_bcount));
   1146     0   stevel 		bp->b_flags &= ~B_ERROR;
   1147     0   stevel 		bp->b_error = 0;
   1148     0   stevel 		bp->b_resid = bp->b_bcount;	/* init resid */
   1149     0   stevel 
   1150     0   stevel 		ASSERT(DRIVE(bp->b_edev) == ddi_get_instance(fjp->fj_dip));
   1151     0   stevel 		unit = fjp->fj_unit;
   1152     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 1);
   1153     0   stevel 
   1154     0   stevel 		bp_mapin(bp);			/* map in buffers */
   1155     0   stevel 
   1156     0   stevel 		pp = &fdp->d_part[PARTITION(bp->b_edev)];
   1157     0   stevel 		/* starting blk adjusted for the partition */
   1158     0   stevel 		blk = bp->b_blkno + pp->p_start;
   1159     0   stevel 		ptend = pp->p_start + pp->p_size;   /* end of the partition */
   1160     0   stevel 
   1161     0   stevel 		chp = fjp->fj_chars;
   1162     0   stevel 		secpcyl = chp->fdc_nhead * chp->fdc_secptrack;
   1163     0   stevel 		switch (chp->fdc_sec_size) {
   1164     0   stevel 		/* convert logical block numbers to sector numbers */
   1165     0   stevel 		case 1024:
   1166     0   stevel 			sctrshft = SCTRSHFT + 1;
   1167     0   stevel 			blk >>= 1;
   1168     0   stevel 			ptend >>= 1;
   1169     0   stevel 			break;
   1170     0   stevel 		default:
   1171     0   stevel 		case NBPSCTR:
   1172     0   stevel 			sctrshft = SCTRSHFT;
   1173     0   stevel 			break;
   1174     0   stevel 		case 256:
   1175     0   stevel 			sctrshft = SCTRSHFT - 1;
   1176     0   stevel 			blk <<= 1;
   1177     0   stevel 			ptend <<= 1;
   1178     0   stevel 			break;
   1179     0   stevel 		}
   1180     0   stevel 
   1181     0   stevel 		/*
   1182     0   stevel 		 * If off the end, limit to actual amount that
   1183     0   stevel 		 * can be transferred.
   1184     0   stevel 		 */
   1185     0   stevel 		if ((blk + (bp->b_bcount >> sctrshft)) > ptend)
   1186     0   stevel 			/* to end of partition */
   1187     0   stevel 			len = (ptend - blk) << sctrshft;
   1188     0   stevel 		else
   1189     0   stevel 			len = bp->b_bcount;
   1190     0   stevel 		addr = bp->b_un.b_addr;		/* data buffer address */
   1191     0   stevel 
   1192     0   stevel 		/*
   1193     0   stevel 		 * now we have the real start blk, addr and len for xfer op
   1194     0   stevel 		 */
   1195     0   stevel 		while (len != 0) {
   1196     0   stevel 			/* start cyl of req */
   1197     0   stevel 			cyl = blk / secpcyl;
   1198     0   stevel 			bincyl = blk % secpcyl;
   1199     0   stevel 			/* start head of req */
   1200     0   stevel 			head = bincyl / chp->fdc_secptrack;
   1201     0   stevel 			/* start sector of req */
   1202     0   stevel 			sect = (bincyl % chp->fdc_secptrack) + 1;
   1203     0   stevel 			/*
   1204     0   stevel 			 * If the desired block and length will go beyond the
   1205     0   stevel 			 * cylinder end, then limit it to the cylinder end.
   1206     0   stevel 			 */
   1207     0   stevel 			if (bp->b_flags & B_READ) {
   1208     0   stevel 				if (len > ((secpcyl - bincyl) << sctrshft))
   1209     0   stevel 					tlen = (secpcyl - bincyl) << sctrshft;
   1210     0   stevel 				else
   1211     0   stevel 					tlen = len;
   1212     0   stevel 			} else {
   1213     0   stevel 				if (len >
   1214     0   stevel 				    ((chp->fdc_secptrack - sect + 1) <<
   1215     0   stevel 				    sctrshft))
   1216     0   stevel 					tlen =
   1217     0   stevel 					    (chp->fdc_secptrack - sect + 1) <<
   1218     0   stevel 					    sctrshft;
   1219     0   stevel 				else
   1220     0   stevel 					tlen = len;
   1221     0   stevel 			}
   1222     0   stevel 
   1223     0   stevel 			FDERRPRINT(FDEP_L0, FDEM_STRT, (CE_CONT,
   1224     0   stevel 			    "  blk 0x%x addr 0x%p len 0x%x "
   1225     0   stevel 			    "cyl %d head %d sec %d\n  resid 0x%lx, tlen %d\n",
   1226     0   stevel 			    blk, (void *)addr, len, cyl, head, sect,
   1227     0   stevel 			    bp->b_resid, tlen));
   1228     0   stevel 
   1229     0   stevel 			/*
   1230     0   stevel 			 * (try to) do the operation - failure returns an errno
   1231     0   stevel 			 */
   1232     0   stevel 			bp->b_error = fjp->fj_ops->fco_rw(fjp, unit,
   1233     0   stevel 			    bp->b_flags & B_READ, cyl, head, sect, addr, tlen);
   1234     0   stevel 			if (bp->b_error != 0) {
   1235     0   stevel 				FDERRPRINT(FDEP_L3, FDEM_STRT, (CE_WARN,
   1236     0   stevel 				    "fdstart: bad exec of bp: 0x%p, err=%d",
   1237     0   stevel 				    (void *)bp, bp->b_error));
   1238     0   stevel 				bp->b_flags |= B_ERROR;
   1239     0   stevel 				break;
   1240     0   stevel 			}
   1241     0   stevel 			blk += tlen >> sctrshft;
   1242     0   stevel 			len -= tlen;
   1243     0   stevel 			addr += tlen;
   1244     0   stevel 			bp->b_resid -= tlen;
   1245     0   stevel 		}
   1246     0   stevel 		FDERRPRINT(FDEP_L0, FDEM_STRT,
   1247     0   stevel 		    (CE_CONT, "fdstart done: b_resid %lu, b_count %lu\n",
   1248     0   stevel 		    bp->b_resid, bp->b_bcount));
   1249     0   stevel 		if (fdp->d_iostat) {
   1250     0   stevel 			if (bp->b_flags & B_READ) {
   1251     0   stevel 				KIOSP->reads++;
   1252     0   stevel 				KIOSP->nread += (bp->b_bcount - bp->b_resid);
   1253     0   stevel 			} else {
   1254     0   stevel 				KIOSP->writes++;
   1255     0   stevel 				KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
   1256     0   stevel 			}
   1257     0   stevel 			kstat_runq_exit(KIOSP);
   1258     0   stevel 		}
   1259     0   stevel 		bp_mapout(bp);
   1260     0   stevel 		biodone(bp);
   1261     0   stevel 
   1262     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 0);
   1263     0   stevel 		mutex_enter(&fjp->fj_lock);
   1264     0   stevel 		fdp->d_current = 0;
   1265     0   stevel 	}
   1266     0   stevel 	fjp->fj_flags ^= FUNIT_BUSY;
   1267     0   stevel }
   1268     0   stevel 
   1269     0   stevel /* ARGSUSED */
   1270     0   stevel static int
   1271     0   stevel fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
   1272     0   stevel 	int *rval_p)
   1273     0   stevel {
   1274     0   stevel 	union {
   1275     0   stevel 		struct dk_cinfo dki;
   1276     0   stevel 		struct dk_geom dkg;
   1277     0   stevel 		struct dk_allmap dka;
   1278     0   stevel 		struct fd_char fdchar;
   1279     0   stevel 		struct fd_drive drvchar;
   1280     0   stevel 		int	temp;
   1281     0   stevel 	} cpy;
   1282     0   stevel 	struct vtoc vtoc;
   1283     0   stevel 	struct fcu_obj *fjp = NULL;
   1284     0   stevel 	struct fdisk *fdp = NULL;
   1285     0   stevel 	struct dk_map *dmp;
   1286     0   stevel 	struct dk_label *label;
   1287     0   stevel 	int nblks, part, unit;
   1288     0   stevel 	int rval = 0;
   1289     0   stevel 	enum dkio_state state;
   1290     0   stevel 
   1291     0   stevel 	unit = fd_getdrive(dev, &fjp, &fdp);
   1292     0   stevel 	if (!fjp || !fdp)
   1293     0   stevel 		return (ENXIO);
   1294     0   stevel 
   1295     0   stevel 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
   1296     0   stevel 	    (CE_CONT, "fd_ioctl fd unit %d: cmd %x, arg %lx\n",
   1297     0   stevel 	    unit, cmd, arg));
   1298     0   stevel 
   1299     0   stevel 	switch (cmd) {
   1300     0   stevel 	case DKIOCINFO:
   1301     0   stevel 		fjp->fj_ops->fco_dkinfo(fjp, &cpy.dki);
   1302     0   stevel 		cpy.dki.dki_cnum = FDCTLR(fjp->fj_unit);
   1303     0   stevel 		cpy.dki.dki_unit = FDUNIT(fjp->fj_unit);
   1304     0   stevel 		cpy.dki.dki_partition = PARTITION(dev);
   1305     0   stevel 		if (ddi_copyout(&cpy.dki, (void *)arg, sizeof (cpy.dki), flag))
   1306     0   stevel 			rval = EFAULT;
   1307     0   stevel 		break;
   1308     0   stevel 
   1309     0   stevel 	case DKIOCG_PHYGEOM:
   1310     0   stevel 	case DKIOCG_VIRTGEOM:
   1311     0   stevel 		cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
   1312     0   stevel 		goto get_geom;
   1313     0   stevel 	case DKIOCGGEOM:
   1314     0   stevel 		if (fjp->fj_flags & FUNIT_LABELOK)
   1315     0   stevel 			cpy.dkg.dkg_nsect = (fjp->fj_chars->fdc_secptrack *
   1316     0   stevel 			    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
   1317     0   stevel 		else
   1318     0   stevel 			cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
   1319     0   stevel get_geom:
   1320     0   stevel 		cpy.dkg.dkg_pcyl = fjp->fj_chars->fdc_ncyl;
   1321     0   stevel 		cpy.dkg.dkg_ncyl = fjp->fj_chars->fdc_ncyl;
   1322     0   stevel 		cpy.dkg.dkg_nhead = fjp->fj_chars->fdc_nhead;
   1323     0   stevel 		cpy.dkg.dkg_intrlv = fjp->fj_attr->fda_intrlv;
   1324     0   stevel 		cpy.dkg.dkg_rpm = fjp->fj_attr->fda_rotatespd;
   1325     0   stevel 		cpy.dkg.dkg_read_reinstruct =
   1326     0   stevel 		    (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
   1327     0   stevel 		cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
   1328     0   stevel 		if (ddi_copyout(&cpy.dkg, (void *)arg, sizeof (cpy.dkg), flag))
   1329     0   stevel 			rval = EFAULT;
   1330     0   stevel 		break;
   1331     0   stevel 
   1332     0   stevel 	case DKIOCSGEOM:
   1333     0   stevel 		if (ddi_copyin((void *)arg, &cpy.dkg,
   1334     0   stevel 		    sizeof (struct dk_geom), flag)) {
   1335     0   stevel 			rval = EFAULT;
   1336     0   stevel 			break;
   1337     0   stevel 		}
   1338     0   stevel 		mutex_enter(&fjp->fj_lock);
   1339     0   stevel 		fjp->fj_chars->fdc_ncyl = cpy.dkg.dkg_ncyl;
   1340     0   stevel 		fjp->fj_chars->fdc_nhead = cpy.dkg.dkg_nhead;
   1341     0   stevel 		fjp->fj_chars->fdc_secptrack = cpy.dkg.dkg_nsect;
   1342     0   stevel 		fjp->fj_attr->fda_intrlv = cpy.dkg.dkg_intrlv;
   1343     0   stevel 		fjp->fj_attr->fda_rotatespd = cpy.dkg.dkg_rpm;
   1344     0   stevel 		fdp->d_curfdtype = -1;
   1345     0   stevel 		mutex_exit(&fjp->fj_lock);
   1346     0   stevel 		break;
   1347     0   stevel 
   1348     0   stevel 	/*
   1349     0   stevel 	 * return the map of all logical partitions
   1350     0   stevel 	 */
   1351     0   stevel 	case DKIOCGAPART:
   1352     0   stevel 		/*
   1353     0   stevel 		 * Note the conversion from starting sector number
   1354     0   stevel 		 * to starting cylinder number.
   1355     0   stevel 		 * Return error if division results in a remainder.
   1356     0   stevel 		 */
   1357     0   stevel 		nblks = fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack;
   1358     0   stevel 
   1359     0   stevel #ifdef _MULTI_DATAMODEL
   1360     0   stevel 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1361     0   stevel 		case DDI_MODEL_ILP32:
   1362     0   stevel 		{
   1363     0   stevel 			struct dk_allmap32 dka32;
   1364     0   stevel 
   1365     0   stevel 			for (part = 0; part < NDKMAP; part++) {
   1366     0   stevel 				if ((fdp->d_part[part].p_start % nblks) != 0)
   1367     0   stevel 					return (EINVAL);
   1368     0   stevel 				dka32.dka_map[part].dkl_cylno =
   1369     0   stevel 				    fdp->d_part[part].p_start / nblks;
   1370     0   stevel 				dka32.dka_map[part].dkl_nblk =
   1371     0   stevel 				    fdp->d_part[part].p_size;
   1372     0   stevel 			}
   1373     0   stevel 
   1374     0   stevel 			if (ddi_copyout(&dka32, (void *)arg,
   1375     0   stevel 			    sizeof (struct dk_allmap32), flag))
   1376     0   stevel 				rval = EFAULT;
   1377     0   stevel 
   1378     0   stevel 			break;
   1379     0   stevel 		}
   1380     0   stevel 		case DDI_MODEL_NONE:
   1381     0   stevel 
   1382     0   stevel #endif /* _MULTI_DATAMODEL */
   1383     0   stevel 
   1384     0   stevel 			dmp = (struct dk_map *)&cpy.dka;
   1385     0   stevel 			for (part = 0; part < NDKMAP; part++) {
   1386     0   stevel 				if ((fdp->d_part[part].p_start % nblks) != 0)
   1387     0   stevel 					return (EINVAL);
   1388     0   stevel 				dmp->dkl_cylno =
   1389     0   stevel 				    fdp->d_part[part].p_start / nblks;
   1390     0   stevel 				dmp->dkl_nblk = fdp->d_part[part].p_size;
   1391     0   stevel 				dmp++;
   1392     0   stevel 			}
   1393     0   stevel 
   1394     0   stevel 			if (ddi_copyout(&cpy.dka, (void *)arg,
   1395     0   stevel 			    sizeof (struct dk_allmap), flag))
   1396     0   stevel 				rval = EFAULT;
   1397     0   stevel #ifdef _MULTI_DATAMODEL
   1398     0   stevel 			break;
   1399     0   stevel 
   1400     0   stevel 		}
   1401     0   stevel #endif /* _MULTI_DATAMODEL */
   1402     0   stevel 
   1403     0   stevel 		break;
   1404     0   stevel 
   1405     0   stevel 	/*
   1406     0   stevel 	 * Set the map of all logical partitions
   1407     0   stevel 	 */
   1408     0   stevel 	case DKIOCSAPART:
   1409     0   stevel 
   1410     0   stevel #ifdef _MULTI_DATAMODEL
   1411     0   stevel 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1412     0   stevel 		case DDI_MODEL_ILP32:
   1413     0   stevel 		{
   1414     0   stevel 			struct dk_allmap32 dka32;
   1415     0   stevel 
   1416     0   stevel 			if (ddi_copyin((void *)arg, &dka32,
   1417     0   stevel 			    sizeof (dka32), flag)) {
   1418     0   stevel 				rval = EFAULT;
   1419     0   stevel 				break;
   1420     0   stevel 			}
   1421     0   stevel 			for (part = 0; part < NDKMAP; part++) {
   1422     0   stevel 				cpy.dka.dka_map[part].dkl_cylno =
   1423     0   stevel 				    dka32.dka_map[part].dkl_cylno;
   1424     0   stevel 				cpy.dka.dka_map[part].dkl_nblk =
   1425     0   stevel 				    dka32.dka_map[part].dkl_nblk;
   1426     0   stevel 			}
   1427     0   stevel 			break;
   1428     0   stevel 		}
   1429     0   stevel 		case DDI_MODEL_NONE:
   1430     0   stevel 
   1431     0   stevel #endif /* _MULTI_DATAMODEL */
   1432     0   stevel 		if (ddi_copyin((void *)arg, &cpy.dka, sizeof (cpy.dka), flag))
   1433     0   stevel 			rval = EFAULT;
   1434     0   stevel #ifdef _MULTI_DATAMODEL
   1435     0   stevel 
   1436     0   stevel 			break;
   1437     0   stevel 		}
   1438     0   stevel #endif /* _MULTI_DATAMODEL */
   1439     0   stevel 
   1440     0   stevel 		if (rval != 0)
   1441     0   stevel 			break;
   1442     0   stevel 
   1443     0   stevel 		dmp = (struct dk_map *)&cpy.dka;
   1444     0   stevel 		nblks = fjp->fj_chars->fdc_nhead *
   1445     0   stevel 		    fjp->fj_chars->fdc_secptrack;
   1446     0   stevel 		mutex_enter(&fjp->fj_lock);
   1447     0   stevel 		/*
   1448     0   stevel 		 * Note the conversion from starting cylinder number
   1449     0   stevel 		 * to starting sector number.
   1450     0   stevel 		 */
   1451     0   stevel 		for (part = 0; part < NDKMAP; part++) {
   1452     0   stevel 			fdp->d_part[part].p_start = dmp->dkl_cylno *
   1453     0   stevel 			    nblks;
   1454     0   stevel 			fdp->d_part[part].p_size = dmp->dkl_nblk;
   1455     0   stevel 			dmp++;
   1456     0   stevel 		}
   1457     0   stevel 		mutex_exit(&fjp->fj_lock);
   1458     0   stevel 
   1459     0   stevel 		break;
   1460     0   stevel 
   1461     0   stevel 	case DKIOCGVTOC:
   1462     0   stevel 		mutex_enter(&fjp->fj_lock);
   1463     0   stevel 
   1464     0   stevel 		/*
   1465     0   stevel 		 * Exit if the diskette has no label.
   1466     0   stevel 		 * Also, get the label to make sure the correct one is
   1467     0   stevel 		 * being used since the diskette may have changed
   1468     0   stevel 		 */
   1469     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 1);
   1470     0   stevel 		rval = fdgetlabel(fjp, unit);
   1471     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 0);
   1472     0   stevel 		if (rval) {
   1473     0   stevel 			mutex_exit(&fjp->fj_lock);
   1474     0   stevel 			rval = EINVAL;
   1475     0   stevel 			break;
   1476     0   stevel 		}
   1477     0   stevel 
   1478     0   stevel 		fd_build_user_vtoc(fjp, fdp, &vtoc);
   1479     0   stevel 		mutex_exit(&fjp->fj_lock);
   1480     0   stevel 
   1481     0   stevel #ifdef _MULTI_DATAMODEL
   1482     0   stevel 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1483     0   stevel 		case DDI_MODEL_ILP32:
   1484     0   stevel 		{
   1485     0   stevel 			struct vtoc32	vtoc32;
   1486     0   stevel 
   1487     0   stevel 			vtoctovtoc32(vtoc, vtoc32);
   1488     0   stevel 
   1489     0   stevel 			if (ddi_copyout(&vtoc32, (void *)arg,
   1490     0   stevel 			    sizeof (vtoc32), flag))
   1491     0   stevel 				rval = EFAULT;
   1492     0   stevel 
   1493     0   stevel 			break;
   1494     0   stevel 		}
   1495     0   stevel 		case DDI_MODEL_NONE:
   1496     0   stevel 
   1497     0   stevel #endif /* _MULTI_DATAMODEL */
   1498     0   stevel 			if (ddi_copyout(&vtoc, (void *)arg,
   1499     0   stevel 			    sizeof (vtoc), flag))
   1500     0   stevel 				rval = EFAULT;
   1501     0   stevel #ifdef _MULTI_DATAMODEL
   1502     0   stevel 			break;
   1503     0   stevel 		}
   1504     0   stevel #endif /* _MULTI_DATAMODEL */
   1505     0   stevel 
   1506     0   stevel 		break;
   1507     0   stevel 
   1508     0   stevel 	case DKIOCSVTOC:
   1509     0   stevel 
   1510     0   stevel #ifdef _MULTI_DATAMODEL
   1511     0   stevel 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1512     0   stevel 		case DDI_MODEL_ILP32:
   1513     0   stevel 		{
   1514     0   stevel 			struct vtoc32	vtoc32;
   1515     0   stevel 
   1516     0   stevel 			if (ddi_copyin((void *)arg, &vtoc32,
   1517     0   stevel 			    sizeof (vtoc32), flag)) {
   1518     0   stevel 				rval = EFAULT;
   1519     0   stevel 				break;
   1520     0   stevel 			}
   1521     0   stevel 
   1522     0   stevel 			vtoc32tovtoc(vtoc32, vtoc);
   1523     0   stevel 
   1524     0   stevel 			break;
   1525     0   stevel 		}
   1526     0   stevel 		case DDI_MODEL_NONE:
   1527     0   stevel 
   1528     0   stevel #endif /* _MULTI_DATAMODEL */
   1529     0   stevel 			if (ddi_copyin((void *)arg, &vtoc, sizeof (vtoc), flag))
   1530     0   stevel 				rval = EFAULT;
   1531     0   stevel #ifdef _MULTI_DATAMODEL
   1532     0   stevel 			break;
   1533     0   stevel 		}
   1534     0   stevel #endif /* _MULTI_DATAMODEL */
   1535     0   stevel 
   1536     0   stevel 		if (rval != 0)
   1537     0   stevel 			break;
   1538     0   stevel 
   1539     0   stevel 
   1540     0   stevel 		label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
   1541     0   stevel 
   1542     0   stevel 		mutex_enter(&fjp->fj_lock);
   1543     0   stevel 
   1544     0   stevel 		if ((rval = fd_build_label_vtoc(fjp, fdp, &vtoc, label)) == 0) {
   1545     0   stevel 			fjp->fj_ops->fco_select(fjp, unit, 1);
   1546     0   stevel 			rval = fjp->fj_ops->fco_rw(fjp, unit, FDWRITE,
   1547     0   stevel 			    0, 0, 1, (caddr_t)label, sizeof (struct dk_label));
   1548     0   stevel 			fjp->fj_ops->fco_select(fjp, unit, 0);
   1549     0   stevel 		}
   1550     0   stevel 		mutex_exit(&fjp->fj_lock);
   1551     0   stevel 		kmem_free(label, sizeof (struct dk_label));
   1552     0   stevel 		break;
   1553     0   stevel 
   1554     0   stevel 	case DKIOCSTATE:
   1555     0   stevel 		FDERRPRINT(FDEP_L1, FDEM_IOCT,
   1556     0   stevel 		    (CE_CONT, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit));
   1557     0   stevel 
   1558     0   stevel 		if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) {
   1559     0   stevel 			rval = EFAULT;
   1560     0   stevel 			break;
   1561     0   stevel 		}
   1562     0   stevel 
   1563     0   stevel 		rval = fd_check_media(dev, state);
   1564     0   stevel 
   1565     0   stevel 		if (ddi_copyout(&fdp->d_media_state, (void *)arg,
   1566     0   stevel 		    sizeof (int), flag))
   1567     0   stevel 			rval = EFAULT;
   1568     0   stevel 		break;
   1569     0   stevel 
   1570     0   stevel 	case FDIOGCHAR:
   1571     0   stevel 		if (ddi_copyout(fjp->fj_chars, (void *)arg,
   1572     0   stevel 		    sizeof (struct fd_char), flag))
   1573     0   stevel 			rval = EFAULT;
   1574     0   stevel 		break;
   1575     0   stevel 
   1576     0   stevel 	case FDIOSCHAR:
   1577     0   stevel 		if (ddi_copyin((void *)arg, &cpy.fdchar,
   1578     0   stevel 		    sizeof (struct fd_char), flag)) {
   1579     0   stevel 			rval = EFAULT;
   1580     0   stevel 			break;
   1581     0   stevel 		}
   1582     0   stevel 		switch (cpy.fdchar.fdc_transfer_rate) {
   1583     0   stevel 		case 417:
   1584     0   stevel 			if ((fdp->d_media & (1 << FMT_3M)) == 0) {
   1585     0   stevel 				cmn_err(CE_CONT,
   1586     0   stevel 				    "fdioschar:Medium density not supported\n");
   1587     0   stevel 				rval = EINVAL;
   1588     0   stevel 				break;
   1589     0   stevel 			}
   1590     0   stevel 			mutex_enter(&fjp->fj_lock);
   1591     0   stevel 			fjp->fj_attr->fda_rotatespd = 360;
   1592     0   stevel 			mutex_exit(&fjp->fj_lock);
   1593     0   stevel 			/* cpy.fdchar.fdc_transfer_rate = 500; */
   1594     0   stevel 			/* FALLTHROUGH */
   1595     0   stevel 		case 1000:
   1596     0   stevel 		case 500:
   1597     0   stevel 		case 300:
   1598     0   stevel 		case 250:
   1599     0   stevel 			mutex_enter(&fjp->fj_lock);
   1600     0   stevel 			*(fjp->fj_chars) = cpy.fdchar;
   1601     0   stevel 			fdp->d_curfdtype = -1;
   1602     0   stevel 			fjp->fj_flags &= ~FUNIT_CHAROK;
   1603     0   stevel 			mutex_exit(&fjp->fj_lock);
   1604     0   stevel 
   1605     0   stevel 			break;
   1606     0   stevel 
   1607     0   stevel 		default:
   1608     0   stevel 			FDERRPRINT(FDEP_L4, FDEM_IOCT,
   1609     0   stevel 			    (CE_WARN, "fd_ioctl fd unit %d: FDIOSCHAR odd "
   1610  7656   Sherry 			    "xfer rate %dkbs",
   1611  7656   Sherry 			    unit, cpy.fdchar.fdc_transfer_rate));
   1612     0   stevel 			rval = EINVAL;
   1613     0   stevel 			break;
   1614     0   stevel 		}
   1615     0   stevel 		break;
   1616     0   stevel 
   1617     0   stevel 	/*
   1618     0   stevel 	 * set all characteristics and geometry to the defaults
   1619     0   stevel 	 */
   1620     0   stevel 	case FDDEFGEOCHAR:
   1621     0   stevel 		mutex_enter(&fjp->fj_lock);
   1622     0   stevel 		fdp->d_curfdtype = fdp->d_deffdtype;
   1623     0   stevel 		*fjp->fj_chars = *defchar[fdp->d_curfdtype];
   1624     0   stevel 		*fjp->fj_attr = fdtypes[fdp->d_curfdtype];
   1625     0   stevel 		bcopy(fdparts[fdp->d_curfdtype],
   1626     0   stevel 		    fdp->d_part, sizeof (struct partition) * NDKMAP);
   1627     0   stevel 		fjp->fj_flags &= ~FUNIT_CHAROK;
   1628     0   stevel 		mutex_exit(&fjp->fj_lock);
   1629     0   stevel 		break;
   1630     0   stevel 
   1631     0   stevel 	case FDEJECT:  /* eject disk */
   1632     0   stevel 	case DKIOCEJECT:
   1633     0   stevel 		fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
   1634     0   stevel 		rval = ENOSYS;
   1635     0   stevel 		break;
   1636     0   stevel 
   1637     0   stevel 	case FDGETCHANGE: /* disk changed */
   1638     0   stevel 		if (ddi_copyin((void *)arg, &cpy.temp, sizeof (int), flag)) {
   1639     0   stevel 			rval = EFAULT;
   1640     0   stevel 			break;
   1641     0   stevel 		}
   1642     0   stevel 		mutex_enter(&fjp->fj_lock);
   1643     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 1);
   1644     0   stevel 
   1645     0   stevel 		if (fjp->fj_flags & FUNIT_CHANGED)
   1646     0   stevel 			cpy.temp |= FDGC_HISTORY;
   1647     0   stevel 		else
   1648     0   stevel 			cpy.temp &= ~FDGC_HISTORY;
   1649     0   stevel 		fjp->fj_flags &= ~FUNIT_CHANGED;
   1650     0   stevel 
   1651     0   stevel 		if (fjp->fj_ops->fco_getchng(fjp, unit)) {
   1652     0   stevel 			cpy.temp |= FDGC_DETECTED;
   1653     0   stevel 			fjp->fj_ops->fco_resetchng(fjp, unit);
   1654     0   stevel 			/*
   1655     0   stevel 			 * check diskette again only if it was removed
   1656     0   stevel 			 */
   1657     0   stevel 			if (fjp->fj_ops->fco_getchng(fjp, unit)) {
   1658     0   stevel 				/*
   1659     0   stevel 				 * no diskette is present
   1660     0   stevel 				 */
   1661     0   stevel 				cpy.temp |= FDGC_CURRENT;
   1662     0   stevel 				if (fjp->fj_flags & FUNIT_CHGDET)
   1663     0   stevel 					/*
   1664     0   stevel 					 * again no diskette; not a new change
   1665     0   stevel 					 */
   1666     0   stevel 					cpy.temp ^= FDGC_DETECTED;
   1667     0   stevel 				else
   1668     0   stevel 					fjp->fj_flags |= FUNIT_CHGDET;
   1669     0   stevel 			} else {
   1670     0   stevel 				/*
   1671     0   stevel 				 * a new diskette is present
   1672     0   stevel 				 */
   1673     0   stevel 				cpy.temp &= ~FDGC_CURRENT;
   1674     0   stevel 				fjp->fj_flags &= ~FUNIT_CHGDET;
   1675     0   stevel 			}
   1676     0   stevel 		} else {
   1677     0   stevel 			cpy.temp &= ~(FDGC_DETECTED | FDGC_CURRENT);
   1678     0   stevel 			fjp->fj_flags &= ~FUNIT_CHGDET;
   1679     0   stevel 		}
   1680     0   stevel 		/*
   1681     0   stevel 		 * also get state of write protection
   1682     0   stevel 		 */
   1683     0   stevel 		if (fjp->fj_flags & FUNIT_WPROT) {
   1684     0   stevel 			cpy.temp |= FDGC_CURWPROT;
   1685     0   stevel 		} else {
   1686     0   stevel 			cpy.temp &= ~FDGC_CURWPROT;
   1687     0   stevel 		}
   1688     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 0);
   1689     0   stevel 		mutex_exit(&fjp->fj_lock);
   1690     0   stevel 
   1691     0   stevel 		if (ddi_copyout(&cpy.temp, (void *)arg, sizeof (int), flag))
   1692     0   stevel 			rval = EFAULT;
   1693     0   stevel 		break;
   1694     0   stevel 
   1695     0   stevel 	case FDGETDRIVECHAR:
   1696     0   stevel 		if (ddi_copyout(fjp->fj_drive, (void *)arg,
   1697     0   stevel 		    sizeof (struct fd_drive), flag))
   1698     0   stevel 			rval = EFAULT;
   1699     0   stevel 		break;
   1700     0   stevel 
   1701     0   stevel 	case FDSETDRIVECHAR:
   1702     0   stevel 		if (ddi_copyin((void *)arg, &cpy.drvchar,
   1703     0   stevel 		    sizeof (struct fd_drive), flag)) {
   1704     0   stevel 			rval = EFAULT;
   1705     0   stevel 			break;
   1706     0   stevel 		}
   1707     0   stevel 		mutex_enter(&fjp->fj_lock);
   1708     0   stevel 		*(fjp->fj_drive) = cpy.drvchar;
   1709     0   stevel 		fdp->d_curfdtype = -1;
   1710     0   stevel 		fjp->fj_flags &= ~FUNIT_CHAROK;
   1711     0   stevel 		mutex_exit(&fjp->fj_lock);
   1712     0   stevel 		break;
   1713     0   stevel 
   1714     0   stevel 	case DKIOCREMOVABLE: {
   1715     0   stevel 		int	i = 1;
   1716     0   stevel 
   1717     0   stevel 		/* no brainer: floppies are always removable */
   1718     0   stevel 		if (ddi_copyout(&i, (void *)arg, sizeof (int), flag)) {
   1719     0   stevel 			rval = EFAULT;
   1720     0   stevel 		}
   1721     0   stevel 		break;
   1722     0   stevel 	}
   1723     0   stevel 
   1724     0   stevel 	case DKIOCGMEDIAINFO:
   1725     0   stevel 		rval = fd_get_media_info(fjp, (caddr_t)arg, flag);
   1726     0   stevel 		break;
   1727     0   stevel 
   1728     0   stevel 	case FDIOCMD:
   1729     0   stevel 	{
   1730     0   stevel 		struct fd_cmd fc;
   1731     0   stevel 		int cyl, head, spc, spt;
   1732     0   stevel 
   1733     0   stevel #ifdef _MULTI_DATAMODEL
   1734     0   stevel 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1735     0   stevel 		case DDI_MODEL_ILP32:
   1736     0   stevel 		{
   1737     0   stevel 			struct fd_cmd32 fc32;
   1738     0   stevel 
   1739     0   stevel 			if (ddi_copyin((void *)arg, &fc32,
   1740     0   stevel 			    sizeof (fc32), flag)) {
   1741     0   stevel 				rval = EFAULT;
   1742     0   stevel 				break;
   1743     0   stevel 			}
   1744     0   stevel 
   1745     0   stevel 			fc.fdc_cmd = fc32.fdc_cmd;
   1746     0   stevel 			fc.fdc_flags = fc32.fdc_flags;
   1747     0   stevel 			fc.fdc_blkno = fc32.fdc_blkno;
   1748     0   stevel 			fc.fdc_secnt = fc32.fdc_secnt;
   1749     0   stevel 			fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
   1750     0   stevel 			fc.fdc_buflen = fc32.fdc_buflen;
   1751     0   stevel 
   1752     0   stevel 			break;
   1753     0   stevel 		}
   1754     0   stevel 		case DDI_MODEL_NONE:
   1755     0   stevel 
   1756     0   stevel #endif /* _MULTI_DATAMODEL */
   1757     0   stevel 
   1758     0   stevel 			if (ddi_copyin((void *)arg, &fc, sizeof (fc), flag)) {
   1759     0   stevel 				rval = EFAULT;
   1760     0   stevel 				break;
   1761     0   stevel 			}
   1762     0   stevel #ifdef _MULTI_DATAMODEL
   1763     0   stevel 			break;
   1764     0   stevel 		}
   1765     0   stevel #endif /* _MULTI_DATAMODEL */
   1766     0   stevel 
   1767     0   stevel 		if (rval != 0)
   1768     0   stevel 			break;
   1769     0   stevel 
   1770     0   stevel 	if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
   1771     0   stevel 			auto struct iovec aiov;
   1772     0   stevel 			auto struct uio auio;
   1773     0   stevel 			struct uio *uio = &auio;
   1774     0   stevel 
   1775     0   stevel 			spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
   1776     0   stevel 
   1777     0   stevel 			bzero(&auio, sizeof (struct uio));
   1778     0   stevel 			bzero(&aiov, sizeof (struct iovec));
   1779     0   stevel 			aiov.iov_base = fc.fdc_bufaddr;
   1780     0   stevel 			aiov.iov_len = (uint_t)fc.fdc_secnt *
   1781     0   stevel 			    fjp->fj_chars->fdc_sec_size;
   1782     0   stevel 			uio->uio_iov = &aiov;
   1783     0   stevel 
   1784     0   stevel 			uio->uio_iovcnt = 1;
   1785     0   stevel 			uio->uio_resid = aiov.iov_len;
   1786     0   stevel 			uio->uio_segflg = UIO_USERSPACE;
   1787     0   stevel 
   1788     0   stevel 			rval = physio(fd_strategy, (struct buf *)0, dev,
   1789     0   stevel 			    spc, minphys, uio);
   1790     0   stevel 			break;
   1791     0   stevel 		} else if (fc.fdc_cmd == FDCMD_FORMAT_TRACK) {
   1792     0   stevel 			spt = fjp->fj_chars->fdc_secptrack;	/* sec/trk */
   1793     0   stevel 			spc = fjp->fj_chars->fdc_nhead * spt;	/* sec/cyl */
   1794     0   stevel 			cyl = fc.fdc_blkno / spc;
   1795     0   stevel 			head = (fc.fdc_blkno % spc) / spt;
   1796     0   stevel 			if ((cyl | head) == 0)
   1797     0   stevel 				fjp->fj_flags &=
   1798     0   stevel 				    ~(FUNIT_LABELOK | FUNIT_UNLABELED);
   1799     0   stevel 
   1800     0   stevel 			FDERRPRINT(FDEP_L0, FDEM_FORM,
   1801     0   stevel 			    (CE_CONT, "fd_format cyl %d, hd %d\n", cyl, head));
   1802     0   stevel 			fjp->fj_ops->fco_select(fjp, unit, 1);
   1803     0   stevel 			rval = fjp->fj_ops->fco_format(fjp, unit, cyl, head,
   1804     0   stevel 			    (int)fc.fdc_flags);
   1805     0   stevel 			fjp->fj_ops->fco_select(fjp, unit, 0);
   1806     0   stevel 
   1807     0   stevel 			break;
   1808     0   stevel 		}
   1809     0   stevel 		FDERRPRINT(FDEP_L4, FDEM_IOCT,
   1810     0   stevel 		    (CE_WARN, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete",
   1811     0   stevel 		    unit));
   1812     0   stevel 		rval = EINVAL;
   1813     0   stevel 		break;
   1814     0   stevel 	}
   1815     0   stevel 
   1816     0   stevel 	case FDRAW:
   1817     0   stevel 		rval = fd_rawioctl(fjp, unit, (caddr_t)arg, flag);
   1818     0   stevel 		break;
   1819     0   stevel 
   1820     0   stevel 	default:
   1821     0   stevel 		FDERRPRINT(FDEP_L4, FDEM_IOCT,
   1822     0   stevel 		    (CE_WARN, "fd_ioctl fd unit %d: invalid ioctl 0x%x",
   1823     0   stevel 		    unit, cmd));
   1824     0   stevel 		rval = ENOTTY;
   1825     0   stevel 		break;
   1826     0   stevel 	}
   1827     0   stevel 	return (rval);
   1828     0   stevel }
   1829     0   stevel 
   1830     0   stevel static void
   1831     0   stevel fd_build_user_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp)
   1832     0   stevel {
   1833     0   stevel 	struct partition *vpart;
   1834     0   stevel 	int	i;
   1835     0   stevel 	int	xblk;
   1836     0   stevel 
   1837     0   stevel 	/*
   1838     0   stevel 	 * Return vtoc structure fields in the provided VTOC area, addressed
   1839     0   stevel 	 * by *vtocp.
   1840     0   stevel 	 *
   1841     0   stevel 	 */
   1842     0   stevel 	bzero(vtocp, sizeof (struct vtoc));
   1843     0   stevel 
   1844     0   stevel 	bcopy(fdp->d_vtoc_bootinfo,
   1845     0   stevel 	    vtocp->v_bootinfo, sizeof (vtocp->v_bootinfo));
   1846     0   stevel 
   1847     0   stevel 	vtocp->v_sanity = VTOC_SANE;
   1848     0   stevel 	vtocp->v_version = fdp->d_vtoc_version;
   1849     0   stevel 	bcopy(fdp->d_vtoc_volume, vtocp->v_volume, LEN_DKL_VVOL);
   1850     0   stevel 	if (fjp->fj_flags & FUNIT_LABELOK) {
   1851     0   stevel 		vtocp->v_sectorsz = DEV_BSIZE;
   1852     0   stevel 		xblk = 1;
   1853     0   stevel 	} else {
   1854     0   stevel 		vtocp->v_sectorsz = fjp->fj_chars->fdc_sec_size;
   1855     0   stevel 		xblk = vtocp->v_sectorsz / DEV_BSIZE;
   1856     0   stevel 	}
   1857     0   stevel 	vtocp->v_nparts = 3;	/* <= NDKMAP;	*/
   1858     0   stevel 
   1859     0   stevel 	/*
   1860     0   stevel 	 * Copy partitioning information.
   1861     0   stevel 	 */
   1862     0   stevel 	bcopy(fdp->d_part, vtocp->v_part, sizeof (struct partition) * NDKMAP);
   1863     0   stevel 	for (i = NDKMAP, vpart = vtocp->v_part; i && (xblk > 1); i--, vpart++) {
   1864     0   stevel 		/* correct partition info if sector size > 512 bytes */
   1865     0   stevel 		vpart->p_start /= xblk;
   1866     0   stevel 		vpart->p_size /= xblk;
   1867     0   stevel 	}
   1868     0   stevel 
   1869     0   stevel 	bcopy(fdp->d_vtoc_timestamp,
   1870     0   stevel 	    vtocp->timestamp, sizeof (fdp->d_vtoc_timestamp));
   1871     0   stevel 	bcopy(fdp->d_vtoc_asciilabel, vtocp->v_asciilabel, LEN_DKL_ASCII);
   1872     0   stevel }
   1873     0   stevel 
   1874     0   stevel 
   1875     0   stevel static int
   1876     0   stevel fd_build_label_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp,
   1877     0   stevel     struct dk_label *labelp)
   1878     0   stevel {
   1879     0   stevel 	struct partition *vpart;
   1880     0   stevel 	int	i;
   1881     0   stevel 	int	nblks;
   1882     0   stevel 	int	ncyl;
   1883     0   stevel 	ushort_t sum, *sp;
   1884     0   stevel 
   1885     0   stevel 
   1886     0   stevel 	/*
   1887     0   stevel 	 * Sanity-check the vtoc
   1888     0   stevel 	 */
   1889     0   stevel 	if (vtocp->v_sanity != VTOC_SANE ||
   1890     0   stevel 	    vtocp->v_nparts > NDKMAP || vtocp->v_nparts <= 0) {
   1891     0   stevel 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
   1892     0   stevel 		    (CE_WARN, "fd_build_label:  sanity check on vtoc failed"));
   1893     0   stevel 		return (EINVAL);
   1894     0   stevel 	}
   1895     0   stevel 
   1896     0   stevel 	/*
   1897     0   stevel 	 * before copying the vtoc, the partition information in it should be
   1898     0   stevel 	 * checked against the information the driver already has on the
   1899     0   stevel 	 * diskette.
   1900     0   stevel 	 */
   1901     0   stevel 
   1902     0   stevel 	nblks = (fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack *
   1903  7656   Sherry 	    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
   1904     0   stevel 	if (nblks == 0 || fjp->fj_chars->fdc_ncyl == 0)
   1905     0   stevel 		return (EFAULT);
   1906     0   stevel 	vpart = vtocp->v_part;
   1907     0   stevel 
   1908     0   stevel 	/*
   1909     0   stevel 	 * Check the partition information in the vtoc.  The starting sectors
   1910     0   stevel 	 * must lie along cylinder boundaries. (NDKMAP entries are checked
   1911     0   stevel 	 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
   1912     0   stevel 	 * is less than NDKMAP)
   1913     0   stevel 	 */
   1914     0   stevel 	for (i = NDKMAP; i; i--) {
   1915     0   stevel 		if ((vpart->p_start % nblks) != 0) {
   1916     0   stevel 			return (EINVAL);
   1917     0   stevel 		}
   1918     0   stevel 		ncyl = vpart->p_start / nblks;
   1919     0   stevel 		ncyl += vpart->p_size / nblks;
   1920     0   stevel 		if ((vpart->p_size % nblks) != 0)
   1921     0   stevel 			ncyl++;
   1922     0   stevel 		if (ncyl > (long)fjp->fj_chars->fdc_ncyl) {
   1923     0   stevel 			return (EINVAL);
   1924     0   stevel 		}
   1925     0   stevel 		vpart++;
   1926     0   stevel 	}
   1927     0   stevel 
   1928     0   stevel 
   1929     0   stevel 	bcopy(vtocp->v_bootinfo, fdp->d_vtoc_bootinfo,
   1930     0   stevel 	    sizeof (vtocp->v_bootinfo));
   1931     0   stevel 	fdp->d_vtoc_version = vtocp->v_version;
   1932     0   stevel 	bcopy(vtocp->v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
   1933     0   stevel 
   1934     0   stevel 	/*
   1935     0   stevel 	 * Copy partitioning information.
   1936     0   stevel 	 */
   1937     0   stevel 	bcopy(vtocp->v_part, fdp->d_part, sizeof (struct partition) * NDKMAP);
   1938     0   stevel 	bcopy(vtocp->timestamp, fdp->d_vtoc_timestamp,
   1939     0   stevel 	    sizeof (fdp->d_vtoc_timestamp));
   1940     0   stevel 	bcopy(vtocp->v_asciilabel, fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
   1941     0   stevel 
   1942     0   stevel 	/*
   1943     0   stevel 	 * construct the diskette label in supplied buffer
   1944     0   stevel 	 */
   1945     0   stevel 
   1946     0   stevel 	/* Put appropriate vtoc structure fields into the disk label */
   1947     0   stevel 	labelp->dkl_vtoc.v_bootinfo[0] = (uint32_t)vtocp->v_bootinfo[0];
   1948     0   stevel 	labelp->dkl_vtoc.v_bootinfo[1] = (uint32_t)vtocp->v_bootinfo[1];
   1949     0   stevel 	labelp->dkl_vtoc.v_bootinfo[2] = (uint32_t)vtocp->v_bootinfo[2];
   1950     0   stevel 
   1951     0   stevel 	labelp->dkl_vtoc.v_sanity = vtocp->v_sanity;
   1952     0   stevel 	labelp->dkl_vtoc.v_version = vtocp->v_version;
   1953     0   stevel 
   1954     0   stevel 	bcopy(vtocp->v_volume, labelp->dkl_vtoc.v_volume, LEN_DKL_VVOL);
   1955     0   stevel 
   1956     0   stevel 	labelp->dkl_vtoc.v_nparts = vtocp->v_nparts;
   1957     0   stevel 
   1958     0   stevel 	bcopy(vtocp->v_reserved, labelp->dkl_vtoc.v_reserved,
   1959     0   stevel 	    sizeof (labelp->dkl_vtoc.v_reserved));
   1960     0   stevel 
   1961     0   stevel 	for (i = 0; i < (int)vtocp->v_nparts; i++) {
   1962     0   stevel 		labelp->dkl_vtoc.v_part[i].p_tag  = vtocp->v_part[i].p_tag;
   1963     0   stevel 		labelp->dkl_vtoc.v_part[i].p_flag  = vtocp->v_part[i].p_flag;
   1964     0   stevel 		labelp->dkl_vtoc.v_part[i].p_start  = vtocp->v_part[i].p_start;
   1965     0   stevel 		labelp->dkl_vtoc.v_part[i].p_size  = vtocp->v_part[i].p_size;
   1966     0   stevel 	}
   1967     0   stevel 
   1968     0   stevel 	for (i = 0; i < NDKMAP; i++) {
   1969     0   stevel 		labelp->dkl_vtoc.v_timestamp[i] = vtocp->timestamp[i];
   1970     0   stevel 	}
   1971     0   stevel 	bcopy(vtocp->v_asciilabel, labelp->dkl_asciilabel, LEN_DKL_ASCII);
   1972     0   stevel 
   1973     0   stevel 
   1974     0   stevel 	labelp->dkl_pcyl = fjp->fj_chars->fdc_ncyl;
   1975     0   stevel 	labelp->dkl_ncyl = fjp->fj_chars->fdc_ncyl;
   1976     0   stevel 	labelp->dkl_nhead = fjp->fj_chars->fdc_nhead;
   1977     0   stevel 	/*
   1978     0   stevel 	 * The fdc_secptrack field of the fd_char structure is the number
   1979     0   stevel 	 * of sectors per track where the sectors are fdc_sec_size.
   1980     0   stevel 	 * The dkl_nsect field of the dk_label structure is the number of
   1981     0   stevel 	 * DEV_BSIZE (512) byte sectors per track.
   1982     0   stevel 	 */
   1983     0   stevel 	labelp->dkl_nsect = (fjp->fj_chars->fdc_secptrack *
   1984     0   stevel 	    fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
   1985     0   stevel 	labelp->dkl_intrlv = fjp->fj_attr->fda_intrlv;
   1986     0   stevel 	labelp->dkl_rpm = fjp->fj_attr->fda_rotatespd;
   1987     0   stevel 	labelp->dkl_read_reinstruct =
   1988     0   stevel 	    (int)(labelp->dkl_nsect * labelp->dkl_rpm * 4) / 60000;
   1989     0   stevel 	labelp->dkl_write_reinstruct = labelp->dkl_read_reinstruct;
   1990     0   stevel 
   1991     0   stevel 	labelp->dkl_magic = DKL_MAGIC;
   1992     0   stevel 
   1993     0   stevel 	sum = 0;
   1994     0   stevel 	labelp->dkl_cksum = 0;
   1995     0   stevel 	sp = (ushort_t *)labelp;
   1996     0   stevel 	while (sp < &(labelp->dkl_cksum)) {
   1997     0   stevel 		sum ^= *sp++;
   1998     0   stevel 	}
   1999     0   stevel 	labelp->dkl_cksum = sum;
   2000     0   stevel 
   2001     0   stevel 	return (0);
   2002     0   stevel }
   2003     0   stevel 
   2004     0   stevel static int
   2005     0   stevel fd_rawioctl(struct fcu_obj *fjp, int unit, caddr_t arg, int mode)
   2006     0   stevel {
   2007     0   stevel 	struct fd_raw fdr;
   2008     0   stevel 	char *arg_result = NULL;
   2009     0   stevel 	int flag = B_READ;
   2010     0   stevel 	int rval = 0;
   2011     0   stevel 	caddr_t	uaddr;
   2012     0   stevel 	uint_t ucount;
   2013     0   stevel 
   2014     0   stevel 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2015     0   stevel 	    (CE_CONT, "fd_rawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
   2016     0   stevel 
   2017     0   stevel 	if (fjp->fj_chars->fdc_medium != 3 && fjp->fj_chars->fdc_medium != 5) {
   2018     0   stevel 		cmn_err(CE_CONT, "fd_rawioctl: Medium density not supported\n");
   2019     0   stevel 		return (ENXIO);
   2020     0   stevel 	}
   2021     0   stevel 
   2022     0   stevel #ifdef _MULTI_DATAMODEL
   2023     0   stevel 	switch (ddi_model_convert_from(mode & FMODELS)) {
   2024     0   stevel 	case DDI_MODEL_ILP32:
   2025     0   stevel 	{
   2026     0   stevel 		struct fd_raw32 fdr32;
   2027     0   stevel 
   2028     0   stevel 		if (ddi_copyin(arg, &fdr32, sizeof (fdr32), mode))
   2029     0   stevel 			return (EFAULT);
   2030     0   stevel 
   2031     0   stevel 		bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
   2032     0   stevel 		fdr.fdr_cnum = fdr32.fdr_cnum;
   2033     0   stevel 		fdr.fdr_nbytes = fdr32.fdr_nbytes;
   2034     0   stevel 		fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
   2035     0   stevel 		arg_result = ((struct fd_raw32 *)arg)->fdr_result;
   2036     0   stevel 
   2037     0   stevel 		break;
   2038     0   stevel 	}
   2039     0   stevel 	case DDI_MODEL_NONE:
   2040     0   stevel #endif /* ! _MULTI_DATAMODEL */
   2041     0   stevel 
   2042     0   stevel 		if (ddi_copyin(arg, &fdr, sizeof (fdr), mode))
   2043     0   stevel 			return (EFAULT);
   2044     0   stevel 
   2045     0   stevel 		arg_result = ((struct fd_raw *)arg)->fdr_result;
   2046     0   stevel 
   2047     0   stevel #ifdef _MULTI_DATAMODEL
   2048     0   stevel 		break;
   2049     0   stevel 	}
   2050     0   stevel #endif /* _MULTI_DATAMODEL */
   2051     0   stevel 
   2052     0   stevel 
   2053     0   stevel 
   2054     0   stevel 	/*
   2055     0   stevel 	 * copy user address & nbytes from raw_req so that we can
   2056     0   stevel 	 * put kernel address in req structure
   2057     0   stevel 	 */
   2058     0   stevel 	uaddr = fdr.fdr_addr;
   2059     0   stevel 	ucount = (uint_t)fdr.fdr_nbytes;
   2060     0   stevel 	unit &= 3;
   2061     0   stevel 
   2062     0   stevel 	switch (fdr.fdr_cmd[0] & 0x0f) {
   2063     0   stevel 
   2064     0   stevel 	case FDRAW_FORMAT:
   2065     0   stevel 		ucount += 16;
   2066     0   stevel 		fdr.fdr_addr = kmem_zalloc(ucount, KM_SLEEP);
   2067     0   stevel 		if (ddi_copyin(uaddr, fdr.fdr_addr,
   2068     0   stevel 		    (size_t)fdr.fdr_nbytes, mode)) {
   2069     0   stevel 			kmem_free(fdr.fdr_addr, ucount);
   2070     0   stevel 			return (EFAULT);
   2071     0   stevel 		}
   2072     0   stevel 		if ((*fdr.fdr_addr | fdr.fdr_addr[1]) == 0)
   2073     0   stevel 			fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
   2074     0   stevel 		flag = B_WRITE;
   2075     0   stevel 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
   2076     0   stevel 		break;
   2077     0   stevel 
   2078     0   stevel 	case FDRAW_WRCMD:
   2079     0   stevel 	case FDRAW_WRITEDEL:
   2080     0   stevel 		flag = B_WRITE;
   2081     0   stevel 		/* FALLTHROUGH */
   2082     0   stevel 	case FDRAW_RDCMD:
   2083     0   stevel 	case FDRAW_READDEL:
   2084     0   stevel 	case FDRAW_READTRACK:
   2085     0   stevel 		if (ucount) {
   2086     0   stevel 			/*
   2087     0   stevel 			 * In SunOS 4.X, we used to as_fault things in.
   2088     0   stevel 			 * We really cannot do this in 5.0/SVr4. Unless
   2089     0   stevel 			 * someone really believes that speed is of the
   2090     0   stevel 			 * essence here, it is just much simpler to do
   2091     0   stevel 			 * this in kernel space and use copyin/copyout.
   2092     0   stevel 			 */
   2093     0   stevel 			fdr.fdr_addr = kmem_alloc((size_t)ucount, KM_SLEEP);
   2094     0   stevel 			if (flag == B_WRITE) {
   2095     0   stevel 				if (ddi_copyin(uaddr, fdr.fdr_addr, ucount,
   2096     0   stevel 				    mode)) {
   2097     0   stevel 					kmem_free(fdr.fdr_addr, ucount);
   2098     0   stevel 					return (EFAULT);
   2099     0   stevel 				}
   2100     0   stevel 			}
   2101     0   stevel 		} else
   2102     0   stevel 			return (EINVAL);
   2103     0   stevel 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
   2104     0   stevel 		break;
   2105     0   stevel 
   2106     0   stevel 	case FDRAW_READID:
   2107     0   stevel 	case FDRAW_REZERO:
   2108     0   stevel 	case FDRAW_SEEK:
   2109     0   stevel 	case FDRAW_SENSE_DRV:
   2110     0   stevel 		ucount = 0;
   2111     0   stevel 		fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
   2112     0   stevel 		break;
   2113     0   stevel 
   2114     0   stevel 	case FDRAW_SPECIFY:
   2115     0   stevel 		fdr.fdr_cmd[2] &= 0xfe;	/* keep NoDMA bit clear */
   2116     0   stevel 		/* FALLTHROUGH */
   2117     0   stevel 	case FDRAW_SENSE_INT:
   2118     0   stevel 		ucount = 0;
   2119     0   stevel 		break;
   2120     0   stevel 
   2121     0   stevel 	default:
   2122     0   stevel 		return (EINVAL);
   2123     0   stevel 	}
   2124     0   stevel 
   2125     0   stevel 	/*
   2126     0   stevel 	 * Note that we ignore any error returns from controller
   2127     0   stevel 	 * This is the way the driver has been, and it may be
   2128     0   stevel 	 * that the raw ioctl senders simply don't want to
   2129     0   stevel 	 * see any errors returned in this fashion.
   2130     0   stevel 	 */
   2131     0   stevel 
   2132     0   stevel 	fjp->fj_ops->fco_select(fjp, unit, 1);
   2133     0   stevel 	rval = fjp->fj_ops->fco_rwioctl(fjp, unit, (caddr_t)&fdr);
   2134     0   stevel 
   2135     0   stevel 	if (ucount && flag == B_READ && rval == 0) {
   2136     0   stevel 		if (ddi_copyout(fdr.fdr_addr, uaddr, ucount, mode)) {
   2137     0   stevel 			rval = EFAULT;
   2138     0   stevel 		}
   2139     0   stevel 	}
   2140     0   stevel 	if (ddi_copyout(fdr.fdr_result, arg_result, sizeof (fdr.fdr_cmd), mode))
   2141     0   stevel 		rval = EFAULT;
   2142     0   stevel 
   2143     0   stevel 	fjp->fj_ops->fco_select(fjp, unit, 0);
   2144     0   stevel 	if (ucount)
   2145     0   stevel 		kmem_free(fdr.fdr_addr, ucount);
   2146     0   stevel 
   2147     0   stevel 	return (rval);
   2148     0   stevel }
   2149     0   stevel 
   2150     0   stevel /*
   2151     0   stevel  * property operation routine.  return the number of blocks for the partition
   2152     0   stevel  * in question or forward the request to the property facilities.
   2153     0   stevel  */
   2154     0   stevel static int
   2155     0   stevel fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
   2156     0   stevel     char *name, caddr_t valuep, int *lengthp)
   2157     0   stevel {
   2158     0   stevel 	struct fcu_obj	*fjp = NULL;
   2159     0   stevel 	struct fdisk	*fdp = NULL;
   2160     0   stevel 	uint64_t	nblocks64;
   2161     0   stevel 
   2162     0   stevel 	FDERRPRINT(FDEP_L1, FDEM_PROP,
   2163     0   stevel 	    (CE_CONT, "fd_prop_op: dip %p %s\n", (void *)dip, name));
   2164     0   stevel 
   2165     0   stevel 	/*
   2166     0   stevel 	 * Our dynamic properties are all device specific and size oriented.
   2167     0   stevel 	 * Requests issued under conditions where size is valid are passed
   2168     0   stevel 	 * to ddi_prop_op_nblocks with the size information, otherwise the
   2169     0   stevel 	 * request is passed to ddi_prop_op.
   2170     0   stevel 	 */
   2171     0   stevel 	if (dev == DDI_DEV_T_ANY) {
   2172     0   stevel pass:  		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
   2173     0   stevel 		    name, valuep, lengthp));
   2174     0   stevel 	} else {
   2175     0   stevel 		/*
   2176     0   stevel 		 * Ignoring return value because success is checked by
   2177     0   stevel 		 * verifying fjp and fdp and returned unit value is not used.
   2178     0   stevel 		 */
   2179     0   stevel 		(void) fd_getdrive(dev, &fjp, &fdp);
   2180     0   stevel 		if (!fjp || !fdp)
   2181     0   stevel 			goto pass;
   2182     0   stevel 
   2183     0   stevel 		/* get nblocks value */
   2184     0   stevel 		nblocks64 = (ulong_t)fdp->d_part[PARTITION(dev)].p_size;
   2185     0   stevel 
   2186     0   stevel 		return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
   2187     0   stevel 		    name, valuep, lengthp, nblocks64));
   2188     0   stevel 	}
   2189     0   stevel }
   2190     0   stevel 
   2191     0   stevel static void
   2192     0   stevel fd_media_watch(void *arg)
   2193     0   stevel {
   2194     0   stevel 	struct fcu_obj *fjp;
   2195     0   stevel 	struct fdisk *fdp;
   2196     0   stevel 
   2197     0   stevel #ifdef DEBUG
   2198     0   stevel 	int	unit;
   2199     0   stevel #define	DEBUG_ASSIGN	unit=
   2200     0   stevel #else
   2201     0   stevel #define	DEBUG_ASSIGN	(void)
   2202     0   stevel #endif
   2203     0   stevel 	DEBUG_ASSIGN fd_getdrive((dev_t)arg, &fjp, &fdp);
   2204     0   stevel 	/*
   2205     0   stevel 	 * Ignoring return in non DEBUG mode because device exist.
   2206     0   stevel 	 * Returned unit value is not used.
   2207     0   stevel 	 */
   2208     0   stevel 
   2209     0   stevel 	FDERRPRINT(FDEP_L0, FDEM_IOCT,
   2210     0   stevel 	    (CE_CONT, "fd_media_watch unit %d\n", unit));
   2211     0   stevel 
   2212     0   stevel 	/*
   2213     0   stevel 	 * fd_get_media_state() cannot be called from this timeout function
   2214     0   stevel 	 * because the  floppy drive has to be selected first, and that could
   2215     0   stevel 	 * force this function to sleep (while waiting for the select
   2216     0   stevel 	 * semaphore).
   2217     0   stevel 	 * Instead, just wakeup up driver.
   2218     0   stevel 	 */
   2219     0   stevel 	mutex_enter(&fjp->fj_lock);
   2220     0   stevel 	cv_broadcast(&fdp->d_statecv);
   2221     0   stevel 	mutex_exit(&fjp->fj_lock);
   2222     0   stevel }
   2223     0   stevel 
   2224     0   stevel enum dkio_state
   2225     0   stevel fd_get_media_state(struct fcu_obj *fjp, int unit)
   2226     0   stevel {
   2227     0   stevel 	enum dkio_state state;
   2228     0   stevel 
   2229     0   stevel 	if (fjp->fj_ops->fco_getchng(fjp, unit)) {
   2230     0   stevel 		/* recheck disk only if DSKCHG "high" */
   2231     0   stevel 		fjp->fj_ops->fco_resetchng(fjp, unit);
   2232     0   stevel 		if (fjp->fj_ops->fco_getchng(fjp, unit)) {
   2233     0   stevel 			if (fjp->fj_flags & FUNIT_CHGDET) {
   2234     0   stevel 				/*
   2235     0   stevel 				 * again no diskette; not a new change
   2236     0   stevel 				 */
   2237     0   stevel 				state = DKIO_NONE;
   2238     0   stevel 			} else {
   2239     0   stevel 				/*
   2240     0   stevel 				 * a new change; diskette was ejected
   2241     0   stevel 				 */
   2242     0   stevel 				fjp->fj_flags |= FUNIT_CHGDET;
   2243     0   stevel 				state = DKIO_EJECTED;
   2244     0   stevel 			}
   2245     0   stevel 		} else {
   2246     0   stevel 			fjp->fj_flags &= ~FUNIT_CHGDET;
   2247     0   stevel 			state = DKIO_INSERTED;
   2248     0   stevel 		}
   2249     0   stevel 	} else {
   2250     0   stevel 		fjp->fj_flags &= ~FUNIT_CHGDET;
   2251     0   stevel 		state = DKIO_INSERTED;
   2252     0   stevel 	}
   2253     0   stevel 	FDERRPRINT(FDEP_L0, FDEM_IOCT,
   2254     0   stevel 	    (CE_CONT, "fd_get_media_state unit %d: state %x\n", unit, state));
   2255     0   stevel 	return (state);
   2256     0   stevel }
   2257     0   stevel 
   2258     0   stevel static int
   2259     0   stevel fd_check_media(dev_t dev, enum dkio_state state)
   2260     0   stevel {
   2261     0   stevel 	struct fcu_obj *fjp;
   2262     0   stevel 	struct fdisk *fdp;
   2263     0   stevel 	int	unit;
   2264     0   stevel 	int	err;
   2265     0   stevel 
   2266     0   stevel 	unit = fd_getdrive(dev, &fjp, &fdp);
   2267     0   stevel 
   2268     0   stevel 	mutex_enter(&fjp->fj_lock);
   2269     0   stevel 
   2270     0   stevel 	fjp->fj_ops->fco_select(fjp, unit, 1);
   2271     0   stevel 	fdp->d_media_state = fd_get_media_state(fjp, unit);
   2272     0   stevel 	fdp->d_media_timeout = drv_usectohz(fd_check_media_time);
   2273     0   stevel 
   2274     0   stevel 	while (fdp->d_media_state == state) {
   2275     0   stevel 		/* release the controller and drive */
   2276     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 0);
   2277     0   stevel 
   2278     0   stevel 		/* turn on timer */
   2279     0   stevel 		fdp->d_media_timeout_id = timeout(fd_media_watch,
   2280  7656   Sherry 		    (void *)dev, fdp->d_media_timeout);
   2281     0   stevel 
   2282     0   stevel 		if (cv_wait_sig(&fdp->d_statecv, &fjp->fj_lock) == 0) {
   2283     0   stevel 			fdp->d_media_timeout = 0;
   2284     0   stevel 			mutex_exit(&fjp->fj_lock);
   2285     0   stevel 			return (EINTR);
   2286     0   stevel 		}
   2287     0   stevel 		fjp->fj_ops->fco_select(fjp, unit, 1);
   2288     0   stevel 		fdp->d_media_state = fd_get_media_state(fjp, unit);
   2289     0   stevel 	}
   2290     0   stevel 
   2291     0   stevel 	if (fdp->d_media_state == DKIO_INSERTED) {
   2292     0   stevel 		err = fdgetlabel(fjp, unit);
   2293     0   stevel 		if (err) {
   2294     0   stevel 			fjp->fj_ops->fco_select(fjp, unit, 0);
   2295     0   stevel 			mutex_exit(&fjp->fj_lock);
   2296     0   stevel 			return (EIO);
   2297     0   stevel 		}
   2298     0   stevel 	}
   2299     0   stevel 	fjp->fj_ops->fco_select(fjp, unit, 0);
   2300     0   stevel 	mutex_exit(&fjp->fj_lock);
   2301     0   stevel 	return (0);
   2302     0   stevel }
   2303     0   stevel 
   2304     0   stevel /*
   2305     0   stevel  * fd_get_media_info :
   2306     0   stevel  * 	Collects medium information for
   2307     0   stevel  *	DKIOCGMEDIAINFO ioctl.
   2308     0   stevel  */
   2309     0   stevel 
   2310     0   stevel static int
   2311     0   stevel fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag)
   2312     0   stevel {
   2313     0   stevel 	struct dk_minfo media_info;
   2314     0   stevel 	int err = 0;
   2315     0   stevel 
   2316     0   stevel 	media_info.dki_media_type = DK_FLOPPY;
   2317     0   stevel 	media_info.dki_lbsize = fjp->fj_chars->fdc_sec_size;
   2318     0   stevel 	media_info.dki_capacity = fjp->fj_chars->fdc_ncyl *
   2319  7656   Sherry 	    fjp->fj_chars->fdc_secptrack * fjp->fj_chars->fdc_nhead;
   2320     0   stevel 
   2321     0   stevel 	if (ddi_copyout(&media_info, buf, sizeof (struct dk_minfo), flag))
   2322     0   stevel 		err = EFAULT;
   2323     0   stevel 	return (err);
   2324     0   stevel }
   2325