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