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