Home | History | Annotate | Download | only in io
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 /*
     28  * Intel 82077 Floppy Disk Driver
     29  */
     30 
     31 /*
     32  * Notes
     33  *
     34  *	0. The driver supports two flavors of hardware design:
     35  *		"SUNW,fdtwo"	- sun4m	- 82077 with sun4m style Auxio
     36  *		"fdthree"  - sun4u - 82077 with DMA
     37  *	   In addition it supports an apparent bug in some versions of
     38  *	   the 82077 controller.
     39  *
     40  *	1. The driver is mostly set up for multiple controllers, multiple
     41  *	drives. However- we *do* assume the use of the AUXIO register, and
     42  *	if we ever have > 1 fdc, we'll have to see what that means. This
     43  *	is all intrinsically machine specific, but there isn't much we
     44  *	can do about it.
     45  *
     46  *	2. The driver also is structured to deal with one drive active at
     47  *	a time. This is because the 82072 chip (no longer supported) was
     48  *	known to be buggy with respect to overlapped seeks.
     49  *
     50  *	3. The high level interrupt code is in assembler, and runs in a
     51  *	sparc trap window. It acts as a pseudo-dma engine as well as
     52  *	handles a couple of other interrupts. When it gets its job done,
     53  *	it schedules a second stage interrupt (soft interrupt) which
     54  *	is then fielded here in fd_lointr.  When DMA is used, the fdintr_dma
     55  *	interrupt handler is used.
     56  *
     57  *	4. Nearly all locking is done on a lower level MUTEX_DRIVER
     58  *	mutex. The locking is quite conservative, and is generally
     59  *	established very close to any of the entries into the driver.
     60  *	There is nearly no locking done of the high level MUTEX_DRIVER
     61  *	mutex (which generally is a SPIN mutex because the floppy usually
     62  *	interrupts above LOCK_LEVEL). The assembler high level interrupt
     63  *	handler grabs the high level mutex, but the code in the driver
     64  *	here is especially structured to not need to do this.
     65  *
     66  *	5. Fdrawioctl commands that pass data are not optimized for
     67  *	speed. If they need to be faster, the driver structure will
     68  *	have to be redone such that fdrawioctl calls physio after
     69  *	cons'ing up a uio structure and that fdstart will be able
     70  *	to detect that a particular buffer is a 'special' buffer.
     71  *
     72  *	6. Removable media support is not complete.
     73  *
     74  */
     75 
     76 #include <sys/param.h>
     77 #include <sys/buf.h>
     78 #include <sys/ioctl.h>
     79 #include <sys/uio.h>
     80 #include <sys/open.h>
     81 #include <sys/conf.h>
     82 #include <sys/file.h>
     83 #include <sys/cmn_err.h>
     84 #include <sys/debug.h>
     85 #include <sys/kmem.h>
     86 #include <sys/stat.h>
     87 #include <sys/autoconf.h>
     88 
     89 #include <sys/dklabel.h>
     90 
     91 #include <sys/vtoc.h>
     92 #include <sys/dkio.h>
     93 #include <sys/fdio.h>
     94 
     95 #include <sys/ddi.h>
     96 #include <sys/sunddi.h>
     97 #include <sys/kstat.h>
     98 
     99 /*
    100  * included to check for ELC or SLC which report floppy controller that
    101  */
    102 #include <sys/cpu.h>
    103 
    104 #include "sys/fdvar.h"
    105 #include "sys/fdreg.h"
    106 #include "sys/dma_i8237A.h"
    107 
    108 /*
    109  * Defines
    110  */
    111 #define	KIOSP	KSTAT_IO_PTR(un->un_iostat)
    112 #define	KIOIP	KSTAT_INTR_PTR(fdc->c_intrstat)
    113 #define	MEDIUM_DENSITY	0x40
    114 #define	SEC_SIZE_CODE	(fdctlr.c_csb->csb_unit]->un_chars->medium ? 3 : 2)
    115 #define	CMD_READ	(MT + SK + FDRAW_RDCMD + MFM)
    116 #define	CMD_WRITE	(MT + FDRAW_WRCMD + MFM)
    117 #define	C		CE_CONT
    118 #define	FD_POLLABLE_PROP	"pollable"	/* prom property */
    119 #define	FD_MANUAL_EJECT		"manual"	/* prom property */
    120 #define	FD_UNIT			"unit"		/* prom property */
    121 
    122 /*
    123  * Sony MP-F17W-50D Drive Parameters
    124  *				High Capacity
    125  *	Capacity unformatted	2Mb
    126  *	Capacity formatted	1.47Mb
    127  *	Encoding method	 MFM
    128  *	Recording density	17434 bpi
    129  *	Track density		135 tpi
    130  *	Cylinders		80
    131  *	Heads			2
    132  *	Tracks			160
    133  *	Rotational speed	300 rpm
    134  *	Transfer rate		250/500 kbps
    135  *	Latency (average)	100 ms
    136  *	Access time
    137  *		Average		95 ms
    138  *		Track to track	3 ms
    139  *	Head settling time	15 ms
    140  *	Motor start time	500 ms
    141  *	Head load time		? ms
    142  */
    143 
    144 /*
    145  * The max_fd_dma_len is used only when southbridge is present.
    146  * It has been observed that when IFB tests are run the floppy dma could get
    147  * starved and result in underrun errors. After experimenting it was found that
    148  * doing dma in chunks of 2048 works OK.
    149  * The reason for making this a global variable is that there could be
    150  * situations under which the customer would like to get full performance
    151  * from floppy. He may not be having IFB boards that cause underrun errors.
    152  * Under those conditions we could set this value to a much higher value
    153  * by editing /etc/system file.
    154  */
    155 int	max_fd_dma_len = 2048;
    156 
    157 static void quiesce_fd_interrupt(struct fdctlr *);
    158 
    159 /*
    160  * Character/block entry points function prototypes
    161  */
    162 static int fd_open(dev_t *, int, int, cred_t *);
    163 static int fd_close(dev_t, int, int, cred_t *);
    164 static int fd_strategy(struct buf *);
    165 static int fd_read(dev_t, struct uio *, cred_t *);
    166 static int fd_write(dev_t, struct uio *, cred_t *);
    167 static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
    168 static int
    169 fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *);
    170 
    171 /*
    172  * Device operations (dev_ops) entries function prototypes
    173  */
    174 static int fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
    175 		void **result);
    176 static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
    177 static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
    178 static int fd_power(dev_info_t *dip, int component, int level);
    179 
    180 /*
    181  * Internal functions
    182  */
    183 static int fd_attach_check_drive(struct fdctlr *fdc);
    184 static int fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc);
    185 static int fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc);
    186 static int fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc,
    187     int *hard);
    188 static int fd_build_label_vtoc(struct fdunit *, struct vtoc *);
    189 static void fd_build_user_vtoc(struct fdunit *, struct vtoc *);
    190 static int fdcheckdisk(struct fdctlr *fdc, int unit);
    191 static int fd_check_media(dev_t dev, enum dkio_state state);
    192 static void fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard,
    193     int locks);
    194 static void fdeject(struct fdctlr *, int unit);
    195 static int fdexec(struct fdctlr *fdc, int flags);
    196 static void fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit);
    197 static int fdformat(struct fdctlr *fdc, int unit, int cyl, int hd);
    198 static caddr_t fd_getauxiova();
    199 static struct fdctlr *fd_getctlr(dev_t);
    200 static void fdgetcsb(struct fdctlr *);
    201 static int fdgetlabel(struct fdctlr *fdc, int unit);
    202 enum dkio_state fd_get_media_state(struct fdctlr *, int);
    203 static uint_t fdintr_dma();
    204 static int fd_isauxiodip(dev_info_t *);
    205 static uint_t  fd_lointr(caddr_t arg);
    206 static void fd_media_watch(void *);
    207 static void fdmotoff(void *);
    208 static int fd_part_is_open(struct fdunit *un, int part);
    209 static int fdrawioctl(struct fdctlr *, int, intptr_t, int);
    210 static int fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg);
    211 static int fdrecover(struct fdctlr *);
    212 static void fdretcsb(struct fdctlr *);
    213 static int fdreset(struct fdctlr *);
    214 static int fdrw(struct fdctlr *fdc, int, int, int, int, int, caddr_t, uint_t);
    215 static void fdselect(struct fdctlr *fdc, int unit, int onoff);
    216 static int fdsensedrv(struct fdctlr *fdc, int unit);
    217 static int fdsense_chng(struct fdctlr *, int unit);
    218 static void fdstart(struct fdctlr *);
    219 static int fdstart_dma(register struct fdctlr *fdc, caddr_t addr, uint_t len);
    220 static int fd_unit_is_open(struct fdunit *);
    221 static void fdunpacklabel(struct packed_label *, struct dk_label *);
    222 static int fd_unbind_handle(struct fdctlr *);
    223 static void fdwatch(void *);
    224 static void set_rotational_speed(struct fdctlr *, int);
    225 static int fd_get_media_info(struct fdunit *un, caddr_t buf, int flag);
    226 static int fd_pm_lower_power(struct fdctlr *fdc);
    227 static int fd_pm_raise_power(struct fdctlr *fdc);
    228 static void create_pm_components(dev_info_t *dip);
    229 static void set_data_count_register(struct fdctlr *fdc, uint32_t count);
    230 static uint32_t get_data_count_register(struct fdctlr *fdc);
    231 static void reset_dma_controller(struct fdctlr *fdc);
    232 static void set_data_address_register(struct fdctlr *fdc, uint32_t address);
    233 static uint32_t get_dma_control_register(struct fdctlr *fdc);
    234 static void set_dma_mode(struct fdctlr *fdc, int val);
    235 static void set_dma_control_register(struct fdctlr *fdc, uint32_t val);
    236 static void release_sb_dma(struct fdctlr *fdc);
    237 
    238 /*
    239  * External functions
    240  */
    241 extern uint_t fd_intr(caddr_t);	/* defined in fd_asm.s */
    242 extern void set_auxioreg();
    243 extern void call_debug();
    244 
    245 
    246 
    247 /*
    248  * The following macro checks whether the device in a SUSPENDED state.
    249  * As per WDD guide lines the I/O requests to a suspended device should
    250  * be blocked until the device is resumed.
    251  * Here we cv_wait on c_suspend_cv, and there is a cv_broadcast() in
    252  * DDI_RESUME to wake up this thread.
    253  *
    254  * NOTE: This code is not tested because the kernel threads are suspended
    255  * before the device is suspended. So there can not be any I/O requests on
    256  * a suspended device until the cpr implementation changes..
    257  */
    258 
    259 #define	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc) 	\
    260 		{\
    261 			while (fdc->c_un->un_state == FD_STATE_SUSPENDED) {\
    262 				cv_wait(&fdc->c_suspend_cv, \
    263 							&fdc->c_lolock);\
    264 			}\
    265 		}
    266 
    267 /*
    268  * bss (uninitialized data)
    269  */
    270 struct	fdctlr	*fdctlrs;	/* linked list of controllers */
    271 
    272 /*
    273  * initialized data
    274  */
    275 
    276 static int fd_check_media_time = 5000000;	/* 5 second state check */
    277 static int fd_pollable = 0;
    278 static uchar_t rwretry = 10;
    279 static uchar_t skretry = 5;
    280 /* This variable allows the dynamic change of the burst size */
    281 static int fd_burstsize = DCSR_BURST_0 | DCSR_BURST_1;
    282 
    283 static struct driver_minor_data {
    284 	char	*name;
    285 	int	minor;
    286 	int	type;
    287 } fd_minor [] = {
    288 	{ "a", 0, S_IFBLK},
    289 	{ "b", 1, S_IFBLK},
    290 	{ "c", 2, S_IFBLK},
    291 	{ "a,raw", 0, S_IFCHR},
    292 	{ "b,raw", 1, S_IFCHR},
    293 	{ "c,raw", 2, S_IFCHR},
    294 	{0}
    295 };
    296 
    297 /*
    298  * If the interrupt handler is invoked and no controllers expect an
    299  * interrupt, the kernel panics.  The following message is printed out.
    300  */
    301 char *panic_msg = "fd_intr: unexpected interrupt\n";
    302 
    303 /*
    304  * Specify/Configure cmd parameters
    305  */
    306 static uchar_t fdspec[2] = { 0xc2, 0x33 };	/*  "specify" parameters */
    307 static uchar_t fdconf[3] = { 0x64, 0x58, 0x00 }; /*  "configure" parameters */
    308 
    309 /* When DMA is used, set the ND bit to 0 */
    310 #define	SPEC_DMA_MODE	0x32
    311 
    312 /*
    313  * default characteristics
    314  */
    315 static struct fd_char fdtypes[] = {
    316 	{	/* struct fd_char fdchar_1.7MB density */
    317 		0,		/* medium */
    318 		500,		/* transfer rate */
    319 		80,		/* number of cylinders */
    320 		2,		/* number of heads */
    321 		512,		/* sector size */
    322 		21,		/* sectors per track */
    323 		-1,		/* (NA) # steps per data track */
    324 	},
    325 	{	/* struct fd_char fdchar_highdens */
    326 		0, 		/* medium */
    327 		500, 		/* transfer rate */
    328 		80, 		/* number of cylinders */
    329 		2, 		/* number of heads */
    330 		512, 		/* sector size */
    331 		18, 		/* sectors per track */
    332 		-1, 		/* (NA) # steps per data track */
    333 	},
    334 	{	/* struct fd_char fdchar_meddens */
    335 		1, 		/* medium */
    336 		500, 		/* transfer rate */
    337 		77, 		/* number of cylinders */
    338 		2, 		/* number of heads */
    339 		1024, 		/* sector size */
    340 		8, 		/* sectors per track */
    341 		-1, 		/* (NA) # steps per data track */
    342 	},
    343 	{	/* struct fd_char fdchar_lowdens  */
    344 		0, 		/* medium */
    345 		250, 		/* transfer rate */
    346 		80, 		/* number of cylinders */
    347 		2, 		/* number of heads */
    348 		512, 		/* sector size */
    349 		9, 		/* sectors per track */
    350 		-1, 		/* (NA) # steps per data track */
    351 	}
    352 };
    353 
    354 
    355 static int nfdtypes = sizeof (fdtypes) / sizeof (fdtypes[0]);
    356 
    357 
    358 /*
    359  * Default Label & partition maps
    360  */
    361 
    362 static struct packed_label fdlbl_high_21 = {
    363 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 21" },
    364 	300,				/* rotations per minute */
    365 	80,				/* # physical cylinders */
    366 	0,				/* alternates per cylinder */
    367 	1,				/* interleave factor */
    368 	80,				/* # of data cylinders */
    369 	0,				/* # of alternate cylinders */
    370 	2,				/* # of heads in this partition */
    371 	21,				/* # of 512 byte sectors per track */
    372 	{
    373 		{ 0, 79 * 2 * 21 },	/* part 0 - all but last cyl */
    374 		{ 79, 1 * 2 * 21 },	/* part 1 - just the last cyl */
    375 		{ 0, 80 * 2 * 21 },	/* part 2 - "the whole thing" */
    376 	},
    377 	{	0,			/* version */
    378 		"",			/* volume label */
    379 		3,			/* no. of partitions */
    380 		{ 0 },			/* partition hdrs, sec 2 */
    381 		{ 0 },			/* mboot info.  unsupported */
    382 		VTOC_SANE,		/* verify vtoc sanity */
    383 		{ 0 },			/* reserved space */
    384 		0,			/* timestamp */
    385 	},
    386 };
    387 
    388 static struct packed_label fdlbl_high_80 = {
    389 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 18" },
    390 	300, 				/* rotations per minute */
    391 	80, 				/* # physical cylinders */
    392 	0, 				/* alternates per cylinder */
    393 	1, 				/* interleave factor */
    394 	80, 				/* # of data cylinders */
    395 	0, 				/* # of alternate cylinders */
    396 	2, 				/* # of heads in this partition */
    397 	18, 				/* # of 512 byte sectors per track */
    398 	{
    399 		{ 0, 79 * 2 * 18 }, 	/* part 0 - all but last cyl */
    400 		{ 79, 1 * 2 * 18 }, 	/* part 1 - just the last cyl */
    401 		{ 0, 80 * 2 * 18 }, 	/* part 2 - "the whole thing" */
    402 	},
    403 	{	0,			/* version */
    404 		"",			/* volume label */
    405 		3,			/* no. of partitions */
    406 		{ 0 },			/* partition hdrs, sec 2 */
    407 		{ 0 },			/* mboot info.  unsupported */
    408 		VTOC_SANE,		/* verify vtoc sanity */
    409 		{ 0 },			/* reserved space */
    410 		0,			/* timestamp */
    411 	},
    412 };
    413 
    414 /*
    415  * A medium density diskette has 1024 byte sectors.  The dk_label structure
    416  * assumes a sector is DEVBSIZE (512) bytes.
    417  */
    418 static struct packed_label fdlbl_medium_80 = {
    419 	{ "3.5\" floppy cyl 77 alt 0 hd 2 sec 8" },
    420 	360, 				/* rotations per minute */
    421 	77, 				/* # physical cylinders */
    422 	0, 				/* alternates per cylinder */
    423 	1, 				/* interleave factor */
    424 	77, 				/* # of data cylinders */
    425 	0, 				/* # of alternate cylinders */
    426 	2, 				/* # of heads in this partition */
    427 	16, 				/* # of 512 byte sectors per track */
    428 	{
    429 		{ 0, 76 * 2 * 8 * 2 },  /* part 0 - all but last cyl */
    430 		{ 76, 1 * 2 * 8 * 2 },  /* part 1 - just the last cyl */
    431 		{ 0, 77 * 2 * 8 * 2 },  /* part 2 - "the whole thing" */
    432 	},
    433 	{	0,			/* version */
    434 		"",			/* volume label */
    435 		3,			/* no. of partitions */
    436 		{ 0 },			/* partition hdrs, sec 2 */
    437 		{ 0 },			/* mboot info.  unsupported */
    438 		VTOC_SANE,		/* verify vtoc sanity */
    439 		{ 0 },			/* reserved space */
    440 		0,			/* timestamp */
    441 	},
    442 };
    443 
    444 static struct packed_label fdlbl_low_80 = {
    445 	{ "3.5\" floppy cyl 80 alt 0 hd 2 sec 9" },
    446 	300, 				/* rotations per minute */
    447 	80, 				/* # physical cylinders */
    448 	0, 				/* alternates per cylinder */
    449 	1, 				/* interleave factor */
    450 	80, 				/* # of data cylinders */
    451 	0, 				/* # of alternate cylinders */
    452 	2, 				/* # of heads in this partition */
    453 	9, 				/* # of 512 byte sectors per track */
    454 	{
    455 		{ 0, 79 * 2 * 9 }, 	/* part 0 - all but last cyl */
    456 		{ 79, 1 * 2 * 9 }, 	/* part 1 - just the last cyl */
    457 		{ 0, 80 * 2 * 9 }, 	/* part 2 - "the whole thing" */
    458 	},
    459 	{	0,			/* version */
    460 		"",			/* volume label */
    461 		3,			/* no. of partitions */
    462 		{ 0 },			/* partition hdrs, sec 2 */
    463 		{ 0 },			/* mboot info.  unsupported */
    464 		VTOC_SANE,		/* verify vtoc sanity */
    465 		{ 0 },			/* reserved space */
    466 		0,			/* timestamp */
    467 	},
    468 };
    469 
    470 static struct fdcmdinfo {
    471 	char *cmdname;		/* command name */
    472 	uchar_t ncmdbytes;	/* number of bytes of command */
    473 	uchar_t nrsltbytes;	/* number of bytes in result */
    474 	uchar_t cmdtype;		/* characteristics */
    475 } fdcmds[] = {
    476 	"", 0, 0, 0, 			/* - */
    477 	"", 0, 0, 0, 			/* - */
    478 	"read_track", 9, 7, 1, 		/* 2 */
    479 	"specify", 3, 0, 3, 		/* 3 */
    480 	"sense_drv_status", 2, 1, 3, 	/* 4 */
    481 	"write", 9, 7, 1, 		/* 5 */
    482 	"read", 9, 7, 1, 		/* 6 */
    483 	"recalibrate", 2, 0, 2, 		/* 7 */
    484 	"sense_int_status", 1, 2, 3, 	/* 8 */
    485 	"write_del", 9, 7, 1, 		/* 9 */
    486 	"read_id", 2, 7, 2, 		/* A */
    487 	"motor_on/off", 1, 0, 4, 	/* B */
    488 	"read_del", 9, 7, 1, 		/* C */
    489 	"format_track", 10, 7, 1, 	/* D */
    490 	"dump_reg", 1, 10, 4, 		/* E */
    491 	"seek", 3, 0, 2, 		/* F */
    492 	"", 0, 0, 0, 			/* - */
    493 	"", 0, 0, 0, 			/* - */
    494 	"", 0, 0, 0, 			/* - */
    495 	"configure", 4, 0, 4, 		/* 13 */
    496 	/* relative seek */
    497 };
    498 
    499 static struct cb_ops fd_cb_ops = {
    500 	fd_open, 		/* open */
    501 	fd_close, 		/* close */
    502 	fd_strategy, 		/* strategy */
    503 	nodev, 			/* print */
    504 	nodev, 			/* dump */
    505 	fd_read, 		/* read */
    506 	fd_write, 		/* write */
    507 	fd_ioctl, 		/* ioctl */
    508 	nodev, 			/* devmap */
    509 	nodev, 			/* mmap */
    510 	nodev, 			/* segmap */
    511 	nochpoll, 		/* poll */
    512 	fd_prop_op, 		/* cb_prop_op */
    513 	0, 			/* streamtab  */
    514 	D_NEW | D_MP		/* Driver compatibility flag */
    515 };
    516 
    517 static struct dev_ops	fd_ops = {
    518 	DEVO_REV, 		/* devo_rev, */
    519 	0, 			/* refcnt  */
    520 	fd_info, 		/* info */
    521 	nulldev, 		/* identify */
    522 	nulldev, 		/* probe */
    523 	fd_attach, 		/* attach */
    524 	fd_detach, 		/* detach */
    525 	nodev, 			/* reset */
    526 	&fd_cb_ops, 		/* driver operations */
    527 	(struct bus_ops *)0,	/* bus operations */
    528 	fd_power,		/* power */
    529 	ddi_quiesce_not_supported,	/* devo_quiesce */
    530 };
    531 
    532 
    533 /*
    534  * error handling
    535  *
    536  * for debugging, set rwretry and skretry = 1
    537  *		set fderrlevel to 1
    538  *		set fderrmask  to 224  or 100644
    539  *
    540  * after debug set rwretry to 10, skretry to 5, and fderrlevel to 3
    541  * set fderrmask to FDEM_ALL
    542  * remove the define FD_DEBUG
    543  *
    544  */
    545 
    546 static unsigned int fderrmask = (unsigned int)FDEM_ALL;
    547 static int fderrlevel = 3;
    548 
    549 static int tosec = 16;  /* long timeouts for sundiag for now */
    550 
    551 /*
    552  * loadable module support
    553  */
    554 
    555 #include <sys/modctl.h>
    556 
    557 extern struct mod_ops mod_driverops;
    558 static struct modldrv modldrv = {
    559 	&mod_driverops,		/* Type of module. driver here */
    560 	"Floppy Driver", 	/* Name of the module. */
    561 	&fd_ops, 		/* Driver ops vector */
    562 };
    563 
    564 static struct modlinkage modlinkage = {
    565 	MODREV_1,
    566 	&modldrv,
    567 	NULL
    568 };
    569 
    570 int
    571 _init(void)
    572 {
    573 	return (mod_install(&modlinkage));
    574 }
    575 
    576 int
    577 _info(struct modinfo *modinfop)
    578 {
    579 	return (mod_info(&modlinkage, modinfop));
    580 }
    581 
    582 int
    583 _fini(void)
    584 {
    585 	int e;
    586 
    587 	if ((e = mod_remove(&modlinkage)) != 0)
    588 		return (e);
    589 
    590 	/* ddi_soft_state_fini() */
    591 	return (0);
    592 }
    593 
    594 /* ARGSUSED */
    595 static int
    596 fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    597 {
    598 	struct 			fdctlr *fdc;
    599 	struct 			driver_minor_data *dmdp;
    600 	int			instance = ddi_get_instance(dip);
    601 	int			hard_intr_set = 0;
    602 
    603 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: start\n"));
    604 
    605 	switch (cmd) {
    606 		case DDI_ATTACH:
    607 			break;
    608 		case DDI_RESUME:
    609 
    610 			if (!(fdc = fd_getctlr(instance << FDINSTSHIFT))) {
    611 				return (DDI_FAILURE);
    612 			}
    613 			quiesce_fd_interrupt(fdc);
    614 			if (fdc->c_fdtype & FDCTYPE_SB)
    615 				if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
    616 				    fdintr_dma, (caddr_t)0) != DDI_SUCCESS) {
    617 				return (DDI_FAILURE);
    618 			}
    619 
    620 			(void) pm_raise_power(dip, 0, PM_LEVEL_ON);
    621 			mutex_enter(&fdc->c_lolock);
    622 			/*
    623 			 * Wake up any thread blocked due to I/O requests
    624 			 * while the device was suspended.
    625 			 */
    626 			cv_broadcast(&fdc->c_suspend_cv);
    627 			mutex_exit(&fdc->c_lolock);
    628 			return (DDI_SUCCESS);
    629 
    630 		default:
    631 			return (DDI_FAILURE);
    632 	}
    633 
    634 
    635 	/*
    636 	 * Check for the pollable property
    637 	 * A pollable floppy drive currently only exists on the
    638 	 * Sparcstation Voyager.  This drive does not need to
    639 	 * be turned on in order to sense whether or not a diskette
    640 	 * is present.
    641 	 */
    642 	if (ddi_getprop(DDI_DEV_T_ANY, dip,
    643 	    DDI_PROP_DONTPASS, FD_POLLABLE_PROP, 0))
    644 		fd_pollable = 1;
    645 
    646 	fdc = kmem_zalloc(sizeof (*fdc), KM_SLEEP);
    647 	fdc->c_dip = dip;
    648 
    649 
    650 	fdc->c_next = fdctlrs;
    651 	fdctlrs = fdc;
    652 
    653 	/* Determine which type of controller is present and initialize it */
    654 	if (fd_attach_det_ctlr(dip, fdc) == DDI_FAILURE) {
    655 		fd_cleanup(dip, fdc, hard_intr_set, 0);
    656 		return (DDI_FAILURE);
    657 	}
    658 	/* Finish mapping the device registers & setting up structures */
    659 	if (fd_attach_map_regs(dip, fdc) == DDI_FAILURE) {
    660 		fd_cleanup(dip, fdc, hard_intr_set, 0);
    661 		return (DDI_FAILURE);
    662 	}
    663 
    664 	/*
    665 	 * Initialize the DMA limit structures if it's being used.
    666 	 */
    667 	if (fdc->c_fdtype & FDCTYPE_DMA) {
    668 		fdc->c_fd_dma_lim.dma_attr_version = DMA_ATTR_V0;
    669 		fdc->c_fd_dma_lim.dma_attr_addr_lo = 0x00000000ull;
    670 		fdc->c_fd_dma_lim.dma_attr_addr_hi = 0xfffffffeull;
    671 		fdc->c_fd_dma_lim.dma_attr_count_max = 0xffffff;
    672 		if (fdc->c_fdtype & FDCTYPE_SB) {
    673 			fdc->c_fd_dma_lim.dma_attr_align = FD_SB_DMA_ALIGN;
    674 		} else {
    675 			fdc->c_fd_dma_lim.dma_attr_align = 1;
    676 		}
    677 		fdc->c_fd_dma_lim.dma_attr_burstsizes = 0x0;
    678 		fdc->c_fd_dma_lim.dma_attr_minxfer = 1;
    679 		fdc->c_fd_dma_lim.dma_attr_maxxfer = 0xffff;
    680 		fdc->c_fd_dma_lim.dma_attr_seg = 0xffff;
    681 		fdc->c_fd_dma_lim.dma_attr_sgllen = 1;
    682 		fdc->c_fd_dma_lim.dma_attr_granular = 512;
    683 
    684 		if (ddi_dma_alloc_handle(dip, &fdc->c_fd_dma_lim,
    685 		    DDI_DMA_DONTWAIT, 0, &fdc->c_dmahandle) != DDI_SUCCESS) {
    686 			fd_cleanup(dip, fdc, hard_intr_set, 0);
    687 			return (DDI_FAILURE);
    688 		}
    689 
    690 		if (fdc->c_fdtype & FDCTYPE_SB) {
    691 			ddi_device_acc_attr_t dev_attr;
    692 			size_t	rlen;
    693 
    694 			dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
    695 			dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
    696 			dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
    697 
    698 			if (ddi_dma_mem_alloc(fdc->c_dmahandle,
    699 			    (size_t)(32*1024), &dev_attr, DDI_DMA_CONSISTENT,
    700 			    DDI_DMA_SLEEP, NULL, (caddr_t *)&fdc->dma_buf,
    701 			    &rlen, &fdc->c_dma_buf_handle) != DDI_SUCCESS) {
    702 				fd_cleanup(dip, fdc, hard_intr_set, 0);
    703 				return (DDI_FAILURE);
    704 			}
    705 
    706 		}
    707 	}
    708 
    709 
    710 	/* Register the interrupts */
    711 	if (fd_attach_register_interrupts(dip, fdc,
    712 	    &hard_intr_set) == DDI_FAILURE) {
    713 		fd_cleanup(dip, fdc, hard_intr_set, 0);
    714 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
    715 		    (C, "fd_attach: registering interrupts failed\n"));
    716 		return (DDI_FAILURE);
    717 	}
    718 
    719 
    720 	/*
    721 	 * set initial controller/drive/disk "characteristics/geometry"
    722 	 *
    723 	 * NOTE:  The driver only supports one floppy drive.  The hardware
    724 	 * only supports one drive because there is only one auxio register
    725 	 * for one drive.
    726 	 */
    727 	fdc->c_un = kmem_zalloc(sizeof (struct fdunit), KM_SLEEP);
    728 	fdc->c_un->un_chars = kmem_alloc(sizeof (struct fd_char), KM_SLEEP);
    729 	fdc->c_un->un_iostat = kstat_create("fd", 0, "fd0", "disk",
    730 	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
    731 	if (fdc->c_un->un_iostat) {
    732 		fdc->c_un->un_iostat->ks_lock = &fdc->c_lolock;
    733 		kstat_install(fdc->c_un->un_iostat);
    734 	}
    735 
    736 	fdc->c_un->un_drive = kmem_zalloc(sizeof (struct fd_drive), KM_SLEEP);
    737 
    738 	/* check for the manual eject property */
    739 	if (ddi_getprop(DDI_DEV_T_ANY, dip,
    740 	    DDI_PROP_DONTPASS, FD_MANUAL_EJECT, 0)) {
    741 		fdc->c_un->un_drive->fdd_ejectable = 0;
    742 	} else {
    743 		/* an absence of the property indicates auto eject */
    744 		fdc->c_un->un_drive->fdd_ejectable = -1;
    745 	}
    746 
    747 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: ejectable? %d\n",
    748 	    fdc->c_un->un_drive->fdd_ejectable));
    749 
    750 	/*
    751 	 * Check for the drive id.  If the drive id property doesn't exist
    752 	 * then the drive id is set to 0
    753 	 */
    754 	fdc->c_un->un_unit_no = ddi_getprop(DDI_DEV_T_ANY, dip,
    755 	    DDI_PROP_DONTPASS, FD_UNIT, 0);
    756 
    757 
    758 	if (fdc->c_fdtype & FDCTYPE_SB) {
    759 		fdc->sb_dma_channel = ddi_getprop(DDI_DEV_T_ANY, dip,
    760 		    DDI_PROP_DONTPASS, "dma-channel", 0);
    761 	}
    762 
    763 
    764 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: unit %d\n",
    765 	    fdc->c_un->un_unit_no));
    766 
    767 	/* Initially set the characteristics to high density */
    768 	fdc->c_un->un_curfdtype = 1;
    769 	*fdc->c_un->un_chars = fdtypes[fdc->c_un->un_curfdtype];
    770 	fdunpacklabel(&fdlbl_high_80, &fdc->c_un->un_label);
    771 
    772 	/* Make sure drive is present */
    773 	if (fd_attach_check_drive(fdc) == DDI_FAILURE) {
    774 		fd_cleanup(dip, fdc, hard_intr_set, 1);
    775 		return (DDI_FAILURE);
    776 	}
    777 
    778 	for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
    779 		if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
    780 		    (instance << FDINSTSHIFT) | dmdp->minor,
    781 		    DDI_NT_FD, 0) == DDI_FAILURE) {
    782 			fd_cleanup(dip, fdc, hard_intr_set, 1);
    783 			return (DDI_FAILURE);
    784 		}
    785 	}
    786 
    787 	create_pm_components(dip);
    788 
    789 	/*
    790 	 * Add a zero-length attribute to tell the world we support
    791 	 * kernel ioctls (for layered drivers)
    792 	 */
    793 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
    794 	    DDI_KERNEL_IOCTL, NULL, 0);
    795 
    796 	ddi_report_dev(dip);
    797 
    798 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
    799 	    (C, "attached 0x%x\n", ddi_get_instance(dip)));
    800 
    801 	return (DDI_SUCCESS);
    802 }
    803 
    804 /*
    805  * Finish mapping the registers and initializing structures
    806  */
    807 static int
    808 fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc)
    809 {
    810 	ddi_device_acc_attr_t attr;
    811 
    812 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
    813 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
    814 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
    815 
    816 	/* Map the DMA registers of the platform supports DMA */
    817 	if (fdc->c_fdtype & FDCTYPE_SB) {
    818 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
    819 		    0, sizeof (struct sb_dma_reg), &attr,
    820 		    &fdc->c_handlep_dma)) {
    821 			return (DDI_FAILURE);
    822 		}
    823 
    824 
    825 	} else if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
    826 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
    827 		    0, sizeof (struct cheerio_dma_reg), &attr,
    828 		    &fdc->c_handlep_dma)) {
    829 			return (DDI_FAILURE);
    830 		}
    831 	}
    832 
    833 	/* Reset the DMA engine and enable floppy interrupts */
    834 	reset_dma_controller(fdc);
    835 	set_dma_control_register(fdc, DCSR_INIT_BITS);
    836 
    837 	/* Finish initializing structures associated with the device regs */
    838 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
    839 	case FDCTYPE_82077:
    840 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "type is 82077\n"));
    841 		/*
    842 		 * Initialize addrs of key registers
    843 		 */
    844 		fdc->c_control =
    845 		    (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_control;
    846 		fdc->c_fifo = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_fifo;
    847 		fdc->c_dor = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dor;
    848 		fdc->c_dir = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dir;
    849 
    850 
    851 		FDERRPRINT(FDEP_L1, FDEM_ATTA, ((int)C,
    852 		    (char *)"fdattach: msr/dsr at %p\n",
    853 		    (void *)fdc->c_control));
    854 
    855 		/*
    856 		 * The 82077 doesn't use the first configuration parameter
    857 		 * so let's adjust that while we know we're an 82077.
    858 		 */
    859 		fdconf[0] = 0;
    860 
    861 		quiesce_fd_interrupt(fdc);
    862 		break;
    863 	default:
    864 		break;
    865 	}
    866 
    867 	return (0);
    868 }
    869 
    870 /*
    871  * Determine which type of floppy controller is present and
    872  * initialize the registers accordingly
    873  */
    874 static int
    875 fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc)
    876 {
    877 	ddi_device_acc_attr_t attr;
    878 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
    879 	/* DDI_NEVERSWAP_ACC since the controller has a byte interface. */
    880 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
    881 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
    882 
    883 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
    884 	    (C, "fdattach_det_cltr: start \n"));
    885 
    886 	/*
    887 	 * First, map in the controller's registers
    888 	 * The controller has an 8-bit interface, so byte
    889 	 * swapping isn't needed
    890 	 */
    891 
    892 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&fdc->c_reg,
    893 	    0, sizeof (union fdcreg),
    894 	    &attr,
    895 	    &fdc->c_handlep_cont)) {
    896 		return (DDI_FAILURE);
    897 	}
    898 
    899 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
    900 	    (C, "fdattach_det_cltr: mapped floppy regs\n"));
    901 
    902 
    903 	/*
    904 	 * Set platform specific characteristics based on the device-tree
    905 	 * node name.
    906 	 */
    907 
    908 
    909 	if (strcmp(ddi_get_name(dip), "SUNW,fdtwo") == 0) {
    910 		fdc->c_fdtype |= FDCTYPE_SLAVIO;
    911 		fdc->c_fdtype |= FDCTYPE_82077;
    912 		fdc->c_auxiova = fd_getauxiova(dip);
    913 		fdc->c_auxiodata = (uchar_t)(AUX_MBO4M|AUX_TC4M);
    914 		fdc->c_auxiodata2 = (uchar_t)AUX_TC4M;
    915 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
    916 		    (C, "fdattach: slavio will be used!\n"));
    917 
    918 
    919 /*
    920  * Check the binding name to identify whether it is a South bridge based
    921  * system or not.
    922  */
    923 	} else if (strcmp(ddi_get_name(dip), "pnpALI,1533,0") == 0) {
    924 
    925 		fdc->c_fdtype |= FDCTYPE_SB;
    926 		fdc->c_fdtype |= FDCTYPE_82077;
    927 		fdc->c_fdtype |= FDCTYPE_DMA;
    928 
    929 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
    930 		    (C, "fdattach: southbridge will be used!\n"));
    931 
    932 		/*
    933 		 * The driver assumes high density characteristics until
    934 		 * the diskette is looked at.
    935 		 */
    936 
    937 		fdc->c_fdtype |= FDCTYPE_DMA8237;
    938 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
    939 
    940 
    941 	} else if (strcmp(ddi_get_name(dip), "fdthree") == 0) {
    942 
    943 		fdc->c_fdtype |= FDCTYPE_CHEERIO;
    944 		fdc->c_fdtype |= FDCTYPE_82077;
    945 
    946 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
    947 		    (C, "fdattach: cheerio will be used!\n"));
    948 		/*
    949 		 * The cheerio auxio register should be memory mapped.  The
    950 		 * auxio register on other platforms is shared and mapped
    951 		 * elsewhere in the kernel
    952 		 */
    953 		if (ddi_regs_map_setup(dip, 2, (caddr_t *)&fdc->c_auxio_reg,
    954 		    0, sizeof (uint_t), &attr, &fdc->c_handlep_aux)) {
    955 			return (DDI_FAILURE);
    956 		}
    957 
    958 		/*
    959 		 * The driver assumes high density characteristics until
    960 		 * the diskette is looked at.
    961 		 */
    962 		Set_auxio(fdc, AUX_HIGH_DENSITY);
    963 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
    964 		    (C, "fdattach: auxio register 0x%x\n",
    965 		    *fdc->c_auxio_reg));
    966 
    967 		fdc->c_fdtype |= FDCTYPE_DMA;
    968 		FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
    969 
    970 	}
    971 
    972 	if (fdc->c_fdtype == 0) {
    973 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
    974 		    (C, "fdattach: no controller!\n"));
    975 		return (DDI_FAILURE);
    976 	} else {
    977 		return (0);
    978 	}
    979 }
    980 
    981 
    982 /*
    983  * Register the floppy interrupts
    984  */
    985 static int
    986 fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc, int *hard)
    987 {
    988 	ddi_iblock_cookie_t  iblock_cookie_soft;
    989 	int status;
    990 
    991 	/*
    992 	 * First call ddi_get_iblock_cookie() to retrieve the
    993 	 * the interrupt block cookie so that the mutexes may
    994 	 * be initialized before adding the interrupt.  If the
    995 	 * mutexes are initialized after adding the interrupt, there
    996 	 * could be a race condition.
    997 	 */
    998 	if (ddi_get_iblock_cookie(dip, 0, &fdc->c_block) != DDI_SUCCESS) {
    999 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1000 		    (C, "fdattach: ddi_get_iblock_cookie failed\n"));
   1001 		return (DDI_FAILURE);
   1002 
   1003 	}
   1004 
   1005 	/* Initialize high level mutex */
   1006 	mutex_init(&fdc->c_hilock, NULL, MUTEX_DRIVER, fdc->c_block);
   1007 
   1008 	/*
   1009 	 * Try to register fast trap handler, if unable try standard
   1010 	 * interrupt handler, else bad
   1011 	 */
   1012 
   1013 	if (fdc->c_fdtype & FDCTYPE_DMA) {
   1014 		if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
   1015 		    fdintr_dma, (caddr_t)0) == DDI_SUCCESS) {
   1016 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1017 			    (C, "fdattach: standard intr\n"));
   1018 
   1019 				/*
   1020 				 * When DMA is used, the low level lock
   1021 				 * is used in the hard interrupt handler.
   1022 				 */
   1023 				mutex_init(&fdc->c_lolock, NULL,
   1024 				    MUTEX_DRIVER, fdc->c_block);
   1025 
   1026 				*hard = 1;
   1027 		} else {
   1028 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1029 			    (C, "fdattach: can't add dma intr\n"));
   1030 
   1031 			mutex_destroy(&fdc->c_hilock);
   1032 
   1033 			return (DDI_FAILURE);
   1034 		}
   1035 	} else {
   1036 		/*
   1037 		 * Platforms that don't support DMA have both hard
   1038 		 * and soft interrupts.
   1039 		 */
   1040 		if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
   1041 		    fd_intr, (caddr_t)0) == DDI_SUCCESS) {
   1042 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1043 			    (C, "fdattach: standard intr\n"));
   1044 			*hard = 1;
   1045 
   1046 			/* fast traps are not enabled */
   1047 			fdc->c_fasttrap = 0;
   1048 
   1049 		} else {
   1050 			FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1051 			    (C, "fdattach: can't add intr\n"));
   1052 
   1053 			mutex_destroy(&fdc->c_hilock);
   1054 
   1055 			return (DDI_FAILURE);
   1056 		}
   1057 
   1058 
   1059 		/*
   1060 		 * Initialize the soft interrupt handler.  First call
   1061 		 * ddi_get_soft_iblock_cookie() so that the mutex may
   1062 		 * be initialized before the handler is added.
   1063 		 */
   1064 		status = ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
   1065 		    &iblock_cookie_soft);
   1066 
   1067 
   1068 		if (status != DDI_SUCCESS) {
   1069 			mutex_destroy(&fdc->c_hilock);
   1070 			return (DDI_FAILURE);
   1071 		}
   1072 
   1073 		/*
   1074 		 * Initialize low level mutex which is used in the soft
   1075 		 * interrupt handler
   1076 		 */
   1077 		mutex_init(&fdc->c_lolock, NULL, MUTEX_DRIVER,
   1078 		    iblock_cookie_soft);
   1079 
   1080 		if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &fdc->c_softid,
   1081 		    NULL, NULL,
   1082 		    fd_lointr,
   1083 		    (caddr_t)fdc) != DDI_SUCCESS) {
   1084 
   1085 			mutex_destroy(&fdc->c_hilock);
   1086 			mutex_destroy(&fdc->c_lolock);
   1087 
   1088 			return (DDI_FAILURE);
   1089 		}
   1090 	}
   1091 
   1092 	fdc->c_intrstat = kstat_create("fd", 0, "fdc0", "controller",
   1093 	    KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
   1094 	if (fdc->c_intrstat) {
   1095 		fdc->c_hiintct = &KIOIP->intrs[KSTAT_INTR_HARD];
   1096 		kstat_install(fdc->c_intrstat);
   1097 	}
   1098 
   1099 	/* condition variable to wait on while an io transaction occurs */
   1100 	cv_init(&fdc->c_iocv, NULL, CV_DRIVER, NULL);
   1101 
   1102 	/* condition variable for the csb */
   1103 	cv_init(&fdc->c_csbcv, NULL, CV_DRIVER, NULL);
   1104 
   1105 	/* condition variable for motor on waiting period */
   1106 	cv_init(&fdc->c_motoncv, NULL, CV_DRIVER, NULL);
   1107 
   1108 	/* semaphore to serialize opens and closes */
   1109 	sema_init(&fdc->c_ocsem, 1, NULL, SEMA_DRIVER, NULL);
   1110 
   1111 	/* condition variable to wait on suspended floppy controller. */
   1112 	cv_init(&fdc->c_suspend_cv, NULL, CV_DRIVER, NULL);
   1113 
   1114 	return (0);
   1115 }
   1116 
   1117 /*
   1118  * Make sure the drive is present
   1119  * 	- acquires the low level lock
   1120  */
   1121 static int
   1122 fd_attach_check_drive(struct fdctlr *fdc)
   1123 {
   1124 	int tmp_fderrlevel;
   1125 	int unit = fdc->c_un->un_unit_no;
   1126 
   1127 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1128 	    (C, "fd_attach_check_drive\n"));
   1129 
   1130 
   1131 	mutex_enter(&fdc->c_lolock);
   1132 	switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
   1133 
   1134 	/* insure that the eject line is reset */
   1135 	case FDCTYPE_82077:
   1136 
   1137 		/*
   1138 		 * Everything but the motor enable, drive select,
   1139 		 * and reset bits are turned off.  These three
   1140 		 * bits remain as they are.
   1141 		 */
   1142 		/* LINTED */
   1143 		Set_dor(fdc, ~((MOTEN(unit))|DRVSEL|RESET), 0);
   1144 
   1145 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1146 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
   1147 
   1148 		drv_usecwait(5);
   1149 		if (unit == 0) {
   1150 			/* LINTED */
   1151 			Set_dor(fdc, RESET|DRVSEL, 1);
   1152 		} else {
   1153 
   1154 			/* LINTED */
   1155 			Set_dor(fdc, DRVSEL, 0);
   1156 			/* LINTED */
   1157 			Set_dor(fdc, RESET, 1);
   1158 		}
   1159 
   1160 		drv_usecwait(5);
   1161 
   1162 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1163 		    (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
   1164 
   1165 		if (!((fdc->c_fdtype & FDCTYPE_CHEERIO) ||
   1166 		    (fdc->c_fdtype & FDCTYPE_SB))) {
   1167 			set_auxioreg(AUX_TC4M, 0);
   1168 		}
   1169 		break;
   1170 	default:
   1171 		break;
   1172 	}
   1173 
   1174 
   1175 	fdgetcsb(fdc);
   1176 	if (fdreset(fdc) != 0) {
   1177 		mutex_exit(&fdc->c_lolock);
   1178 		return (DDI_FAILURE);
   1179 	}
   1180 
   1181 
   1182 	/* check for drive present */
   1183 
   1184 	tmp_fderrlevel = fderrlevel;
   1185 
   1186 
   1187 	fderrlevel = FDEP_LMAX;
   1188 
   1189 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1190 	    (C, "fdattach: call fdrecalseek\n"));
   1191 
   1192 	/* Make sure the drive is present */
   1193 	if (fdrecalseek(fdc, unit, -1, 0) != 0) {
   1194 		timeout_id_t timeid = fdc->c_mtimeid;
   1195 		fderrlevel = tmp_fderrlevel;
   1196 		fdc->c_mtimeid = 0;
   1197 		mutex_exit(&fdc->c_lolock);
   1198 
   1199 
   1200 		/* Do not hold the mutex over the call to untimeout */
   1201 		if (timeid) {
   1202 			(void) untimeout(timeid);
   1203 		}
   1204 
   1205 		FDERRPRINT(FDEP_L2, FDEM_ATTA,
   1206 		    (C, "fd_attach: no drive?\n"));
   1207 
   1208 		return (DDI_FAILURE);
   1209 	}
   1210 
   1211 	fderrlevel = tmp_fderrlevel;
   1212 
   1213 	fdselect(fdc, unit, 0);    /* deselect drive zero (used in fdreset) */
   1214 	fdretcsb(fdc);
   1215 	mutex_exit(&fdc->c_lolock);
   1216 
   1217 	return (0);
   1218 }
   1219 
   1220 /*
   1221  * Clean up routine used by fd_detach and fd_attach
   1222  *
   1223  * Note: if the soft id is non-zero, then ddi_add_softintr() completed
   1224  * successfully.  I can not make the same assumption about the iblock_cookie
   1225  * for the high level interrupt handler.  So, the hard parameter indicates
   1226  * whether or not a high level interrupt handler has been added.
   1227  *
   1228  * If the locks parameter is nonzero, then all mutexes, semaphores and
   1229  * condition variables will be destroyed.
   1230  *
   1231  * Does not assume the low level mutex is held.
   1232  *
   1233  */
   1234 static void
   1235 fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard, int locks)
   1236 {
   1237 
   1238 
   1239 	FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1240 	    (C, "fd_cleanup instance: %d ctlr: 0x%p\n",
   1241 	    ddi_get_instance(dip), (void *)fdc));
   1242 
   1243 
   1244 	if (fdc == NULL) {
   1245 		return;
   1246 	}
   1247 
   1248 	/*
   1249 	 * Remove interrupt handlers first before anything else
   1250 	 * is deallocated.
   1251 	 */
   1252 
   1253 	/* Remove hard interrupt if one is registered */
   1254 	if (hard) {
   1255 		ddi_remove_intr(dip, (uint_t)0, fdc->c_block);
   1256 	}
   1257 
   1258 	/* Remove soft interrupt if one is registered */
   1259 	if (fdc->c_softid != NULL)
   1260 		ddi_remove_softintr(fdc->c_softid);
   1261 
   1262 
   1263 	/* Remove timers */
   1264 	if (fdc->c_fdtype & FDCTYPE_82077) {
   1265 		if (fdc->c_mtimeid)
   1266 			(void) untimeout(fdc->c_mtimeid);
   1267 		/*
   1268 		 * Need to turn off motor (includes select/LED for South Bridge
   1269 		 * chipset) just in case it was on when timer was removed
   1270 		 */
   1271 		fdmotoff(fdc);
   1272 	}
   1273 	if (fdc->c_timeid)
   1274 		(void) untimeout(fdc->c_timeid);
   1275 
   1276 
   1277 	/* Remove memory handles */
   1278 	if (fdc->c_handlep_cont)
   1279 		ddi_regs_map_free(&fdc->c_handlep_cont);
   1280 
   1281 	if (fdc->c_handlep_aux)
   1282 		ddi_regs_map_free(&fdc->c_handlep_aux);
   1283 
   1284 	if (fdc->c_handlep_dma)
   1285 		ddi_regs_map_free(&fdc->c_handlep_dma);
   1286 
   1287 	if (fdc->c_dma_buf_handle != NULL)
   1288 		ddi_dma_mem_free(&fdc->c_dma_buf_handle);
   1289 
   1290 	if (fdc->c_dmahandle != NULL)
   1291 		ddi_dma_free_handle(&fdc->c_dmahandle);
   1292 
   1293 
   1294 	/* Remove all minor nodes */
   1295 	ddi_remove_minor_node(dip, NULL);
   1296 
   1297 
   1298 
   1299 	/* Remove unit structure if one exists */
   1300 	if (fdc->c_un != (struct fdunit *)NULL) {
   1301 
   1302 		ASSERT(!mutex_owned(&fdc->c_lolock));
   1303 
   1304 		if (fdc->c_un->un_iostat)
   1305 			kstat_delete(fdc->c_un->un_iostat);
   1306 		fdc->c_un->un_iostat = NULL;
   1307 
   1308 		if (fdc->c_un->un_chars)
   1309 			kmem_free(fdc->c_un->un_chars, sizeof (struct fd_char));
   1310 
   1311 		if (fdc->c_un->un_drive)
   1312 			kmem_free(fdc->c_un->un_drive,
   1313 			    sizeof (struct fd_drive));
   1314 
   1315 		kmem_free((caddr_t)fdc->c_un, sizeof (struct fdunit));
   1316 	}
   1317 
   1318 	if (fdc->c_intrstat) {
   1319 		FDERRPRINT(FDEP_L1, FDEM_ATTA,
   1320 		    (C, "fd_cleanup: delete intrstat\n"));
   1321 
   1322 		kstat_delete(fdc->c_intrstat);
   1323 	}
   1324 
   1325 	fdc->c_intrstat = NULL;
   1326 
   1327 	if (locks) {
   1328 		cv_destroy(&fdc->c_iocv);
   1329 		cv_destroy(&fdc->c_csbcv);
   1330 		cv_destroy(&fdc->c_motoncv);
   1331 		cv_destroy(&fdc->c_suspend_cv);
   1332 		sema_destroy(&fdc->c_ocsem);
   1333 		mutex_destroy(&fdc->c_hilock);
   1334 		mutex_destroy(&fdc->c_lolock);
   1335 	}
   1336 
   1337 
   1338 	fdctlrs = fdc->c_next;
   1339 	kmem_free(fdc, sizeof (*fdc));
   1340 
   1341 
   1342 }
   1343 
   1344 
   1345 static int
   1346 fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
   1347 {
   1348 	int instance = ddi_get_instance(dip);
   1349 	struct fdctlr *fdc = fd_getctlr(instance << FDINSTSHIFT);
   1350 	timeout_id_t c_mtimeid;
   1351 
   1352 	FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_detach\n"));
   1353 
   1354 	switch (cmd) {
   1355 
   1356 	case DDI_DETACH:
   1357 		/*
   1358 		 * The hard parameter is set to 1.  If detach is called, then
   1359 		 * attach must have passed meaning that the high level
   1360 		 * interrupt handler was successfully added.
   1361 		 * Similarly, the locks parameter is also set to 1.
   1362 		 */
   1363 		fd_cleanup(dip, fdc, 1, 1);
   1364 
   1365 		ddi_prop_remove_all(dip);
   1366 
   1367 		return (DDI_SUCCESS);
   1368 
   1369 	case DDI_SUSPEND:
   1370 		if (!fdc)
   1371 			return (DDI_FAILURE);
   1372 
   1373 
   1374 		mutex_enter(&fdc->c_lolock);
   1375 		fdgetcsb(fdc);	/* Wait for I/O to finish */
   1376 		c_mtimeid = fdc->c_mtimeid;
   1377 		fdretcsb(fdc);
   1378 		mutex_exit(&fdc->c_lolock);
   1379 
   1380 		(void) untimeout(c_mtimeid);
   1381 		/*
   1382 		 * After suspend, the system could be powered off.
   1383 		 * When it is later powered on the southbridge floppy
   1384 		 * controller will tristate the interrupt line causing
   1385 		 * continuous dma interrupts.
   1386 		 * To avoid getting continuous fd interrupts we will remove the
   1387 		 * dma interrupt handler installed. We will re-install the
   1388 		 * handler when we RESUME.
   1389 		 */
   1390 		if (fdc->c_fdtype & FDCTYPE_SB)
   1391 			ddi_remove_intr(dip, 0, fdc->c_block);
   1392 
   1393 		fdc->c_un->un_state = FD_STATE_SUSPENDED;
   1394 
   1395 		return (DDI_SUCCESS);
   1396 
   1397 	default:
   1398 		return (DDI_FAILURE);
   1399 	}
   1400 }
   1401 
   1402 /* ARGSUSED */
   1403 static int
   1404 fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
   1405 {
   1406 	register struct fdctlr *fdc;
   1407 	register int error;
   1408 
   1409 	switch (infocmd) {
   1410 
   1411 	case DDI_INFO_DEVT2DEVINFO:
   1412 		if ((fdc = fd_getctlr((dev_t)arg)) == NULL) {
   1413 			error = DDI_FAILURE;
   1414 		} else {
   1415 			*result = fdc->c_dip;
   1416 			error = DDI_SUCCESS;
   1417 		}
   1418 		break;
   1419 
   1420 	case DDI_INFO_DEVT2INSTANCE:
   1421 		*result = 0;
   1422 		error = DDI_SUCCESS;
   1423 		break;
   1424 
   1425 	default:
   1426 		error = DDI_FAILURE;
   1427 	}
   1428 	return (error);
   1429 }
   1430 
   1431 /*
   1432  * property operation routine.  return the number of blocks for the partition
   1433  * in question or forward the request to the property facilities.
   1434  */
   1435 static int
   1436 fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
   1437     char *name, caddr_t valuep, int *lengthp)
   1438 {
   1439 	struct fdunit	*un;
   1440 	struct fdctlr	*fdc;
   1441 	uint64_t	nblocks64;
   1442 
   1443 	/*
   1444 	 * Our dynamic properties are all device specific and size oriented.
   1445 	 * Requests issued under conditions where size is valid are passed
   1446 	 * to ddi_prop_op_nblocks with the size information, otherwise the
   1447 	 * request is passed to ddi_prop_op.
   1448 	 */
   1449 	if (dev == DDI_DEV_T_ANY) {
   1450 pass:  		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
   1451 		    name, valuep, lengthp));
   1452 	} else {
   1453 		fdc = fd_getctlr(dev);
   1454 		if (fdc == NULL)
   1455 			goto pass;
   1456 
   1457 		/* we have size if diskette opened and label read */
   1458 		un = fdc->c_un;
   1459 		if ((un == NULL) || !fd_unit_is_open(fdc->c_un))
   1460 			goto pass;
   1461 
   1462 		/* get nblocks value */
   1463 		nblocks64 = (ulong_t)
   1464 		    un->un_label.dkl_map[FDPARTITION(dev)].dkl_nblk;
   1465 
   1466 		return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
   1467 		    name, valuep, lengthp, nblocks64));
   1468 	}
   1469 }
   1470 
   1471 /* ARGSUSED3 */
   1472 static int
   1473 fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
   1474 {
   1475 	dev_t dev;
   1476 	int  part;
   1477 	struct fdctlr *fdc;
   1478 	struct fdunit *un;
   1479 	struct dk_map32 *dkm;
   1480 	uchar_t	pbit;
   1481 	int	err, part_is_open;
   1482 	int 	unit;
   1483 
   1484 	dev = *devp;
   1485 	fdc = fd_getctlr(dev);
   1486 	if ((fdc == NULL) || ((un = fdc->c_un) == NULL)) {
   1487 		return (ENXIO);
   1488 	}
   1489 
   1490 	unit = fdc->c_un->un_unit_no;
   1491 
   1492 	/*
   1493 	 * Serialize opens/closes
   1494 	 */
   1495 
   1496 	sema_p(&fdc->c_ocsem);
   1497 
   1498 	/* check partition */
   1499 	part = FDPARTITION(dev);
   1500 	pbit = 1 << part;
   1501 	dkm = &un->un_label.dkl_map[part];
   1502 	if (dkm->dkl_nblk == 0) {
   1503 		sema_v(&fdc->c_ocsem);
   1504 		return (ENXIO);
   1505 	}
   1506 
   1507 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
   1508 	    (C, "fdopen: ctlr %d unit %d part %d\n",
   1509 	    ddi_get_instance(fdc->c_dip), unit, part));
   1510 
   1511 	FDERRPRINT(FDEP_L1, FDEM_OPEN,
   1512 	    (C, "fdopen: flag 0x%x", flag));
   1513 
   1514 
   1515 	/*
   1516 	 * Insure that drive is present with a recalibrate on first open.
   1517 	 */
   1518 	(void) pm_busy_component(fdc->c_dip, 0);
   1519 
   1520 	mutex_enter(&fdc->c_lolock);
   1521 
   1522 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
   1523 
   1524 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
   1525 		mutex_exit(&fdc->c_lolock);
   1526 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
   1527 		    != DDI_SUCCESS) {
   1528 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
   1529 			    failed. \n"));
   1530 
   1531 				sema_v(&fdc->c_ocsem);
   1532 				(void) pm_idle_component(fdc->c_dip, 0);
   1533 				return (EIO);
   1534 		}
   1535 		mutex_enter(&fdc->c_lolock);
   1536 	}
   1537 	if (fd_unit_is_open(un) == 0) {
   1538 		fdgetcsb(fdc);
   1539 		/*
   1540 		 * no check changed!
   1541 		 */
   1542 		err = fdrecalseek(fdc, unit, -1, 0);
   1543 		fdretcsb(fdc);
   1544 		if (err) {
   1545 			FDERRPRINT(FDEP_L3, FDEM_OPEN,
   1546 			    (C, "fd%d: drive not ready\n", 0));
   1547 			/* deselect drv on last close */
   1548 			fdselect(fdc, unit, 0);
   1549 			mutex_exit(&fdc->c_lolock);
   1550 			sema_v(&fdc->c_ocsem);
   1551 			(void) pm_idle_component(fdc->c_dip, 0);
   1552 			return (EIO);
   1553 		}
   1554 	}
   1555 
   1556 	/*
   1557 	 * Check for previous exclusive open, or trying to exclusive open
   1558 	 */
   1559 	if (otyp == OTYP_LYR) {
   1560 		part_is_open = (un->un_lyropen[part] != 0);
   1561 	} else {
   1562 		part_is_open = fd_part_is_open(un, part);
   1563 	}
   1564 	if ((un->un_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
   1565 		mutex_exit(&fdc->c_lolock);
   1566 		sema_v(&fdc->c_ocsem);
   1567 		FDERRPRINT(FDEP_L2, FDEM_OPEN, (C, "fd:just return\n"));
   1568 		(void) pm_idle_component(fdc->c_dip, 0);
   1569 		return (EBUSY);
   1570 	}
   1571 
   1572 	/* don't attempt access, just return successfully */
   1573 	if (flag & (FNDELAY | FNONBLOCK)) {
   1574 		FDERRPRINT(FDEP_L2, FDEM_OPEN,
   1575 		    (C, "fd: return busy..\n"));
   1576 		goto out;
   1577 	}
   1578 
   1579 	fdc->c_csb.csb_unit = (uchar_t)unit;
   1580 	if (fdgetlabel(fdc, unit)) {
   1581 		/* didn't find label (couldn't read anything) */
   1582 		FDERRPRINT(FDEP_L3, FDEM_OPEN,
   1583 		    (C,
   1584 		    "fd%d: unformatted diskette or no diskette in the drive\n",
   1585 		    0));
   1586 		if (fd_unit_is_open(un) == 0) {
   1587 			/* deselect drv on last close */
   1588 			fdselect(fdc, unit, 0);
   1589 		}
   1590 
   1591 		mutex_exit(&fdc->c_lolock);
   1592 		sema_v(&fdc->c_ocsem);
   1593 		(void) pm_idle_component(fdc->c_dip, 0);
   1594 		return (EIO);
   1595 	}
   1596 
   1597 	/*
   1598 	 * if opening for writing, check write protect on diskette
   1599 	 */
   1600 	if (flag & FWRITE) {
   1601 		fdgetcsb(fdc);
   1602 		err = fdsensedrv(fdc, unit) & WP_SR3;
   1603 		fdretcsb(fdc);
   1604 		if (err) {
   1605 			if (fd_unit_is_open(un) == 0)
   1606 				fdselect(fdc, unit, 0);
   1607 			mutex_exit(&fdc->c_lolock);
   1608 			sema_v(&fdc->c_ocsem);
   1609 			(void) pm_idle_component(fdc->c_dip, 0);
   1610 			return (EROFS);
   1611 		}
   1612 	}
   1613 
   1614 out:
   1615 	/*
   1616 	 * mark open as having succeeded
   1617 	 */
   1618 	if (flag & FEXCL) {
   1619 		un->un_exclmask |= pbit;
   1620 	}
   1621 	if (otyp == OTYP_LYR) {
   1622 		un->un_lyropen[part]++;
   1623 	} else {
   1624 		un->un_regopen[otyp] |= pbit;
   1625 	}
   1626 	mutex_exit(&fdc->c_lolock);
   1627 	sema_v(&fdc->c_ocsem);
   1628 	(void) pm_idle_component(fdc->c_dip, 0);
   1629 	return (0);
   1630 }
   1631 /*
   1632  * fd_part_is_open
   1633  *	return 1 if the partition is open
   1634  *	return 0 otherwise
   1635  */
   1636 static int
   1637 fd_part_is_open(struct fdunit *un, int part)
   1638 {
   1639 	int i;
   1640 	for (i = 0; i < OTYPCNT - 1; i++)
   1641 		if (un->un_regopen[i] & (1 << part))
   1642 			return (1);
   1643 	return (0);
   1644 }
   1645 
   1646 
   1647 /* ARGSUSED */
   1648 static int
   1649 fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
   1650 {
   1651 	int unit, part_is_closed, part;
   1652 	register struct fdctlr *fdc;
   1653 	register struct fdunit *un;
   1654 
   1655 	fdc = fd_getctlr(dev);
   1656 	if (!fdc || !(un = fdc->c_un))
   1657 		return (ENXIO);
   1658 
   1659 
   1660 	unit = fdc->c_un->un_unit_no;
   1661 	FDERRPRINT(FDEP_L1, FDEM_CLOS, (C, "fd_close\n"));
   1662 	part = FDPARTITION(dev);
   1663 
   1664 	sema_p(&fdc->c_ocsem);
   1665 	mutex_enter(&fdc->c_lolock);
   1666 
   1667 	if (otyp == OTYP_LYR) {
   1668 		un->un_lyropen[part]--;
   1669 		part_is_closed = (un->un_lyropen[part] == 0);
   1670 	} else {
   1671 		un->un_regopen[otyp] &= ~(1<<part);
   1672 		part_is_closed = 1;
   1673 	}
   1674 	if (part_is_closed)
   1675 		un->un_exclmask &= ~(1<<part);
   1676 
   1677 	if (fd_unit_is_open(un) == 0) {
   1678 		/* deselect drive on last close */
   1679 		fdselect(fdc, unit, 0);
   1680 		un->un_flags &= ~FDUNIT_CHANGED;
   1681 	}
   1682 	mutex_exit(&fdc->c_lolock);
   1683 	sema_v(&fdc->c_ocsem);
   1684 
   1685 	return (0);
   1686 }
   1687 
   1688 /*
   1689  * fd_strategy
   1690  *	checks operation, hangs buf struct off fdctlr, calls fdstart
   1691  *	if not already busy.  Note that if we call start, then the operation
   1692  *	will already be done on return (start sleeps).
   1693  */
   1694 static int
   1695 fd_strategy(register struct buf *bp)
   1696 {
   1697 	struct fdctlr *fdc;
   1698 	struct fdunit *un;
   1699 	uint_t	phys_blkno;
   1700 	struct dk_map32 *dkm;
   1701 
   1702 	FDERRPRINT(FDEP_L1, FDEM_STRA,
   1703 	    (C, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
   1704 	    (void *)bp, bp->b_edev));
   1705 	FDERRPRINT(FDEP_L1, FDEM_STRA,
   1706 	    (C, "b_blkno=%x b_flags=%x b_count=%x\n",
   1707 	    (int)bp->b_blkno, bp->b_flags, (int)bp->b_bcount));
   1708 	fdc = fd_getctlr(bp->b_edev);
   1709 	un = fdc->c_un;
   1710 	dkm = &un->un_label.dkl_map[FDPARTITION(bp->b_edev)];
   1711 
   1712 	/*
   1713 	 * If it's medium density and the block no. isn't a multiple
   1714 	 * of 1K, then return an error.
   1715 	 */
   1716 	if (un->un_chars->fdc_medium) {
   1717 		phys_blkno = (uint_t)bp->b_blkno >> 1;
   1718 		if (bp->b_blkno & 1) {
   1719 			FDERRPRINT(FDEP_L3, FDEM_STRA,
   1720 			    (C, "b_blkno=0x%lx is not 1k aligned\n",
   1721 			    (long)bp->b_blkno));
   1722 			bp->b_error = EINVAL;
   1723 			bp->b_resid = bp->b_bcount;
   1724 			bp->b_flags |= B_ERROR;
   1725 			biodone(bp);
   1726 			return (0);
   1727 		}
   1728 	} else {
   1729 		phys_blkno = (uint_t)bp->b_blkno;
   1730 	}
   1731 
   1732 
   1733 	/* If the block number is past the end, return an error */
   1734 	if ((phys_blkno > dkm->dkl_nblk)) {
   1735 		FDERRPRINT(FDEP_L3, FDEM_STRA,
   1736 		    (C, "fd%d: block %ld is past the end! (nblk=%d)\n",
   1737 		    0, (long)bp->b_blkno, dkm->dkl_nblk));
   1738 		bp->b_error = ENOSPC;
   1739 		bp->b_resid = bp->b_bcount;
   1740 		bp->b_flags |= B_ERROR;
   1741 		biodone(bp);
   1742 		return (0);
   1743 	}
   1744 
   1745 	/* if at end of file, skip out now */
   1746 	if (phys_blkno == dkm->dkl_nblk) {
   1747 		FDERRPRINT(FDEP_L1, FDEM_STRA,
   1748 		    (C, "b_blkno is at the end!\n"));
   1749 
   1750 		if ((bp->b_flags & B_READ) == 0) {
   1751 			/* a write needs to get an error! */
   1752 			bp->b_error = ENOSPC;
   1753 			bp->b_flags |= B_ERROR;
   1754 
   1755 			FDERRPRINT(FDEP_L1, FDEM_STRA,
   1756 			    (C, "block is at end and this is a write\n"));
   1757 
   1758 		}
   1759 
   1760 		bp->b_resid = bp->b_bcount;
   1761 		biodone(bp);
   1762 		return (0);
   1763 	}
   1764 
   1765 	/* if operation not a multiple of sector size, is error! */
   1766 	if (bp->b_bcount % un->un_chars->fdc_sec_size)	{
   1767 		FDERRPRINT(FDEP_L3, FDEM_STRA,
   1768 		    (C, "fd%d: requested transfer size(0x%lx) is not"
   1769 		    " multiple of sector size(0x%x)\n", 0,
   1770 		    bp->b_bcount, un->un_chars->fdc_sec_size));
   1771 		FDERRPRINT(FDEP_L3, FDEM_STRA,
   1772 		    (C, "	b_blkno=0x%lx b_flags=0x%x\n",
   1773 		    (long)bp->b_blkno, bp->b_flags));
   1774 		bp->b_error = EINVAL;
   1775 		bp->b_resid = bp->b_bcount;
   1776 		bp->b_flags |= B_ERROR;
   1777 		biodone(bp);
   1778 		return (0);
   1779 
   1780 	}
   1781 
   1782 	/*
   1783 	 * Put the buf request in the controller's queue, FIFO.
   1784 	 */
   1785 	bp->av_forw = 0;
   1786 	sema_p(&fdc->c_ocsem);
   1787 
   1788 	(void) pm_busy_component(fdc->c_dip, 0);
   1789 
   1790 	mutex_enter(&fdc->c_lolock);
   1791 
   1792 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
   1793 
   1794 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
   1795 		mutex_exit(&fdc->c_lolock);
   1796 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
   1797 		    != DDI_SUCCESS) {
   1798 			sema_v(&fdc->c_ocsem);
   1799 			(void) pm_idle_component(fdc->c_dip, 0);
   1800 			bp->b_error = EIO;
   1801 			bp->b_resid = bp->b_bcount;
   1802 			bp->b_flags |= B_ERROR;
   1803 			biodone(bp);
   1804 			return (0);
   1805 		} else {
   1806 			mutex_enter(&fdc->c_lolock);
   1807 		}
   1808 	}
   1809 	if (un->un_iostat) {
   1810 		kstat_waitq_enter(KIOSP);
   1811 	}
   1812 	if (fdc->c_actf)
   1813 		fdc->c_actl->av_forw = bp;
   1814 	else
   1815 		fdc->c_actf = bp;
   1816 	fdc->c_actl = bp;
   1817 
   1818 
   1819 	/* call fdstart to start the transfer */
   1820 	fdstart(fdc);
   1821 
   1822 	mutex_exit(&fdc->c_lolock);
   1823 	sema_v(&fdc->c_ocsem);
   1824 	(void) pm_idle_component(fdc->c_dip, 0);
   1825 	return (0);
   1826 }
   1827 
   1828 /* ARGSUSED2 */
   1829 static int
   1830 fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
   1831 {
   1832 	FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_read\n"));
   1833 	return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
   1834 }
   1835 
   1836 /* ARGSUSED2 */
   1837 static int
   1838 fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
   1839 {
   1840 	FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_write\n"));
   1841 	return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
   1842 }
   1843 
   1844 static void
   1845 fdmotoff(void *arg)
   1846 {
   1847 	struct fdctlr *fdc = arg;
   1848 	int unit = fdc->c_un->un_unit_no;
   1849 
   1850 	mutex_enter(&fdc->c_lolock);
   1851 
   1852 	/* Just return if we're about to call untimeout */
   1853 	if (fdc->c_mtimeid == 0) {
   1854 		mutex_exit(&fdc->c_lolock);
   1855 		return;
   1856 	}
   1857 
   1858 	FDERRPRINT(FDEP_L1, FDEM_MOFF, (C, "fdmotoff\n"));
   1859 
   1860 	fdc->c_mtimeid = 0;
   1861 
   1862 	if (!(Msr(fdc) & CB) && (Dor(fdc) & (MOTEN(unit)))) {
   1863 		/* LINTED */
   1864 		Set_dor(fdc, MOTEN(unit), 0);
   1865 	}
   1866 
   1867 	mutex_exit(&fdc->c_lolock);
   1868 }
   1869 
   1870 /* ARGSUSED */
   1871 static int
   1872 fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
   1873 	cred_t *cred_p, int *rval_p)
   1874 {
   1875 	union {
   1876 		struct dk_cinfo dki;
   1877 		struct dk_geom dkg;
   1878 		struct dk_allmap32 dka;
   1879 		struct fd_char fdchar;
   1880 		struct fd_drive drvchar;
   1881 		int	temp;
   1882 	} cpy;
   1883 
   1884 	struct vtoc	vtoc;
   1885 	struct fdunit *un;
   1886 	struct fdctlr *fdc;
   1887 	int unit, dkunit;
   1888 	int err = 0;
   1889 	uint_t	sec_size;
   1890 	enum dkio_state state;
   1891 	int	transfer_rate;
   1892 
   1893 	FDERRPRINT(FDEP_L1, FDEM_IOCT,
   1894 	    (C, "fd_ioctl: cmd 0x%x, arg 0x%lx\n", cmd, (long)arg));
   1895 
   1896 	/* The minor number should always be 0 */
   1897 	if (FDUNIT(dev) != 0)
   1898 		return (ENXIO);
   1899 
   1900 	fdc = fd_getctlr(dev);
   1901 	unit = fdc->c_un->un_unit_no;
   1902 	un = fdc->c_un;
   1903 	sec_size = un->un_chars->fdc_sec_size;
   1904 	bzero(&cpy, sizeof (cpy));
   1905 
   1906 	switch (cmd) {
   1907 	case DKIOCINFO:
   1908 		cpy.dki.dki_addr = 0;
   1909 
   1910 		/*
   1911 		 * The meaning of the dki_slave and dki_unit fields
   1912 		 * is unclear.  The sparc floppy driver follows the same
   1913 		 * convention as sd.c in that the instance number is
   1914 		 * returned in the dki_cnum field.  The dki_slave field is
   1915 		 * ignored.
   1916 		 *
   1917 		 * The dki_cnum contains the controller instance
   1918 		 * and its value can be any positive number. Even
   1919 		 * though currently Sparc platforms only support
   1920 		 * one controller, the controller instance number
   1921 		 * can be any number since it is assigned by the
   1922 		 * system depending on the device properties.
   1923 		 */
   1924 
   1925 		cpy.dki.dki_cnum = FDCTLR(dev);
   1926 
   1927 		/*
   1928 		 * Sparc platforms support only one floppy drive.
   1929 		 * The device node for the controller is the same as
   1930 		 * the device node for the drive.  The x86 driver is
   1931 		 * different in that it has a node for the controller
   1932 		 * and a child node for each drive. Since Sparc supports
   1933 		 * only one drive, the unit number will always be zero.
   1934 		 */
   1935 
   1936 		cpy.dki.dki_unit = FDUNIT(dev);
   1937 
   1938 		/*
   1939 		 * The meaning of the dki_slave field is unclear.
   1940 		 * So, I will leave it set to 0.
   1941 		 */
   1942 
   1943 		cpy.dki.dki_slave = 0;
   1944 
   1945 		cpy.dki.dki_ctype = (ushort_t)-1;
   1946 		if (fdc->c_fdtype & FDCTYPE_82077)
   1947 			cpy.dki.dki_ctype = DKC_INTEL82077;
   1948 		cpy.dki.dki_flags = DKI_FMTTRK;
   1949 		cpy.dki.dki_partition = FDPARTITION(dev);
   1950 		cpy.dki.dki_maxtransfer = maxphys / DEV_BSIZE;
   1951 		if (ddi_copyout((caddr_t)&cpy.dki, (caddr_t)arg,
   1952 		    sizeof (cpy.dki), flag))
   1953 			err = EFAULT;
   1954 		break;
   1955 	case DKIOCGGEOM:
   1956 		cpy.dkg.dkg_ncyl = un->un_chars->fdc_ncyl;
   1957 		cpy.dkg.dkg_nhead = un->un_chars->fdc_nhead;
   1958 		cpy.dkg.dkg_nsect = un->un_chars->fdc_secptrack;
   1959 		cpy.dkg.dkg_intrlv = un->un_label.dkl_intrlv;
   1960 		cpy.dkg.dkg_rpm = un->un_label.dkl_rpm;
   1961 		cpy.dkg.dkg_pcyl = un->un_chars->fdc_ncyl;
   1962 		cpy.dkg.dkg_read_reinstruct =
   1963 		    (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
   1964 		cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
   1965 		if (ddi_copyout((caddr_t)&cpy.dkg, (caddr_t)arg,
   1966 		    sizeof (cpy.dkg), flag))
   1967 			err = EFAULT;
   1968 		break;
   1969 	case DKIOCSGEOM:
   1970 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
   1971 		    (C, "fd_ioctl: DKIOCSGEOM not supported\n"));
   1972 		err = ENOTTY;
   1973 		break;
   1974 
   1975 	/*
   1976 	 * return the map of all logical partitions
   1977 	 */
   1978 	case DKIOCGAPART:
   1979 		/*
   1980 		 * We don't have anything to do if the application is ILP32
   1981 		 * because the label map has a 32-bit format. Otherwise
   1982 		 * convert.
   1983 		 */
   1984 		if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
   1985 			if (ddi_copyout(&un->un_label.dkl_map,
   1986 			    (void *)arg, sizeof (struct dk_allmap32), flag))
   1987 				err = EFAULT;
   1988 		}
   1989 #ifdef _MULTI_DATAMODEL
   1990 		else {
   1991 			struct dk_allmap dk_allmap;
   1992 
   1993 			ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
   1994 			for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
   1995 				dk_allmap.dka_map[dkunit].dkl_cylno =
   1996 				    un->un_label.dkl_map[dkunit].dkl_cylno;
   1997 				dk_allmap.dka_map[dkunit].dkl_nblk =
   1998 				    un->un_label.dkl_map[dkunit].dkl_nblk;
   1999 			}
   2000 			if (ddi_copyout(&dk_allmap, (void *)arg,
   2001 			    sizeof (struct dk_allmap), flag))
   2002 				err = EFAULT;
   2003 		}
   2004 #endif /* _MULTI_DATAMODEL */
   2005 		break;
   2006 
   2007 	/*
   2008 	 * Set the map of all logical partitions
   2009 	 */
   2010 	case DKIOCSAPART:
   2011 		if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
   2012 			if (ddi_copyin((const void *)arg, &cpy.dka,
   2013 			    sizeof (cpy.dka), flag))
   2014 				return (EFAULT);
   2015 			else {
   2016 				mutex_enter(&fdc->c_lolock);
   2017 				for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
   2018 					un->un_label.dkl_map[dkunit] =
   2019 					    cpy.dka.dka_map[dkunit];
   2020 				}
   2021 				mutex_exit(&fdc->c_lolock);
   2022 			}
   2023 		}
   2024 #ifdef _MULTI_DATAMODEL
   2025 		else {
   2026 			struct dk_allmap dk_allmap;
   2027 
   2028 			ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
   2029 			if (ddi_copyin((const void *)arg, &dk_allmap,
   2030 			    sizeof (dk_allmap), flag))
   2031 				return (EFAULT);
   2032 			else {
   2033 				mutex_enter(&fdc->c_lolock);
   2034 				for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
   2035 					un->un_label.dkl_map[dkunit].dkl_cylno =
   2036 					    dk_allmap.dka_map[dkunit].dkl_cylno;
   2037 					un->un_label.dkl_map[dkunit].dkl_nblk =
   2038 					    dk_allmap.dka_map[dkunit].dkl_nblk;
   2039 				}
   2040 				mutex_exit(&fdc->c_lolock);
   2041 			}
   2042 		}
   2043 #endif /* _MULTI_DATAMODEL */
   2044 		break;
   2045 
   2046 	case DKIOCGVTOC:
   2047 		mutex_enter(&fdc->c_lolock);
   2048 
   2049 		/*
   2050 		 * Exit if the diskette has no label.
   2051 		 * Also, get the label to make sure the
   2052 		 * correct one is being used since the diskette
   2053 		 * may have changed
   2054 		 */
   2055 		if (fdgetlabel(fdc, unit)) {
   2056 			mutex_exit(&fdc->c_lolock);
   2057 			err = EINVAL;
   2058 			break;
   2059 		}
   2060 
   2061 		/* Build a vtoc from the diskette's label */
   2062 		fd_build_user_vtoc(un, &vtoc);
   2063 		mutex_exit(&fdc->c_lolock);
   2064 
   2065 #ifdef _MULTI_DATAMODEL
   2066 		switch (ddi_model_convert_from(flag & FMODELS)) {
   2067 		case DDI_MODEL_ILP32: {
   2068 			struct vtoc32 vtoc32;
   2069 
   2070 			vtoctovtoc32(vtoc, vtoc32);
   2071 			if (ddi_copyout(&vtoc32, (void *)arg,
   2072 			    sizeof (struct vtoc32), flag))
   2073 				return (EFAULT);
   2074 			break;
   2075 		}
   2076 
   2077 		case DDI_MODEL_NONE:
   2078 			if (ddi_copyout(&vtoc, (void *)arg,
   2079 			    sizeof (vtoc), flag))
   2080 				return (EFAULT);
   2081 			break;
   2082 		}
   2083 #else /* ! _MULTI_DATAMODEL */
   2084 		if (ddi_copyout(&vtoc, (void *)arg, sizeof (vtoc), flag))
   2085 			return (EFAULT);
   2086 #endif /* _MULTI_DATAMODEL */
   2087 		break;
   2088 
   2089 	case DKIOCSVTOC:
   2090 
   2091 #ifdef _MULTI_DATAMODEL
   2092 		switch (ddi_model_convert_from(flag & FMODELS)) {
   2093 		case DDI_MODEL_ILP32: {
   2094 			struct vtoc32 vtoc32;
   2095 
   2096 			if (ddi_copyin((const void *)arg, &vtoc32,
   2097 			    sizeof (struct vtoc32), flag)) {
   2098 				return (EFAULT);
   2099 			}
   2100 			vtoc32tovtoc(vtoc32, vtoc);
   2101 			break;
   2102 		}
   2103 
   2104 		case DDI_MODEL_NONE:
   2105 			if (ddi_copyin((const void *)arg, &vtoc,
   2106 			    sizeof (vtoc), flag)) {
   2107 				return (EFAULT);
   2108 			}
   2109 			break;
   2110 		}
   2111 #else /* ! _MULTI_DATAMODEL */
   2112 		if (ddi_copyin((const void *)arg, &vtoc, sizeof (vtoc), flag))
   2113 			return (EFAULT);
   2114 #endif /* _MULTI_DATAMODEL */
   2115 
   2116 		mutex_enter(&fdc->c_lolock);
   2117 
   2118 		/*
   2119 		 * The characteristics structure must be filled in because
   2120 		 * it helps build the vtoc.
   2121 		 */
   2122 		if ((un->un_chars->fdc_ncyl == 0) ||
   2123 		    (un->un_chars->fdc_nhead == 0) ||
   2124 		    (un->un_chars->fdc_secptrack == 0)) {
   2125 			mutex_exit(&fdc->c_lolock);
   2126 			err = EINVAL;
   2127 			break;
   2128 		}
   2129 
   2130 		if ((err = fd_build_label_vtoc(un, &vtoc)) != 0) {
   2131 			mutex_exit(&fdc->c_lolock);
   2132 			break;
   2133 		}
   2134 
   2135 		(void) pm_busy_component(fdc->c_dip, 0);
   2136 
   2137 		err = fdrw(fdc, unit, FDWRITE, 0, 0, 1,
   2138 		    (caddr_t)&un->un_label, sizeof (struct dk_label));
   2139 		mutex_exit(&fdc->c_lolock);
   2140 		(void) pm_idle_component(fdc->c_dip, 0);
   2141 		break;
   2142 
   2143 	case DKIOCSTATE:
   2144 		if (ddi_copyin((caddr_t)arg, (caddr_t)&state,
   2145 		    sizeof (int), flag)) {
   2146 			err = EFAULT;
   2147 			break;
   2148 		}
   2149 		(void) pm_busy_component(fdc->c_dip, 0);
   2150 
   2151 		err = fd_check_media(dev, state);
   2152 		(void) pm_idle_component(fdc->c_dip, 0);
   2153 
   2154 		if (ddi_copyout((caddr_t)&un->un_media_state,
   2155 		    (caddr_t)arg, sizeof (int), flag))
   2156 			err = EFAULT;
   2157 		break;
   2158 
   2159 	case FDIOGCHAR:
   2160 		if (ddi_copyout((caddr_t)un->un_chars, (caddr_t)arg,
   2161 		    sizeof (struct fd_char), flag))
   2162 			err = EFAULT;
   2163 		break;
   2164 
   2165 	case FDIOSCHAR:
   2166 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.fdchar,
   2167 				sizeof (struct fd_char), flag)) {
   2168 			err = EFAULT;
   2169 			break;
   2170 		}
   2171 
   2172 		/*
   2173 		 * Check the fields in the fdchar structure that are either
   2174 		 * driver or controller dependent.
   2175 		 */
   2176 
   2177 		transfer_rate = cpy.fdchar.fdc_transfer_rate;
   2178 		if ((transfer_rate != 500) && (transfer_rate != 300) &&
   2179 		    (transfer_rate != 250) && (transfer_rate != 1000)) {
   2180 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
   2181 			    (C, "fd_ioctl: FDIOSCHAR odd transfer rate %d\n",
   2182 			    cpy.fdchar.fdc_transfer_rate));
   2183 			err = EINVAL;
   2184 			break;
   2185 		}
   2186 
   2187 		if ((cpy.fdchar.fdc_nhead < 1) ||
   2188 		    (cpy.fdchar.fdc_nhead > 2)) {
   2189 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
   2190 			    (C, "fd_ioctl: FDIOSCHAR bad no. of heads %d\n",
   2191 			    cpy.fdchar.fdc_nhead));
   2192 			err = EINVAL;
   2193 			break;
   2194 		}
   2195 
   2196 		/*
   2197 		 * The number of cylinders must be between 0 and 255
   2198 		 */
   2199 		if ((cpy.fdchar.fdc_ncyl < 0) || (cpy.fdchar.fdc_ncyl > 255)) {
   2200 			FDERRPRINT(FDEP_L3, FDEM_IOCT,
   2201 			    (C, "fd_ioctl: FDIOSCHAR bad cyl no %d\n",
   2202 			    cpy.fdchar.fdc_ncyl));
   2203 			err = EINVAL;
   2204 			break;
   2205 		}
   2206 
   2207 		/* Copy the fdchar structure */
   2208 
   2209 		mutex_enter(&fdc->c_lolock);
   2210 		*(un->un_chars) = cpy.fdchar;
   2211 
   2212 		un->un_curfdtype = -1;
   2213 
   2214 		mutex_exit(&fdc->c_lolock);
   2215 
   2216 		break;
   2217 	case FDEJECT:  /* eject disk */
   2218 	case DKIOCEJECT:
   2219 
   2220 		/*
   2221 		 * Fail the ioctl if auto-eject isn't supported
   2222 		 */
   2223 		if (fdc->c_un->un_drive->fdd_ejectable == 0) {
   2224 
   2225 			err = ENOSYS;
   2226 
   2227 		} else {
   2228 			(void) pm_busy_component(fdc->c_dip, 0);
   2229 
   2230 			mutex_enter(&fdc->c_lolock);
   2231 
   2232 			CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
   2233 
   2234 			if (fdc->c_un->un_state == FD_STATE_STOPPED) {
   2235 				mutex_exit(&fdc->c_lolock);
   2236 				if ((pm_raise_power(fdc->c_dip, 0,
   2237 				    PM_LEVEL_ON)) != DDI_SUCCESS) {
   2238 					(void) pm_idle_component(fdc->c_dip, 0);
   2239 					err = EIO;
   2240 				}
   2241 				mutex_enter(&fdc->c_lolock);
   2242 			}
   2243 		}
   2244 		if (err == 0) {
   2245 			fdselect(fdc, unit, 1);
   2246 			fdeject(fdc, unit);
   2247 			mutex_exit(&fdc->c_lolock);
   2248 		}
   2249 
   2250 		(void) pm_idle_component(fdc->c_dip, 0);
   2251 
   2252 		/*
   2253 		 * Make sure the drive is turned off
   2254 		 */
   2255 		if (fdc->c_fdtype & FDCTYPE_82077) {
   2256 			if (fdc->c_mtimeid == 0) {
   2257 				fdc->c_mtimeid = timeout(fdmotoff, fdc,
   2258 				    Motoff_delay);
   2259 			}
   2260 		}
   2261 
   2262 		break;
   2263 	case FDGETCHANGE: /* disk changed */
   2264 
   2265 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.temp,
   2266 		    sizeof (int), flag)) {
   2267 			err = EFAULT;
   2268 			break;
   2269 		}
   2270 
   2271 		/* zero out the user's parameter */
   2272 		cpy.temp = 0;
   2273 
   2274 		(void) pm_busy_component(fdc->c_dip, 0);
   2275 
   2276 		mutex_enter(&fdc->c_lolock);
   2277 
   2278 		CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
   2279 
   2280 		if (fdc->c_un->un_state == FD_STATE_STOPPED) {
   2281 			mutex_exit(&fdc->c_lolock);
   2282 			if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
   2283 			    != DDI_SUCCESS) {
   2284 				FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
   2285 				    change failed. \n"));
   2286 				(void) pm_idle_component(fdc->c_dip, 0);
   2287 				return (EIO);
   2288 			}
   2289 
   2290 			mutex_enter(&fdc->c_lolock);
   2291 		}
   2292 		if (un->un_flags & FDUNIT_CHANGED)
   2293 			cpy.temp |= FDGC_HISTORY;
   2294 		else
   2295 			cpy.temp &= ~FDGC_HISTORY;
   2296 		un->un_flags &= ~FDUNIT_CHANGED;
   2297 
   2298 		if (fd_pollable) {
   2299 			/*
   2300 			 * If it's a "pollable" floppy, then we don't
   2301 			 * have to do all the fdcheckdisk nastyness to
   2302 			 * figure out if the thing is still there.
   2303 			 */
   2304 			if (fdsense_chng(fdc, unit)) {
   2305 				cpy.temp |= FDGC_CURRENT;
   2306 			} else {
   2307 				cpy.temp &= ~FDGC_CURRENT;
   2308 			}
   2309 		} else {
   2310 
   2311 			if (fdsense_chng(fdc, unit)) {
   2312 				/*
   2313 				 * check disk change signal is asserted.
   2314 				 * Now find out if the floppy is
   2315 				 * inserted
   2316 				 */
   2317 				if (fdcheckdisk(fdc, unit)) {
   2318 					cpy.temp |= FDGC_CURRENT;
   2319 				} else {
   2320 					/*
   2321 					 * Yes, the floppy was
   2322 					 * reinserted. Implies
   2323 					 * floppy change.
   2324 					 */
   2325 					cpy.temp &= ~FDGC_CURRENT;
   2326 					cpy.temp |= FDGC_HISTORY;
   2327 				}
   2328 			} else {
   2329 				cpy.temp &= ~FDGC_CURRENT;
   2330 			}
   2331 		}
   2332 
   2333 		/*
   2334 		 * For a pollable floppy, the floppy_change signal
   2335 		 * reflects whether the floppy is in there or not.
   2336 		 * We can not detect a floppy change if we don't poll
   2337 		 * this signal when the floppy is being changed.
   2338 		 * Because as soon as the floppy is put back, the
   2339 		 * signal is reset.
   2340 		 * BUT the pollable floppies are available only on
   2341 		 * Sparcstation Voyager Voyagers (Gypsy) only and
   2342 		 * those are motorized floppies. For motorized floppies,
   2343 		 * the floppy can only (assuming the user doesn't use a
   2344 		 * pin to take out the floppy) be taken out by
   2345 		 * issuing 'eject' command which sets the
   2346 		 * un->un_ejected flag. So, if the following
   2347 		 * condition is true, we can assume there
   2348 		 * was a floppy change.
   2349 		 */
   2350 		if (un->un_ejected && !(cpy.temp & FDGC_CURRENT)) {
   2351 			cpy.temp |= FDGC_HISTORY;
   2352 		}
   2353 		un->un_ejected = 0;
   2354 
   2355 
   2356 		/* return the write-protection status */
   2357 		fdgetcsb(fdc);
   2358 		if (fdsensedrv(fdc, unit) & WP_SR3) {
   2359 			cpy.temp |= FDGC_CURWPROT;
   2360 		}
   2361 		fdretcsb(fdc);
   2362 		mutex_exit(&fdc->c_lolock);
   2363 
   2364 		if (ddi_copyout((caddr_t)&cpy.temp, (caddr_t)arg,
   2365 		    sizeof (int), flag))
   2366 			err = EFAULT;
   2367 		(void) pm_idle_component(fdc->c_dip, 0);
   2368 		break;
   2369 
   2370 	case FDGETDRIVECHAR:
   2371 
   2372 		if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.drvchar,
   2373 				sizeof (struct fd_drive), flag)) {
   2374 			err = EFAULT;
   2375 			break;
   2376 		}
   2377 
   2378 		/*
   2379 		 * Return the ejectable value based on the FD_MANUAL_EJECT
   2380 		 * property
   2381 		 */
   2382 		cpy.drvchar.fdd_ejectable = fdc->c_un->un_drive->fdd_ejectable;
   2383 		cpy.drvchar.fdd_maxsearch = nfdtypes; /* 3 - hi m lo density */
   2384 		if (fd_pollable)	/* pollable device */
   2385 			cpy.drvchar.fdd_flags |= FDD_POLLABLE;
   2386 
   2387 		/* the rest of the fd_drive struct is meaningless to us */
   2388 
   2389 		if (ddi_copyout((caddr_t)&cpy.drvchar, (caddr_t)arg,
   2390 		    sizeof (struct fd_drive), flag))
   2391 			err = EFAULT;
   2392 		break;
   2393 
   2394 	case FDSETDRIVECHAR:
   2395 		FDERRPRINT(FDEP_L3, FDEM_IOCT,
   2396 		    (C, "fd_ioctl: FDSETDRIVECHAR not supportedn\n"));
   2397 		err = ENOTTY;
   2398 		break;
   2399 
   2400 	case DKIOCREMOVABLE: {
   2401 		int	i = 1;
   2402 
   2403 		/* no brainer: floppies are always removable */
   2404 		if (ddi_copyout((caddr_t)&i, (caddr_t)arg, sizeof (int),
   2405 		    flag)) {
   2406 			err = EFAULT;
   2407 		}
   2408 		break;
   2409 	}
   2410 	case DKIOCGMEDIAINFO:
   2411 		err = fd_get_media_info(un, (caddr_t)arg, flag);
   2412 		break;
   2413 
   2414 
   2415 	case FDIOCMD:
   2416 	{
   2417 		struct fd_cmd fc;
   2418 		int cyl, hd, spc, spt;
   2419 		int nblks; /* total no. of blocks */
   2420 
   2421 #ifdef _MULTI_DATAMODEL
   2422 		switch (ddi_model_convert_from(flag & FMODELS)) {
   2423 		case DDI_MODEL_ILP32: {
   2424 			struct fd_cmd32 fc32;
   2425 
   2426 			if (ddi_copyin((const void *)arg, &fc32,
   2427 			    sizeof (fc32), flag)) {
   2428 				return (EFAULT);
   2429 			}
   2430 			fc.fdc_cmd	= fc32.fdc_cmd;
   2431 			fc.fdc_flags	= fc32.fdc_flags;
   2432 			fc.fdc_blkno	= (daddr_t)fc32.fdc_blkno;
   2433 			fc.fdc_secnt	= fc32.fdc_secnt;
   2434 			fc.fdc_bufaddr	= (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
   2435 			fc.fdc_buflen	= fc32.fdc_buflen;
   2436 			fc.fdc_cmd	= fc32.fdc_cmd;
   2437 
   2438 			break;
   2439 		}
   2440 
   2441 		case DDI_MODEL_NONE:
   2442 			if (ddi_copyin((const void *)arg, &fc,
   2443 			    sizeof (fc), flag)) {
   2444 				return (EFAULT);
   2445 			}
   2446 			break;
   2447 		}
   2448 #else /* ! _MULTI_DATAMODEL */
   2449 		if (ddi_copyin((const void *)arg, &fc, sizeof (fc), flag)) {
   2450 			return (EFAULT);
   2451 		}
   2452 #endif /* _MULTI_DATAMODEL */
   2453 
   2454 		if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
   2455 			auto struct iovec aiov;
   2456 			auto struct uio auio;
   2457 			struct uio *uio = &auio;
   2458 
   2459 			spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
   2460 
   2461 			bzero(&auio, sizeof (struct uio));
   2462 			bzero(&aiov, sizeof (struct iovec));
   2463 			aiov.iov_base = fc.fdc_bufaddr;
   2464 			aiov.iov_len = (uint_t)fc.fdc_secnt * sec_size;
   2465 			uio->uio_iov = &aiov;
   2466 
   2467 			uio->uio_iovcnt = 1;
   2468 			uio->uio_resid = aiov.iov_len;
   2469 			uio->uio_segflg = UIO_USERSPACE;
   2470 			FDERRPRINT(FDEP_L2, FDEM_IOCT,
   2471 			    (C, "fd_ioctl: call physio\n"));
   2472 			err = physio(fd_strategy, NULL, dev,
   2473 			    spc, minphys, uio);
   2474 			break;
   2475 		} else if (fc.fdc_cmd != FDCMD_FORMAT_TRACK) {
   2476 
   2477 			/*
   2478 			 * The manpage states that only the FDCMD_WRITE,
   2479 			 * FDCMD_READ, and the FDCMD_FORMAT_TR are available.
   2480 			 */
   2481 			FDERRPRINT(FDEP_L1, FDEM_IOCT,
   2482 			    (C, "fd_ioctl: FDIOCMD invalid command\n"));
   2483 			err = EINVAL;
   2484 			break;
   2485 		}
   2486 
   2487 		/* The command is FDCMD_FORMAT_TRACK */
   2488 
   2489 		spt = un->un_chars->fdc_secptrack;	/* sec/trk */
   2490 		spc = un->un_chars->fdc_nhead * spt;	/* sec/cyl */
   2491 		cyl = fc.fdc_blkno / spc;
   2492 		hd = (fc.fdc_blkno % spc) / spt;
   2493 
   2494 		/*
   2495 		 * Make sure the specified block number is in the correct
   2496 		 * range. (block numbers start at 0)
   2497 		 */
   2498 		nblks = spc * un->un_chars->fdc_ncyl;
   2499 
   2500 		if (fc.fdc_blkno < 0 || fc.fdc_blkno > (nblks - 1)) {
   2501 			err = EINVAL;
   2502 			break;
   2503 		}
   2504 
   2505 		(void) pm_busy_component(fdc->c_dip, 0);
   2506 
   2507 		mutex_enter(&fdc->c_lolock);
   2508 		CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
   2509 		if (fdc->c_un->un_state == FD_STATE_STOPPED) {
   2510 			mutex_exit(&fdc->c_lolock);
   2511 			if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
   2512 			    != DDI_SUCCESS) {
   2513 				FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
   2514 				    change failed. \n"));
   2515 				(void) pm_idle_component(fdc->c_dip, 0);
   2516 				return (EIO);
   2517 			}
   2518 
   2519 			mutex_enter(&fdc->c_lolock);
   2520 		}
   2521 
   2522 		if (fdformat(fdc, unit, cyl, hd))
   2523 			err = EIO;
   2524 
   2525 		mutex_exit(&fdc->c_lolock);
   2526 		(void) pm_idle_component(fdc->c_dip, 0);
   2527 
   2528 		break;
   2529 	}
   2530 
   2531 	case FDRAW:
   2532 
   2533 		(void) pm_busy_component(fdc->c_dip, 0);
   2534 		err = fdrawioctl(fdc, unit, arg, flag);
   2535 
   2536 		(void) pm_idle_component(fdc->c_dip, 0);
   2537 
   2538 		break;
   2539 #ifdef FD_DEBUG
   2540 	case IOCTL_DEBUG:
   2541 		fderrlevel--;
   2542 		if (fderrlevel < 0)
   2543 			fderrlevel = 3;
   2544 		cmn_err(C, "fdioctl: CHANGING debug to %d", fderrlevel);
   2545 		return (0);
   2546 #endif /* FD_DEBUG */
   2547 	default:
   2548 		FDERRPRINT(FDEP_L2, FDEM_IOCT,
   2549 		    (C, "fd_ioctl: invalid ioctl 0x%x\n", cmd));
   2550 		err = ENOTTY;
   2551 		break;
   2552 	}
   2553 
   2554 	return (err);
   2555 }
   2556 
   2557 /*
   2558  * fdrawioctl
   2559  *
   2560  * 	- acquires the low level lock
   2561  */
   2562 
   2563 static int
   2564 fdrawioctl(struct fdctlr *fdc, int unit, intptr_t arg, int mode)
   2565 {
   2566 	struct fd_raw fdr;
   2567 #ifdef _MULTI_DATAMODEL
   2568 	struct fd_raw32 fdr32;
   2569 #endif
   2570 	struct fdcsb *csb;
   2571 	int i, err, flag;
   2572 	caddr_t fa;
   2573 	uint_t	fc;
   2574 	size_t	real_length;
   2575 	int	res;
   2576 	ddi_device_acc_attr_t attr;
   2577 	ddi_acc_handle_t	mem_handle;
   2578 
   2579 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
   2580 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
   2581 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
   2582 
   2583 	ASSERT(fdc->c_un->un_unit_no == unit);
   2584 
   2585 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2586 	    (C, "fdrawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
   2587 
   2588 	flag = B_READ;
   2589 	err = 0;
   2590 	fa = NULL;
   2591 	fc = (uint_t)0;
   2592 
   2593 	/* Copy in the arguments */
   2594 	switch (ddi_model_convert_from(mode)) {
   2595 #ifdef _MULTI_DATAMODEL
   2596 	case DDI_MODEL_ILP32:
   2597 		if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr32,
   2598 		    sizeof (fdr32), mode)) {
   2599 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2600 			    (C, "fdrawioctl: copyin error, args32\n"));
   2601 			return (EFAULT);
   2602 		}
   2603 		bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
   2604 		fdr.fdr_cnum = fdr32.fdr_cnum;
   2605 		bcopy(fdr32.fdr_result, fdr.fdr_result,
   2606 		    sizeof (fdr.fdr_result));
   2607 		fdr.fdr_nbytes = fdr32.fdr_nbytes;
   2608 		fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
   2609 		break;
   2610 #endif
   2611 	default:
   2612 	case DDI_MODEL_NONE:
   2613 		if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr,
   2614 		    sizeof (fdr), mode)) {
   2615 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2616 			    (C, "fdrawioctl: copyin error, args\n"));
   2617 			return (EFAULT);
   2618 		}
   2619 		break;
   2620 	}
   2621 
   2622 	mutex_enter(&fdc->c_lolock);
   2623 
   2624 	CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
   2625 
   2626 	if (fdc->c_un->un_state == FD_STATE_STOPPED) {
   2627 		mutex_exit(&fdc->c_lolock);
   2628 		if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
   2629 		    != DDI_SUCCESS) {
   2630 			FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
   2631 			    failed. \n"));
   2632 
   2633 			(void) pm_idle_component(fdc->c_dip, 0);
   2634 			return (EIO);
   2635 		}
   2636 		mutex_enter(&fdc->c_lolock);
   2637 	}
   2638 
   2639 	fdgetcsb(fdc);
   2640 	csb = &fdc->c_csb;
   2641 	csb->csb_unit = (uchar_t)unit;
   2642 
   2643 	/* copy cmd bytes into csb */
   2644 	for (i = 0; i <= fdr.fdr_cnum; i++)
   2645 		csb->csb_cmds[i] = fdr.fdr_cmd[i];
   2646 	csb->csb_ncmds = (uchar_t)fdr.fdr_cnum;
   2647 
   2648 	csb->csb_maxretry = 0;	/* let the application deal with errors */
   2649 	csb->csb_retrys = 0;
   2650 
   2651 	switch (fdr.fdr_cmd[0] & 0x0f) {
   2652 
   2653 	case FDRAW_SPECIFY:
   2654 		/*
   2655 		 * Ensure that the right DMA mode is selected.  There is
   2656 		 * currently no way for the user to tell if DMA is
   2657 		 * happening so set the value for the user.
   2658 		 */
   2659 
   2660 		if (fdc->c_fdtype & FDCTYPE_DMA)
   2661 			csb->csb_cmds[2] = csb->csb_cmds[2] & 0xFE;
   2662 		else
   2663 			csb->csb_cmds[2] = csb->csb_cmds[2] | 0x1;
   2664 
   2665 		csb->csb_opflags = CSB_OFNORESULTS;
   2666 		csb->csb_nrslts = 0;
   2667 		break;
   2668 
   2669 	case FDRAW_SENSE_DRV:
   2670 		/* Insert the appropriate drive number */
   2671 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
   2672 		csb->csb_opflags = CSB_OFIMMEDIATE;
   2673 		csb->csb_nrslts = 1;
   2674 		break;
   2675 
   2676 	case FDRAW_REZERO:
   2677 	case FDRAW_SEEK:
   2678 		/* Insert the appropriate drive number */
   2679 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
   2680 		csb->csb_opflags = CSB_OFSEEKOPS + CSB_OFTIMEIT;
   2681 		csb->csb_nrslts = 2;
   2682 		break;
   2683 
   2684 	case FDRAW_FORMAT:
   2685 		FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2686 		    (C, "fdrawioctl: cmd is fdfraw format\n"));
   2687 
   2688 		/* Insert the appropriate drive number */
   2689 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
   2690 		csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
   2691 		csb->csb_nrslts = NRBRW;
   2692 		flag = B_WRITE;
   2693 
   2694 		/*
   2695 		 * Allocate memory for the command.
   2696 		 * If PIO is being used, then add an extra 16 bytes
   2697 		 */
   2698 		if (fdc->c_fdtype & FDCTYPE_DMA) {
   2699 
   2700 			fc = (uint_t)(fdr.fdr_nbytes);
   2701 			mutex_enter(&fdc->c_hilock);
   2702 
   2703 			res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
   2704 			    &attr, DDI_DMA_STREAMING,
   2705 			    DDI_DMA_DONTWAIT, 0, &fa, &real_length,
   2706 			    &mem_handle);
   2707 
   2708 			if (res != DDI_SUCCESS) {
   2709 				fdretcsb(fdc);
   2710 				mutex_exit(&fdc->c_lolock);
   2711 				mutex_exit(&fdc->c_hilock);
   2712 				return (EIO);
   2713 			}
   2714 
   2715 			fdc->c_csb.csb_read = CSB_WRITE;
   2716 			if (fdstart_dma(fdc, fa, fc) != 0) {
   2717 				ddi_dma_mem_free(&mem_handle);
   2718 				fdretcsb(fdc);
   2719 				mutex_exit(&fdc->c_lolock);
   2720 				mutex_exit(&fdc->c_hilock);
   2721 				return (EIO);
   2722 			}
   2723 			mutex_exit(&fdc->c_hilock);
   2724 
   2725 		} else {
   2726 			fc = (uint_t)(fdr.fdr_nbytes + 16);
   2727 			fa = kmem_zalloc(fc, KM_SLEEP);
   2728 		}
   2729 
   2730 		/* copy in the user's command bytes */
   2731 		if (ddi_copyin(fdr.fdr_addr, fa,
   2732 		    (uint_t)fdr.fdr_nbytes, mode)) {
   2733 			fdretcsb(fdc);
   2734 			mutex_exit(&fdc->c_lolock);
   2735 
   2736 			if (fdc->c_fdtype & FDCTYPE_DMA) {
   2737 				ddi_dma_mem_free(&mem_handle);
   2738 				FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2739 				    (C, "fdrawioctl: (err)free dma memory\n"));
   2740 			} else {
   2741 				kmem_free(fa, fc);
   2742 			}
   2743 
   2744 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2745 			    (C, "fdrawioctl: ddi_copyin error\n"));
   2746 			return (EFAULT);
   2747 		}
   2748 
   2749 		break;
   2750 	case FDRAW_WRCMD:
   2751 	case FDRAW_WRITEDEL:
   2752 		flag = B_WRITE;
   2753 		/* FALLTHROUGH */
   2754 	case FDRAW_RDCMD:
   2755 	case FDRAW_READDEL:
   2756 	case FDRAW_READTRACK:
   2757 		/* Insert the appropriate drive number */
   2758 		csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
   2759 		if (fdc->c_fdtype & FDCTYPE_SB)
   2760 			csb->csb_cmds[1] |= IPS;
   2761 		csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
   2762 		csb->csb_nrslts = NRBRW;
   2763 		break;
   2764 
   2765 	default:
   2766 		fdretcsb(fdc);
   2767 		mutex_exit(&fdc->c_lolock);
   2768 		return (EINVAL);
   2769 	}
   2770 
   2771 	if ((csb->csb_opflags & CSB_OFXFEROPS) && (fdr.fdr_nbytes == 0)) {
   2772 		fdretcsb(fdc);
   2773 		mutex_exit(&fdc->c_lolock);
   2774 		return (EINVAL);
   2775 	}
   2776 	csb->csb_opflags |= CSB_OFRAWIOCTL;
   2777 
   2778 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2779 	    (C, "fdrawioctl: nbytes = %u\n", fdr.fdr_nbytes));
   2780 
   2781 	if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT) {
   2782 		if ((fc = (uint_t)fdr.fdr_nbytes) > 0) {
   2783 			/*
   2784 			 * In SunOS 4.X, we used to as_fault things in.
   2785 			 * We really cannot do this in 5.0/SVr4. Unless
   2786 			 * someone really believes that speed is of the
   2787 			 * essence here, it is just much simpler to do
   2788 			 * this in kernel space and use copyin/copyout.
   2789 			 */
   2790 			if (fdc->c_fdtype & FDCTYPE_DMA) {
   2791 				mutex_enter(&fdc->c_hilock);
   2792 				res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
   2793 				    &attr, DDI_DMA_STREAMING,
   2794 				    DDI_DMA_DONTWAIT, 0, &fa, &real_length,
   2795 				    &mem_handle);
   2796 
   2797 				if (res != DDI_SUCCESS) {
   2798 					fdretcsb(fdc);
   2799 					mutex_exit(&fdc->c_lolock);
   2800 					mutex_exit(&fdc->c_hilock);
   2801 					return (EIO);
   2802 				}
   2803 
   2804 				if (flag == B_WRITE)
   2805 					fdc->c_csb.csb_read = CSB_WRITE;
   2806 				else
   2807 					fdc->c_csb.csb_read = CSB_READ;
   2808 
   2809 				if (fdstart_dma(fdc, fa, fc) != 0) {
   2810 					ddi_dma_mem_free(&mem_handle);
   2811 					fdretcsb(fdc);
   2812 					mutex_exit(&fdc->c_lolock);
   2813 					mutex_exit(&fdc->c_hilock);
   2814 					return (EIO);
   2815 				}
   2816 				mutex_exit(&fdc->c_hilock);
   2817 
   2818 			} else {
   2819 				fa = kmem_zalloc(fc, KM_SLEEP);
   2820 			}
   2821 
   2822 			if (flag == B_WRITE) {
   2823 				if (ddi_copyin(fdr.fdr_addr, fa, fc, mode)) {
   2824 					if (fdc->c_fdtype & FDCTYPE_DMA)
   2825 						ddi_dma_mem_free(&mem_handle);
   2826 					else
   2827 						kmem_free(fa, fc);
   2828 					fdretcsb(fdc);
   2829 					mutex_exit(&fdc->c_lolock);
   2830 					FDERRPRINT(FDEP_L1, FDEM_RAWI, (C,
   2831 					    "fdrawioctl: can't copy data\n"));
   2832 
   2833 					return (EFAULT);
   2834 				}
   2835 			}
   2836 			csb->csb_addr = fa;
   2837 			csb->csb_len = fc;
   2838 		} else {
   2839 			csb->csb_addr = 0;
   2840 			csb->csb_len = 0;
   2841 		}
   2842 	} else {
   2843 		csb->csb_addr = fa;
   2844 		csb->csb_len = fc;
   2845 	}
   2846 
   2847 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2848 	    (C, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmds[0],
   2849 	    csb->csb_cmds[1], csb->csb_cmds[2], csb->csb_cmds[3],
   2850 	    csb->csb_cmds[4], csb->csb_cmds[5], csb->csb_cmds[6],
   2851 	    csb->csb_cmds[7], csb->csb_cmds[8], csb->csb_cmds[9]));
   2852 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2853 	    (C, "nbytes: %x, opflags: %x, addr: %p, len: %x\n",
   2854 	    csb->csb_ncmds, csb->csb_opflags, (void *)csb->csb_addr,
   2855 	    csb->csb_len));
   2856 
   2857 
   2858 	/*
   2859 	 * Note that we ignore any error return s from fdexec.
   2860 	 * This is the way the driver has been, and it may be
   2861 	 * that the raw ioctl senders simply don't want to
   2862 	 * see any errors returned in this fashion.
   2863 	 */
   2864 
   2865 	if ((csb->csb_opflags & CSB_OFNORESULTS) ||
   2866 	    (csb->csb_opflags & CSB_OFIMMEDIATE)) {
   2867 		(void) fdexec(fdc, 0); /* don't sleep, don't check change */
   2868 	} else {
   2869 		(void) fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG);
   2870 	}
   2871 
   2872 
   2873 	FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2874 	    (C, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0],
   2875 	    csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3],
   2876 	    csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6],
   2877 	    csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9]));
   2878 
   2879 	if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT && fc &&
   2880 	    flag == B_READ && err == 0) {
   2881 		if (ddi_copyout(fa, fdr.fdr_addr, fc, mode)) {
   2882 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2883 			    (C, "fdrawioctl: can't copy read data\n"));
   2884 
   2885 			err = EFAULT;
   2886 		}
   2887 	}
   2888 
   2889 
   2890 	if (fc) {
   2891 		if (fdc->c_fdtype & FDCTYPE_DMA) {
   2892 			ddi_dma_mem_free(&mem_handle);
   2893 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2894 			    (C, "fdrawioctl: free dma memory\n"));
   2895 		} else {
   2896 			kmem_free(fa, fc);
   2897 		}
   2898 	}
   2899 
   2900 
   2901 	/* copy cmd results into fdr */
   2902 	for (i = 0; (int)i <= (int)csb->csb_nrslts; i++)
   2903 		fdr.fdr_result[i] = csb->csb_rslt[i];
   2904 	fdr.fdr_nbytes = fdc->c_csb.csb_rlen; /* return resid */
   2905 
   2906 	switch (ddi_model_convert_from(mode)) {
   2907 #ifdef _MULTI_DATAMODEL
   2908 	case DDI_MODEL_ILP32:
   2909 		bcopy(fdr.fdr_cmd, fdr32.fdr_cmd, sizeof (fdr32.fdr_cmd));
   2910 		fdr32.fdr_cnum = fdr.fdr_cnum;
   2911 		bcopy(fdr.fdr_result, fdr32.fdr_result,
   2912 		    sizeof (fdr32.fdr_result));
   2913 		fdr32.fdr_nbytes = fdr.fdr_nbytes;
   2914 		fdr32.fdr_addr = (caddr32_t)(uintptr_t)fdr.fdr_addr;
   2915 		if (ddi_copyout(&fdr32, (caddr_t)arg, sizeof (fdr32), mode)) {
   2916 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2917 			    (C, "fdrawioctl: can't copy results32\n"));
   2918 			err = EFAULT;
   2919 		}
   2920 		break;
   2921 #endif
   2922 	case DDI_MODEL_NONE:
   2923 	default:
   2924 		if (ddi_copyout(&fdr, (caddr_t)arg, sizeof (fdr), mode)) {
   2925 			FDERRPRINT(FDEP_L1, FDEM_RAWI,
   2926 			    (C, "fdrawioctl: can't copy results\n"));
   2927 			err = EFAULT;
   2928 		}
   2929 		break;
   2930 	}
   2931 
   2932 	fdretcsb(fdc);
   2933 	mutex_exit(&fdc->c_lolock);
   2934 	return (0);
   2935 }
   2936 
   2937 /*
   2938  * fdformat
   2939  *	format a track
   2940  * For PIO, builds a table of sector data values with 16 bytes
   2941  * (sizeof fdc's fifo) of dummy on end.	 This is so than when fdc->c_len
   2942  * goes to 0 and fd_intr sends a TC that all the real formatting will
   2943  * have already been done.
   2944  *
   2945  *	- called with the low level lock held
   2946  */
   2947 static int
   2948 fdformat(struct fdctlr *fdc, int unit, int cyl, int hd)
   2949 {
   2950 	struct fdcsb *csb;
   2951 	struct fdunit *un;
   2952 	struct fd_char *ch;
   2953 	int	cmdresult;
   2954 	uchar_t	*fmthdrs;
   2955 	caddr_t fd;
   2956 	int	i;
   2957 	size_t	real_length;
   2958 	ddi_device_acc_attr_t attr;
   2959 	ddi_acc_handle_t mem_handle;
   2960 
   2961 	FDERRPRINT(FDEP_L1, FDEM_FORM,
   2962 	    (C, "fdformat cyl %d, hd %d\n", cyl, hd));
   2963 	fdgetcsb(fdc);
   2964 
   2965 	ASSERT(fdc->c_un->un_unit_no == unit);
   2966 
   2967 	csb = &fdc->c_csb;
   2968 	un = fdc->c_un;
   2969 	ch = un->un_chars;
   2970 
   2971 	/* setup common things in csb */
   2972 	csb->csb_unit = (uchar_t)unit;
   2973 
   2974 	/*
   2975 	 * The controller needs to do a seek before
   2976 	 * each format to get to right cylinder.
   2977 	 */
   2978 	if (fdrecalseek(fdc, unit, cyl, FDXC_CHECKCHG)) {
   2979 		fdretcsb(fdc);
   2980 		return (EIO);
   2981 	}
   2982 
   2983 	/*
   2984 	 * now do the format itself
   2985 	 */
   2986 	csb->csb_nrslts = NRBRW;
   2987 	csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
   2988 
   2989 	csb->csb_cmds[0] = FDRAW_FORMAT;
   2990 	/* always or in MFM bit */
   2991 	csb->csb_cmds[0] |= MFM;
   2992 	csb->csb_cmds[1] = (hd << 2) | (unit & 0x03);
   2993 	csb->csb_cmds[2] = ch->fdc_medium ? 3 : 2;
   2994 	csb->csb_cmds[3] = ch->fdc_secptrack;
   2995 	csb->csb_cmds[4] = GPLF;
   2996 	csb->csb_cmds[5] = FDATA;
   2997 	csb->csb_ncmds = 6;
   2998 	csb->csb_maxretry = rwretry;
   2999 	csb->csb_retrys = 0;
   3000 
   3001 	/*
   3002 	 * NOTE: have to add size of fifo also - for dummy format action
   3003 	 * if PIO is being used.
   3004 	 */
   3005 
   3006 
   3007 	if (fdc->c_fdtype & FDCTYPE_DMA) {
   3008 
   3009 		csb->csb_len = (uint_t)4 * ch->fdc_secptrack;
   3010 
   3011 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
   3012 		attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
   3013 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
   3014 
   3015 		mutex_enter(&fdc->c_hilock);
   3016 
   3017 		cmdresult = ddi_dma_mem_alloc(fdc->c_dmahandle, csb->csb_len,
   3018 		    &attr, DDI_DMA_STREAMING,
   3019 		    DDI_DMA_DONTWAIT, 0, &fd, &real_length,
   3020 		    &mem_handle);
   3021 
   3022 		if (cmdresult != DDI_SUCCESS) {
   3023 			mutex_exit(&fdc->c_hilock);
   3024 			return (cmdresult);
   3025 		}
   3026 
   3027 		fdc->c_csb.csb_read = CSB_WRITE;
   3028 		if (fdstart_dma(fdc, fd,  csb->csb_len) != 0) {
   3029 			ddi_dma_mem_free(&mem_handle);
   3030 			mutex_exit(&fdc->c_hilock);
   3031 			return (-1);
   3032 		}
   3033 		mutex_exit(&fdc->c_hilock);
   3034 
   3035 
   3036 	} else {
   3037 		csb->csb_len = (uint_t)4 * ch->fdc_secptrack + 16;
   3038 		fd = kmem_zalloc(csb->csb_len, KM_SLEEP);
   3039 		fmthdrs = (uchar_t *)fd;
   3040 	}
   3041 
   3042 	csb->csb_addr = (caddr_t)fd;
   3043 
   3044 	for (i = 1; i <= ch->fdc_secptrack; i++) {
   3045 		*fd++ = (uchar_t)cyl;		/* cylinder */
   3046 		*fd++ = (uchar_t)hd;		/* head */
   3047 		*fd++ = (uchar_t)i;	/* sector number */
   3048 		*fd++ = ch->fdc_medium ? 3 : 2; /* sec_size code */
   3049 	}
   3050 
   3051 	if ((cmdresult = fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG)) == 0) {
   3052 		if (csb->csb_cmdstat)
   3053 			cmdresult = EIO;	/* XXX TBD NYD for now */
   3054 	}
   3055 
   3056 	if (fdc->c_fdtype & FDCTYPE_DMA) {
   3057 		ddi_dma_mem_free(&mem_handle);
   3058 	} else {
   3059 		kmem_free((caddr_t)fmthdrs, csb->csb_len);
   3060 	}
   3061 
   3062 	fdretcsb(fdc);
   3063 
   3064 	return (cmdresult);
   3065 }
   3066 
   3067 /*
   3068  * fdstart
   3069  *	called from fd_strategy() or from fdXXXX() to setup and
   3070  *	start operations of read or write only (using buf structs).
   3071  *	Because the chip doesn't handle crossing cylinder boundaries on
   3072  *	the fly, this takes care of those boundary conditions.	Note that
   3073  *	it sleeps until the operation is done *within fdstart* - so that
   3074  *	when fdstart returns, the operation is already done.
   3075  *
   3076  *	- called with the low level lock held
   3077  *
   3078  */
   3079 
   3080 static int slavio_index_pulse_work_around = 0;
   3081 
   3082 static void
   3083 fdstart(struct fdctlr *fdc)
   3084 {
   3085 	struct buf *bp;
   3086 	struct fdcsb *csb;
   3087 	struct fdunit *un;
   3088 	struct fd_char *ch;
   3089 	struct dk_map32 *dkm;
   3090 	uint_t	part;		/* partition number for the transfer */
   3091 	uint_t	start_part;	/* starting block of the partition */
   3092 	uint_t	last_part;	/* last block of the partition */
   3093 	uint_t	blk;		/* starting block of transfer on diskette */
   3094 	uint_t	sect;		/* starting block's offset into track */
   3095 	uint_t	cyl;		/* starting cylinder of the transfer */
   3096 	uint_t	bincyl;		/* starting blocks's offset into cylinder */
   3097 	uint_t	secpcyl;	/* number of sectors per cylinder */
   3098 	uint_t	phys_blkno;	/* no. of blocks on the diskette */
   3099 	uint_t	head;		/* one of two diskette heads */
   3100 	uint_t	unit;
   3101 	uint_t	len, tlen;
   3102 	caddr_t addr;
   3103 	caddr_t temp_addr;
   3104 	uint_t	partial_read = 0;
   3105 	int sb_temp_buf_used = 0;
   3106 
   3107 	bp = fdc->c_actf;
   3108 
   3109 	while (bp != NULL) {
   3110 
   3111 		fdc->c_actf = bp->av_forw;
   3112 		fdc->c_current = bp;
   3113 
   3114 		/*
   3115 		 * Initialize the buf structure.  The residual count is
   3116 		 * initially the number of bytes to be read or written
   3117 		 */
   3118 		bp->b_flags &= ~B_ERROR;
   3119 		bp->b_error = 0;
   3120 		bp->b_resid = bp->b_bcount;
   3121 		bp_mapin(bp);			/* map in buffers */
   3122 
   3123 		addr = bp->b_un.b_addr;		/* assign buffer address */
   3124 
   3125 		/*
   3126 		 * Find the unit and partition numbers.
   3127 		 */
   3128 		unit = fdc->c_un->un_unit_no;
   3129 		un = fdc->c_un;
   3130 		ch = un->un_chars;
   3131 		part = FDPARTITION(bp->b_edev);
   3132 		dkm = &un->un_label.dkl_map[part];
   3133 
   3134 		if (un->un_chars->fdc_medium) {
   3135 			phys_blkno = bp->b_blkno >> 1;
   3136 		} else {
   3137 			phys_blkno = bp->b_blkno;
   3138 		}
   3139 
   3140 		if (un->un_iostat) {
   3141 			kstat_waitq_to_runq(KIOSP);
   3142 		}
   3143 
   3144 		FDERRPRINT(FDEP_L1, FDEM_STRT,
   3145 		    (C, "fdstart: bp=0x%p blkno=0x%x bcount=0x%x\n",
   3146 		    (void *)bp, (int)bp->b_blkno, (int)bp->b_bcount));
   3147 
   3148 		/*
   3149 		 * Get the csb and initialize the values that are the same
   3150 		 * for DMA and PIO.
   3151 		 */
   3152 		fdgetcsb(fdc);		/* get csb (maybe wait for it) */
   3153 		csb = &fdc->c_csb;
   3154 		csb->csb_unit = unit;		/* floppy unit number */
   3155 
   3156 
   3157 		/*
   3158 		 * bugID:4133425 : If the controller is SLAVIO, and
   3159 		 * the read does not reach end of track, then modify
   3160 		 * the tlen to read until the end of track to a temp
   3161 		 * buffer and disable MT. After the read is over,
   3162 		 * copy the useful portion of the data to 'addr'.
   3163 		 * Enable this feature only when
   3164 		 * slavio_index_pulse_work_aound variable is
   3165 		 * set in /etc/system.
   3166 		 */
   3167 
   3168 
   3169 		if (bp->b_flags & B_READ) {
   3170 			if (((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
   3171 			    slavio_index_pulse_work_around) ||
   3172 			    (fdc->c_fdtype & FDCTYPE_TCBUG))
   3173 				csb->csb_cmds[0] = SK | FDRAW_RDCMD | MFM;
   3174 			else
   3175 				csb->csb_cmds[0] = MT | SK | FDRAW_RDCMD | MFM;
   3176 		} else {
   3177 			if (fdc->c_fdtype & FDCTYPE_TCBUG)
   3178 				csb->csb_cmds[0] = FDRAW_WRCMD | MFM;
   3179 			else
   3180 				csb->csb_cmds[0] = MT | FDRAW_WRCMD | MFM;
   3181 		}
   3182 
   3183 
   3184 		if (bp->b_flags & B_READ)
   3185 			fdc->c_csb.csb_read = CSB_READ;
   3186 		else
   3187 			fdc->c_csb.csb_read = CSB_WRITE;
   3188 
   3189 
   3190 		csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size  */
   3191 		csb->csb_cmds[6] = ch->fdc_secptrack; /* EOT-# of sectors/trk */
   3192 		csb->csb_cmds[7] = GPLN;	/* GPL - gap 3 size code */
   3193 		csb->csb_cmds[8] = SSSDTL;	/* DTL - be 0xFF if N != 0 */
   3194 
   3195 		csb->csb_ncmds = NCBRW;		/* number of command bytes */
   3196 		csb->csb_nrslts = NRBRW;	/* number of result bytes */
   3197 
   3198 
   3199 		/*
   3200 		 * opflags for interrupt handler, et.al.
   3201 		 */
   3202 		csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
   3203 
   3204 
   3205 		/*
   3206 		 * Make sure the transfer does not go off the end
   3207 		 * of the partition.  Limit the actual amount transferred
   3208 		 * to fit the partition.
   3209 		 */
   3210 
   3211 		blk = phys_blkno;
   3212 		start_part = (dkm->dkl_cylno * ch->fdc_secptrack
   3213 		    * ch->fdc_nhead);
   3214 		blk = blk + start_part;
   3215 		last_part = start_part + dkm->dkl_nblk;
   3216 
   3217 		if ((blk + (bp->b_bcount / ch->fdc_sec_size)) > last_part)
   3218 			len = (last_part - blk) * ch->fdc_sec_size;
   3219 		else
   3220 			len = (uint_t)bp->b_bcount;
   3221 
   3222 		/*
   3223 		 * now we have the real start blk,
   3224 		 * addr and len for xfer op
   3225 		 * sectors per cylinder
   3226 		 */
   3227 		secpcyl = ch->fdc_nhead * ch->fdc_secptrack;
   3228 
   3229 		/*
   3230 		 * The controller can transfer up to a cylinder at a time.
   3231 		 * Early revs of the 82077 have a bug that causes the chip to
   3232 		 * fail to respond to the Terminal Count signal.  Due to this
   3233 		 * bug, controllers with type FDCTYPE_TCBUG, only transfer up
   3234 		 * to a track at a time.
   3235 		 * See earlier comment for bugID:4133425 for index pulse
   3236 		 * work around.
   3237 		 */
   3238 
   3239 		while (len != 0) {
   3240 
   3241 			cyl = blk / secpcyl;	/* cylinder of transfer */
   3242 			bincyl = blk % secpcyl;	/* blk within cylinder */
   3243 			head = bincyl / ch->fdc_secptrack;
   3244 			sect = (bincyl % ch->fdc_secptrack) + 1;
   3245 						/* sect w/in track */
   3246 
   3247 			/*
   3248 			 * If the desired block and length will go beyond the
   3249 			 * cylinder end, limit it to the cylinder end.
   3250 			 */
   3251 
   3252 			if ((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
   3253 			    slavio_index_pulse_work_around &&
   3254 			    (fdc->c_csb.csb_read == CSB_READ)) {
   3255 
   3256 				tlen = (ch->fdc_secptrack - sect + 1) *
   3257 				    ch->fdc_sec_size;
   3258 				if (len < tlen) {
   3259 					partial_read = 1;
   3260 					temp_addr = (caddr_t)kmem_alloc(tlen,
   3261 					    KM_SLEEP);
   3262 				}
   3263 
   3264 			} else if (fdc->c_fdtype & FDCTYPE_TCBUG) {
   3265 				tlen = len;
   3266 				if (len > ((ch->fdc_secptrack - sect + 1) *
   3267 				    ch->fdc_sec_size))
   3268 					tlen = (ch->fdc_secptrack - sect + 1)
   3269 					    * ch->fdc_sec_size;
   3270 			} else {
   3271 				if (len > ((secpcyl - bincyl)
   3272 				    * ch->fdc_sec_size))
   3273 					tlen = (secpcyl - bincyl)
   3274 					    * ch->fdc_sec_size;
   3275 
   3276 				else
   3277 					tlen = len;
   3278 			}
   3279 			if (fdc->c_fdtype & FDCTYPE_SB) {
   3280 				/*
   3281 				 * To avoid underrun errors during IFB activity.
   3282 				 */
   3283 				if (tlen > max_fd_dma_len)
   3284 					tlen = max_fd_dma_len;
   3285 			}
   3286 
   3287 			FDERRPRINT(FDEP_L1, FDEM_STRT,
   3288 			    (C, "	blk 0x%x, addr 0x%p, len 0x%x\n",
   3289 			    blk, (void *)addr, len));
   3290 			FDERRPRINT(FDEP_L1, FDEM_STRT,
   3291 			    (C, "cyl:%x, head:%x, sec:%x\n",
   3292 			    cyl, head, sect));
   3293 
   3294 			FDERRPRINT(FDEP_L1, FDEM_STRT,
   3295 			    (C, "	resid 0x%lx, tlen %d\n",
   3296 			    bp->b_resid, tlen));
   3297 
   3298 			/*
   3299 			 * Finish programming the command
   3300 			 */
   3301 			csb->csb_cmds[1] = (head << 2) | unit;
   3302 			if (fdc->c_fdtype & FDCTYPE_SB)
   3303 				csb->csb_cmds[1] |= IPS;
   3304 
   3305 			csb->csb_cmds[2] = cyl;	/* C - cylinder address */
   3306 			csb->csb_cmds[3] = head;	/* H - head number */
   3307 			csb->csb_cmds[4] = sect;	/* R - sector number */
   3308 			if (fdc->c_fdtype & FDCTYPE_TCBUG)
   3309 				csb->csb_cmds[6] = sect +
   3310 				    (tlen / ch->fdc_sec_size) - 1;
   3311 
   3312 			csb->csb_len = tlen;
   3313 			if (partial_read)
   3314 				csb->csb_addr = temp_addr;
   3315 			else
   3316 				csb->csb_addr = addr;
   3317 
   3318 			/* retry this many times max */
   3319 			csb->csb_maxretry = rwretry;
   3320 			csb->csb_retrys = 0;
   3321 
   3322 			/* If platform supports DMA, set up DMA resources */
   3323 			if (fdc->c_fdtype & FDCTYPE_DMA) {
   3324 				if ((fdc->c_fdtype & FDCTYPE_SB) &&
   3325 				    (((uint32_t)(uintptr_t)addr & 0xFFFF0000) !=
   3326 				    (((uint32_t)(uintptr_t)addr + tlen) &
   3327 				    0xFFFF0000))) {
   3328 					csb->csb_addr = fdc->dma_buf;
   3329 					sb_temp_buf_used = 1;
   3330 					if (csb->csb_read != CSB_READ) {
   3331 						bcopy(addr, fdc->dma_buf, tlen);
   3332 				}
   3333 			}
   3334 				mutex_enter(&fdc->c_hilock);
   3335 
   3336 				if (fdstart_dma(fdc, csb->csb_addr,
   3337 				    tlen) != 0) {
   3338 
   3339 					bp->b_flags |= B_ERROR;
   3340 					bp->b_error = EAGAIN;
   3341 
   3342 					mutex_exit(&fdc->c_hilock);
   3343 					FDERRPRINT(FDEP_L1, FDEM_STRT,
   3344 					    (C, "fdstart: no dma resources\n"));
   3345 
   3346 					break;
   3347 				}
   3348 				mutex_exit(&fdc->c_hilock);
   3349 
   3350 			}
   3351 
   3352 			bp->b_error = fdexec(fdc, FDXC_SLEEP|FDXC_CHECKCHG);
   3353 			if (bp->b_error != 0) {
   3354 				/*
   3355 				 * error in fdexec
   3356 				 */
   3357 				FDERRPRINT(FDEP_L1, FDEM_STRT, (C,
   3358 				    "fdstart: bad exec of bp: 0x%p, err %d\n",
   3359 				    (void *)bp, bp->b_error));
   3360 
   3361 				bp->b_flags |= B_ERROR;
   3362 				if (partial_read) {
   3363 					partial_read = 0;
   3364 					kmem_free(temp_addr, tlen);
   3365 				}
   3366 				break;
   3367 			}
   3368 
   3369 			/*
   3370 			 * If it was a partial read, copy the useful
   3371 			 * portion of data to 'addr'.
   3372 			 */
   3373 			if (partial_read) {
   3374 				partial_read = 0;
   3375 				bcopy(temp_addr, addr, len);
   3376 				kmem_free(temp_addr, tlen);
   3377 				tlen = len;
   3378 			}
   3379 			if ((fdc->c_fdtype & FDCTYPE_SB) &&
   3380 			    (csb->csb_read == CSB_READ)) {
   3381 				if (sb_temp_buf_used) {
   3382 					bcopy(fdc->dma_buf, addr, tlen);
   3383 					sb_temp_buf_used = 0;
   3384 				}
   3385 			}
   3386 
   3387 			blk += tlen / ch->fdc_sec_size;
   3388 			len -= tlen;
   3389 			addr += tlen;
   3390 			bp->b_resid -= tlen;
   3391 
   3392 		}
   3393 
   3394 		FDERRPRINT(FDEP_L1, FDEM_STRT,
   3395 		    (C, "fdstart done: b_resid %lu, b_count %lu, csb_rlen %d\n",
   3396 		    bp->b_resid, bp->b_bcount, fdc->c_csb.csb_rlen));
   3397 
   3398 		fdc->c_current = 0;
   3399 		fdretcsb(fdc);
   3400 		if (un->un_iostat) {
   3401 			if (bp->b_flags & B_READ) {
   3402 				KIOSP->reads++;
   3403 				KIOSP->nread +=
   3404 				    (bp->b_bcount - bp->b_resid);
   3405 			} else {
   3406 				KIOSP->writes++;
   3407 				KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
   3408 			}
   3409 			kstat_runq_exit(KIOSP);
   3410 		}
   3411 		biodone(bp);
   3412 
   3413 		/*
   3414 		 * Look at the next buffer
   3415 		 */
   3416 		bp = fdc->c_actf;
   3417 
   3418 	}
   3419 }
   3420 
   3421 /*
   3422  * Set up DMA resources
   3423  * The DMA handle was initialized in fd_attach()
   3424  * Assumes the handle has already been allocated by fd_attach()
   3425  */
   3426 static int
   3427 fdstart_dma(struct fdctlr *fdc, caddr_t addr, uint_t len)
   3428 {
   3429 	int		flags;		/* flags for setting up resources */
   3430 	int		res;
   3431 
   3432 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: start\n"));
   3433 
   3434 	if (fdc->c_csb.csb_read == CSB_READ) {
   3435 		flags = DDI_DMA_READ;
   3436 	} else {
   3437 		flags = DDI_DMA_WRITE;
   3438 	}
   3439 
   3440 
   3441 	/* allow partial mapping to maximize the portability of the driver */
   3442 	flags = flags | DDI_DMA_PARTIAL;
   3443 
   3444 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: amt. asked for %d\n",
   3445 	    len));
   3446 
   3447 	/*
   3448 	 * Zero out the current cookie.  This is done to ensure that
   3449 	 * the previous transfers cookie information can in no way be
   3450 	 * used.
   3451 	 */
   3452 	bzero((char *)&fdc->c_csb.csb_dmacookie,
   3453 	    sizeof (fdc->c_csb.csb_dmacookie));
   3454 	fdc->c_csb.csb_nwin = 0;
   3455 	fdc->c_csb.csb_windex = 0;
   3456 	fdc->c_csb.csb_ccount = 0;
   3457 
   3458 	res = ddi_dma_addr_bind_handle(fdc->c_dmahandle, NULL, addr, len,
   3459 	    flags, DDI_DMA_DONTWAIT, 0,  &fdc->c_csb.csb_dmacookie,
   3460 	    &fdc->c_csb.csb_ccount);
   3461 
   3462 	switch (res) {
   3463 		case DDI_DMA_MAPPED:
   3464 			/*
   3465 			 * There is one window. csb_windex is the index
   3466 			 * into the array of windows. If there are n
   3467 			 * windows then, (0 <= windex <= n-1).  csb_windex
   3468 			 * represents the index of the next window
   3469 			 * to be processed.
   3470 			 */
   3471 			fdc->c_csb.csb_nwin = 1;
   3472 			fdc->c_csb.csb_windex = 1;
   3473 
   3474 
   3475 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3476 			    (C, "fdstart_dma: DDI_DMA_MAPPED\n"));
   3477 
   3478 			break;
   3479 		case DDI_DMA_PARTIAL_MAP:
   3480 
   3481 			/*
   3482 			 * obtain the number of DMA windows
   3483 			 */
   3484 			if (ddi_dma_numwin(fdc->c_dmahandle,
   3485 			    &fdc->c_csb.csb_nwin) != DDI_SUCCESS) {
   3486 				return (-1);
   3487 			}
   3488 
   3489 
   3490 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3491 			    (C, "fdstart_dma: partially mapped %d windows\n",
   3492 			    fdc->c_csb.csb_nwin));
   3493 
   3494 			/*
   3495 			 * The DMA window currently in use is window number
   3496 			 * one.
   3497 			 */
   3498 			fdc->c_csb.csb_windex = 1;
   3499 
   3500 			break;
   3501 		case DDI_DMA_NORESOURCES:
   3502 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3503 			    (C, "fdstart_dma: no resources\n"));
   3504 			return (-1);
   3505 		case DDI_DMA_NOMAPPING:
   3506 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3507 			    (C, "fdstart_dma: no mapping\n"));
   3508 			return (-1);
   3509 		case DDI_DMA_TOOBIG:
   3510 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3511 			    (C, "fdstart_dma: too big\n"));
   3512 			return (-1);
   3513 
   3514 		case DDI_DMA_INUSE:
   3515 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3516 			    (C, "fdstart_dma: dma inuse\n"));
   3517 			return (-1);
   3518 		default:
   3519 			FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3520 			    (C, "fdstart_dma: result is 0x%x\n", res));
   3521 			return (-1);
   3522 
   3523 	};
   3524 
   3525 	FDERRPRINT(FDEP_L1, FDEM_SDMA,
   3526 	    (C, "fdstart_dma: bound the handle\n"));
   3527 
   3528 	ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
   3529 
   3530 	FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: done\n"));
   3531 	return (0);
   3532 }
   3533 
   3534 
   3535 /*
   3536  * fd_unbind_handle: unbind a dma handle if one exists
   3537  *		return EIO if unbind failes
   3538  */
   3539 static int
   3540 fd_unbind_handle(struct fdctlr *fdc)
   3541 {
   3542 	if ((fdc->c_fdtype & FDCTYPE_DMA) &&
   3543 	    ((fdc->c_csb.csb_read == CSB_READ) ||
   3544 	    (fdc->c_csb.csb_read == CSB_WRITE))) {
   3545 		mutex_enter(&fdc->c_hilock);
   3546 
   3547 		if (fdc->c_fdtype & FDCTYPE_SB) {
   3548 			if (fdc->sb_dma_lock) {
   3549 				release_sb_dma(fdc);
   3550 			}
   3551 		}
   3552 
   3553 		/*
   3554 		 * If the byte count isn't zero, then the DMA engine is
   3555 		 * still doing a transfer.  If the byte count is nonzero,
   3556 		 * reset the DMA engine to cause it to drain.
   3557 		 */
   3558 
   3559 		if (get_data_count_register(fdc) != 0) {
   3560 			FDERRPRINT(FDEP_L1, FDEM_EXEC,
   3561 			    (C, "unbind & byte count isn't zero\n"));
   3562 
   3563 			reset_dma_controller(fdc);
   3564 			set_dma_control_register(fdc, DCSR_INIT_BITS);
   3565 		}
   3566 
   3567 		if (ddi_dma_unbind_handle(fdc->c_dmahandle) != DDI_SUCCESS) {
   3568 			FDERRPRINT(FDEP_L1, FDEM_EXEC,
   3569 			    (C, "problem unbinding the handle\n"));
   3570 			mutex_exit(&fdc->c_hilock);
   3571 			return (EIO);
   3572 		}
   3573 		mutex_exit(&fdc->c_hilock);
   3574 	}
   3575 	return (0);
   3576 }
   3577 
   3578 /*
   3579  * fdexec
   3580  *	all commands go through here.  Assumes the command block
   3581  *	fdctlr.c_csb is filled in.  The bytes are sent to the
   3582  *	controller and then we do whatever else the csb says -
   3583  *	like wait for immediate results, etc.
   3584  *
   3585  *	All waiting for operations done is in here - to allow retrys
   3586  *	and checking for disk changed - so we don't have to worry
   3587  *	about sleeping at interrupt level.
   3588  *
   3589  * RETURNS: 0 if all ok,
   3590  *	ENXIO - diskette not in drive
   3591  *	EBUSY - if chip is locked or busy
   3592  *	EIO - for timeout during sending cmds to chip
   3593  *
   3594  * to sleep: set FDXC_SLEEP, to check for disk
   3595  * changed: set FDXC_CHECKCHG
   3596  *
   3597  *	- called with the lock held
   3598  */
   3599 static int
   3600 fdexec(struct fdctlr *fdc, int flags)
   3601 {
   3602 	struct fdcsb *csb;
   3603 	int	i;
   3604 	int	to, unit;
   3605 	uchar_t	tmp;
   3606 	caddr_t a = (caddr_t)fdc;
   3607 
   3608 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: flags:%x\n", flags));
   3609 
   3610 	ASSERT(mutex_owned(&fdc->c_lolock));
   3611 
   3612 	csb = &fdc->c_csb;
   3613 	unit = csb->csb_unit;
   3614 
   3615 
   3616 	ASSERT(unit == fdc->c_un->un_unit_no);
   3617 
   3618 retry:
   3619 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: cmd is %s\n",
   3620 	    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
   3621 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: transfer rate = %d\n",
   3622 	    fdc->c_un->un_chars->fdc_transfer_rate));
   3623 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: sec size = %d\n",
   3624 	    fdc->c_un->un_chars->fdc_sec_size));
   3625 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: nblocks (512) = %d\n",
   3626 	    fdc->c_un->un_label.dkl_map[2].dkl_nblk));
   3627 
   3628 	if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
   3629 		fdexec_turn_on_motor(fdc, flags, unit);
   3630 	}
   3631 
   3632 
   3633 	fdselect(fdc, unit, 1);	/* select drive */
   3634 
   3635 	/*
   3636 	 * select data rate for this unit/command
   3637 	 */
   3638 	switch (fdc->c_un->un_chars->fdc_transfer_rate) {
   3639 	case 500:
   3640 		Dsr(fdc, 0);
   3641 		break;
   3642 	case 300:
   3643 		Dsr(fdc, 1);
   3644 		break;
   3645 	case 250:
   3646 		Dsr(fdc, 2);
   3647 		break;
   3648 	}
   3649 	drv_usecwait(2);
   3650 
   3651 
   3652 	/*
   3653 	 * If checking for changed is enabled (i.e., not seeking in checkdisk),
   3654 	 * we sample the DSKCHG line to see if the diskette has wandered away.
   3655 	 */
   3656 	if ((flags & FDXC_CHECKCHG) && fdsense_chng(fdc, unit)) {
   3657 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "diskette changed\n"));
   3658 		fdc->c_un->un_flags |= FDUNIT_CHANGED;
   3659 
   3660 		if (fdcheckdisk(fdc, unit)) {
   3661 
   3662 			(void) fd_unbind_handle(fdc);
   3663 			return (ENXIO);
   3664 
   3665 		}
   3666 	}
   3667 
   3668 	/*
   3669 	 * gather some statistics
   3670 	 */
   3671 	switch (csb->csb_cmds[0] & 0x1f) {
   3672 	case FDRAW_RDCMD:
   3673 		fdc->fdstats.rd++;
   3674 		break;
   3675 	case FDRAW_WRCMD:
   3676 		fdc->fdstats.wr++;
   3677 		break;
   3678 	case FDRAW_REZERO:
   3679 		fdc->fdstats.recal++;
   3680 		break;
   3681 	case FDRAW_FORMAT:
   3682 		fdc->fdstats.form++;
   3683 		break;
   3684 	default:
   3685 		fdc->fdstats.other++;
   3686 		break;
   3687 	}
   3688 
   3689 	/*
   3690 	 * Always set the opmode *prior* to poking the chip.
   3691 	 * This way we don't have to do any locking at high level.
   3692 	 */
   3693 	csb->csb_raddr = 0;
   3694 	csb->csb_rlen = 0;
   3695 	if (csb->csb_opflags & CSB_OFSEEKOPS) {
   3696 		csb->csb_opmode = 2;
   3697 	} else if (csb->csb_opflags & CSB_OFIMMEDIATE) {
   3698 		csb->csb_opmode = 0;
   3699 	} else {
   3700 		csb->csb_opmode = 1;	/* normal data xfer commands */
   3701 		csb->csb_raddr = csb->csb_addr;
   3702 		csb->csb_rlen = csb->csb_len;
   3703 	}
   3704 
   3705 	bzero((caddr_t)csb->csb_rslt, 10);
   3706 	csb->csb_status = 0;
   3707 	csb->csb_cmdstat = 0;
   3708 
   3709 
   3710 	/*
   3711 	 * Program the DMA engine with the length and address of the transfer
   3712 	 * (DMA is only used on a read or a write)
   3713 	 */
   3714 	if ((fdc->c_fdtype & FDCTYPE_DMA) &&
   3715 	    ((fdc->c_csb.csb_read == CSB_READ) ||
   3716 	    (fdc->c_csb.csb_read == CSB_WRITE)))  {
   3717 		mutex_enter(&fdc->c_hilock);
   3718 
   3719 		/* Reset the dcsr to clear it of all errors */
   3720 
   3721 		reset_dma_controller(fdc);
   3722 
   3723 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie addr 0x%p\n",
   3724 		    (void *)fdc->c_csb.csb_dmacookie.dmac_laddress));
   3725 
   3726 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie length %ld\n",
   3727 		    fdc->c_csb.csb_dmacookie.dmac_size));
   3728 		ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
   3729 
   3730 		set_data_count_register(fdc,
   3731 		    fdc->c_csb.csb_dmacookie.dmac_size);
   3732 		set_data_address_register(fdc,
   3733 		    fdc->c_csb.csb_dmacookie.dmac_laddress);
   3734 
   3735 		/* Program the DCSR */
   3736 
   3737 		if (fdc->c_csb.csb_read == CSB_READ)
   3738 			set_dma_mode(fdc, CSB_READ);
   3739 		else
   3740 			set_dma_mode(fdc, CSB_WRITE);
   3741 		mutex_exit(&fdc->c_hilock);
   3742 	}
   3743 
   3744 	/*
   3745 	 * I saw this (chip unexpectedly busy) happen when i shoved the
   3746 	 * floppy into the drive while
   3747 	 * running a dd if= /dev/rfd0c.	so it *is* possible for this to happen.
   3748 	 * we need to do a ctlr reset ...
   3749 	 */
   3750 
   3751 	if (Msr(fdc) & CB) {
   3752 		/* tried to give command to chip when it is busy! */
   3753 		FDERRPRINT(FDEP_L3, FDEM_EXEC,
   3754 		    (C, "fdc: unexpectedly busy-stat 0x%x\n", Msr(fdc)));
   3755 		csb->csb_cmdstat = 1;	/* XXX TBD ERRS NYD for now */
   3756 
   3757 		(void) fd_unbind_handle(fdc);
   3758 		return (EBUSY);
   3759 	}
   3760 
   3761 	/* Give command to the controller */
   3762 	for (i = 0; i < (int)csb->csb_ncmds; i++) {
   3763 
   3764 		/* Test the readiness of the controller to receive the cmd */
   3765 		for (to = FD_CRETRY; to; to--) {
   3766 			if ((Msr(fdc) & (DIO|RQM)) == RQM)
   3767 				break;
   3768 		}
   3769 		if (to == 0) {
   3770 			FDERRPRINT(FDEP_L2, FDEM_EXEC,
   3771 			    (C, "fdc: no RQM - stat 0x%x\n", Msr(fdc)));
   3772 			csb->csb_cmdstat = 1;
   3773 
   3774 			(void) fd_unbind_handle(fdc);
   3775 			return (EIO);
   3776 		}
   3777 
   3778 		Set_Fifo(fdc, csb->csb_cmds[i]);
   3779 
   3780 		FDERRPRINT(FDEP_L1, FDEM_EXEC,
   3781 		    (C, "fdexec: sent 0x%x, Msr 0x%x\n", csb->csb_cmds[i],
   3782 		    Msr(fdc)));
   3783 
   3784 	}
   3785 
   3786 
   3787 	/*
   3788 	 * Start watchdog timer on data transfer type commands - required
   3789 	 * in case a diskette is not present or is unformatted
   3790 	 */
   3791 	if (csb->csb_opflags & CSB_OFTIMEIT) {
   3792 		fdc->c_timeid = timeout(fdwatch, a,
   3793 		    tosec * drv_usectohz(1000000));
   3794 	}
   3795 
   3796 	FDERRPRINT(FDEP_L1, FDEM_EXEC,
   3797 	    (C, "fdexec: cmd sent, Msr 0x%x\n", Msr(fdc)));
   3798 
   3799 	/* If the operation has no results - then just return */
   3800 	if (csb->csb_opflags & CSB_OFNORESULTS) {
   3801 		if (fdc->c_fdtype & FDCTYPE_82077) {
   3802 			if (fdc->c_mtimeid == 0) {
   3803 				fdc->c_mtimeid = timeout(fdmotoff, a,
   3804 				    Motoff_delay);
   3805 			}
   3806 		}
   3807 		FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..\n"));
   3808 
   3809 		/*
   3810 		 * Make sure the last byte is received well by the
   3811 		 * controller. On faster CPU, it may still be busy
   3812 		 * by the time another command comes here.
   3813 		 */
   3814 		for (to = FD_CRETRY; to; to--) {
   3815 			if ((Msr(fdc) & (DIO|RQM)) == RQM)
   3816 				break;
   3817 			}
   3818 		if (to == 0) {
   3819 			csb->csb_cmdstat = 1;
   3820 			return (EIO);
   3821 		}
   3822 
   3823 		/*
   3824 		 * An operation that has no results isn't doing DMA so,
   3825 		 * there is no reason to try to unbind a handle
   3826 		 */
   3827 		return (0);
   3828 	}
   3829 
   3830 	/*
   3831 	 * If this operation has no interrupt AND an immediate result
   3832 	 * then we just busy wait for the results and stuff them into
   3833 	 * the csb
   3834 	 */
   3835 	if (csb->csb_opflags & CSB_OFIMMEDIATE) {
   3836 		to = FD_RRETRY;
   3837 		csb->csb_nrslts = 0;
   3838 		/*
   3839 		 * Wait while this command is still going on.
   3840 		 */
   3841 		while ((tmp = Msr(fdc)) & CB) {
   3842 			/*
   3843 			 * If RQM + DIO, then a result byte is at hand.
   3844 			 */
   3845 			if ((tmp & (RQM|DIO|CB)) == (RQM|DIO|CB)) {
   3846 				csb->csb_rslt[csb->csb_nrslts++] =
   3847 				    Fifo(fdc);
   3848 				/*
   3849 				 * FDERRPRINT(FDEP_L4, FDEM_EXEC,
   3850 				 *    (C, "fdexec: got result 0x%x\n",
   3851 				 *    csb->csb_nrslts));
   3852 				 */
   3853 			} else if (--to == 0) {
   3854 				FDERRPRINT(FDEP_L4, FDEM_EXEC,
   3855 				    (C, "fdexec: timeout, Msr%x, nr%x\n",
   3856 				    Msr(fdc), csb->csb_nrslts));
   3857 
   3858 				csb->csb_status = 2;
   3859 				if (fdc->c_fdtype & FDCTYPE_82077) {
   3860 					if (fdc->c_mtimeid == 0) {
   3861 						fdc->c_mtimeid = timeout(
   3862 						    fdmotoff, a, Motoff_delay);
   3863 					}
   3864 				}
   3865 				/*
   3866 				 * There is no DMA happening.  No need to
   3867 				 * try freeing a handle.
   3868 				 */
   3869 
   3870 				return (EIO);
   3871 			}
   3872 		}
   3873 	}
   3874 
   3875 	/*
   3876 	 * If told to sleep here, well then sleep!
   3877 	 */
   3878 
   3879 	if (flags & FDXC_SLEEP) {
   3880 		fdc->c_flags |= FDCFLG_WAITING;
   3881 		while (fdc->c_flags & FDCFLG_WAITING) {
   3882 			cv_wait(&fdc->c_iocv, &fdc->c_lolock);
   3883 		}
   3884 	}
   3885 
   3886 	/*
   3887 	 * kludge for end-of-cylinder error which must be ignored!!!
   3888 	 */
   3889 
   3890 	if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
   3891 	    ((csb->csb_rslt[0] & IC_SR0) == 0x40) &&
   3892 	    (csb->csb_rslt[1] & EN_SR1))
   3893 		csb->csb_rslt[0] &= ~IC_SR0;
   3894 
   3895 	/*
   3896 	 * See if there was an error detected, if so, fdrecover()
   3897 	 * will check it out and say what to do.
   3898 	 *
   3899 	 * Don't do this, though, if this was the Sense Drive Status
   3900 	 * or the Dump Registers command.
   3901 	 */
   3902 	if (((csb->csb_rslt[0] & IC_SR0) || (fdc->c_csb.csb_dcsr_rslt) ||
   3903 	    (csb->csb_status)) &&
   3904 	    ((csb->csb_cmds[0] != FDRAW_SENSE_DRV) &&
   3905 	    (csb->csb_cmds[0] != DUMPREG))) {
   3906 		/* if it can restarted OK, then do so, else return error */
   3907 		if (fdrecover(fdc) != 0) {
   3908 			if (fdc->c_fdtype & FDCTYPE_82077) {
   3909 				if (fdc->c_mtimeid == 0) {
   3910 					fdc->c_mtimeid = timeout(fdmotoff,
   3911 					    a, Motoff_delay);
   3912 				}
   3913 			}
   3914 
   3915 			/*
   3916 			 * If this was a dma transfer, unbind the handle so
   3917 			 * that other transfers may use it.
   3918 			 */
   3919 
   3920 			(void) fd_unbind_handle(fdc);
   3921 			return (EIO);
   3922 		} else {
   3923 			/* ASSUMES that cmd is still intact in csb */
   3924 			goto retry;
   3925 		}
   3926 	}
   3927 
   3928 	/* things went ok */
   3929 	if (fdc->c_fdtype & FDCTYPE_82077) {
   3930 		if (fdc->c_mtimeid == 0) {
   3931 			fdc->c_mtimeid = timeout(fdmotoff, a, Motoff_delay);
   3932 		}
   3933 	}
   3934 	FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..........\n"));
   3935 
   3936 	if (fd_unbind_handle(fdc))
   3937 		return (EIO);
   3938 
   3939 	return (0);
   3940 }
   3941 
   3942 /*
   3943  * Turn on the drive's motor
   3944  *
   3945  *	- called with the low level lock held
   3946  */
   3947 static void
   3948 fdexec_turn_on_motor(struct fdctlr *fdc, int flags,  uint_t unit)
   3949 {
   3950 	clock_t local_lbolt;
   3951 	timeout_id_t timeid;
   3952 
   3953 	/*
   3954 	 * The low level mutex may not be held over the call to
   3955 	 * untimeout().  See the manpage for details.
   3956 	 */
   3957 	timeid = fdc->c_mtimeid;
   3958 	fdc->c_mtimeid = 0;
   3959 	if (timeid) {
   3960 		mutex_exit(&fdc->c_lolock);
   3961 		(void) untimeout(timeid);
   3962 		mutex_enter(&fdc->c_lolock);
   3963 	}
   3964 
   3965 	ASSERT(fdc->c_un->un_unit_no == unit);
   3966 
   3967 
   3968 	set_rotational_speed(fdc, unit);
   3969 
   3970 	if (!(Dor(fdc) & (MOTEN(unit)))) {
   3971 		/*
   3972 		 * Turn on the motor
   3973 		 */
   3974 		FDERRPRINT(FDEP_L1, FDEM_EXEC,
   3975 		    (C, "fdexec: turning on motor\n"));
   3976 
   3977 		/* LINTED */
   3978 		Set_dor(fdc, (MOTEN(unit)), 1);
   3979 
   3980 		if (flags & FDXC_SLEEP) {
   3981 			local_lbolt = ddi_get_lbolt();
   3982 			(void) cv_timedwait(&fdc->c_motoncv,
   3983 			    &fdc->c_lolock, local_lbolt + Moton_delay);
   3984 		} else {
   3985 			drv_usecwait(1000000);
   3986 		}
   3987 	}
   3988 
   3989 }
   3990 
   3991 /*
   3992  * fdrecover
   3993  *	see if possible to retry an operation.
   3994  *	All we can do is restart the operation.	 If we are out of allowed
   3995  *	retries - return non-zero so that the higher levels will be notified.
   3996  *
   3997  * RETURNS: 0 if ok to restart, !0 if can't or out of retries
   3998  *	- called with the low level lock held
   3999  */
   4000 static int
   4001 fdrecover(struct fdctlr *fdc)
   4002 {
   4003 	struct fdcsb *csb;
   4004 
   4005 	FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdrecover\n"));
   4006 	csb = &fdc->c_csb;
   4007 
   4008 	if (fdc->c_flags & FDCFLG_TIMEDOUT) {
   4009 		struct fdcsb savecsb;
   4010 
   4011 		fdc->c_flags ^= FDCFLG_TIMEDOUT;
   4012 		csb->csb_rslt[1] |= TO_SR1;
   4013 		FDERRPRINT(FDEP_L1, FDEM_RECO,
   4014 		    (C, "fd%d: %s timed out\n", csb->csb_unit,
   4015 		    fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
   4016 
   4017