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;