17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 519397407SSherry Moore * Common Development and Distribution License (the "License"). 619397407SSherry Moore * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*427f591eSFred Herard * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Intel 82077 Floppy Disk Driver 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Notes 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * 0. The driver supports two flavors of hardware design: 347c478bd9Sstevel@tonic-gate * "SUNW,fdtwo" - sun4m - 82077 with sun4m style Auxio 357c478bd9Sstevel@tonic-gate * "fdthree" - sun4u - 82077 with DMA 367c478bd9Sstevel@tonic-gate * In addition it supports an apparent bug in some versions of 377c478bd9Sstevel@tonic-gate * the 82077 controller. 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * 1. The driver is mostly set up for multiple controllers, multiple 407c478bd9Sstevel@tonic-gate * drives. However- we *do* assume the use of the AUXIO register, and 417c478bd9Sstevel@tonic-gate * if we ever have > 1 fdc, we'll have to see what that means. This 427c478bd9Sstevel@tonic-gate * is all intrinsically machine specific, but there isn't much we 437c478bd9Sstevel@tonic-gate * can do about it. 447c478bd9Sstevel@tonic-gate * 457c478bd9Sstevel@tonic-gate * 2. The driver also is structured to deal with one drive active at 467c478bd9Sstevel@tonic-gate * a time. This is because the 82072 chip (no longer supported) was 477c478bd9Sstevel@tonic-gate * known to be buggy with respect to overlapped seeks. 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * 3. The high level interrupt code is in assembler, and runs in a 507c478bd9Sstevel@tonic-gate * sparc trap window. It acts as a pseudo-dma engine as well as 517c478bd9Sstevel@tonic-gate * handles a couple of other interrupts. When it gets its job done, 527c478bd9Sstevel@tonic-gate * it schedules a second stage interrupt (soft interrupt) which 537c478bd9Sstevel@tonic-gate * is then fielded here in fd_lointr. When DMA is used, the fdintr_dma 547c478bd9Sstevel@tonic-gate * interrupt handler is used. 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * 4. Nearly all locking is done on a lower level MUTEX_DRIVER 577c478bd9Sstevel@tonic-gate * mutex. The locking is quite conservative, and is generally 587c478bd9Sstevel@tonic-gate * established very close to any of the entries into the driver. 597c478bd9Sstevel@tonic-gate * There is nearly no locking done of the high level MUTEX_DRIVER 607c478bd9Sstevel@tonic-gate * mutex (which generally is a SPIN mutex because the floppy usually 617c478bd9Sstevel@tonic-gate * interrupts above LOCK_LEVEL). The assembler high level interrupt 627c478bd9Sstevel@tonic-gate * handler grabs the high level mutex, but the code in the driver 637c478bd9Sstevel@tonic-gate * here is especially structured to not need to do this. 647c478bd9Sstevel@tonic-gate * 657c478bd9Sstevel@tonic-gate * 5. Fdrawioctl commands that pass data are not optimized for 667c478bd9Sstevel@tonic-gate * speed. If they need to be faster, the driver structure will 677c478bd9Sstevel@tonic-gate * have to be redone such that fdrawioctl calls physio after 687c478bd9Sstevel@tonic-gate * cons'ing up a uio structure and that fdstart will be able 697c478bd9Sstevel@tonic-gate * to detect that a particular buffer is a 'special' buffer. 707c478bd9Sstevel@tonic-gate * 717c478bd9Sstevel@tonic-gate * 6. Removable media support is not complete. 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #include <sys/param.h> 767c478bd9Sstevel@tonic-gate #include <sys/buf.h> 777c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 787c478bd9Sstevel@tonic-gate #include <sys/uio.h> 797c478bd9Sstevel@tonic-gate #include <sys/open.h> 807c478bd9Sstevel@tonic-gate #include <sys/conf.h> 817c478bd9Sstevel@tonic-gate #include <sys/file.h> 827c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 837c478bd9Sstevel@tonic-gate #include <sys/debug.h> 847c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 857c478bd9Sstevel@tonic-gate #include <sys/stat.h> 867c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate #include <sys/dklabel.h> 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate #include <sys/vtoc.h> 917c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 927c478bd9Sstevel@tonic-gate #include <sys/fdio.h> 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 957c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 967c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * included to check for ELC or SLC which report floppy controller that 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate #include "sys/fdvar.h" 1047c478bd9Sstevel@tonic-gate #include "sys/fdreg.h" 1057c478bd9Sstevel@tonic-gate #include "sys/dma_i8237A.h" 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Defines 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate #define KIOSP KSTAT_IO_PTR(un->un_iostat) 1117c478bd9Sstevel@tonic-gate #define KIOIP KSTAT_INTR_PTR(fdc->c_intrstat) 1127c478bd9Sstevel@tonic-gate #define MEDIUM_DENSITY 0x40 1137c478bd9Sstevel@tonic-gate #define SEC_SIZE_CODE (fdctlr.c_csb->csb_unit]->un_chars->medium ? 3 : 2) 1147c478bd9Sstevel@tonic-gate #define CMD_READ (MT + SK + FDRAW_RDCMD + MFM) 1157c478bd9Sstevel@tonic-gate #define CMD_WRITE (MT + FDRAW_WRCMD + MFM) 1167c478bd9Sstevel@tonic-gate #define C CE_CONT 1177c478bd9Sstevel@tonic-gate #define FD_POLLABLE_PROP "pollable" /* prom property */ 1187c478bd9Sstevel@tonic-gate #define FD_MANUAL_EJECT "manual" /* prom property */ 1197c478bd9Sstevel@tonic-gate #define FD_UNIT "unit" /* prom property */ 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* 1227c478bd9Sstevel@tonic-gate * Sony MP-F17W-50D Drive Parameters 1237c478bd9Sstevel@tonic-gate * High Capacity 1247c478bd9Sstevel@tonic-gate * Capacity unformatted 2Mb 1257c478bd9Sstevel@tonic-gate * Capacity formatted 1.47Mb 1267c478bd9Sstevel@tonic-gate * Encoding method MFM 1277c478bd9Sstevel@tonic-gate * Recording density 17434 bpi 1287c478bd9Sstevel@tonic-gate * Track density 135 tpi 1297c478bd9Sstevel@tonic-gate * Cylinders 80 1307c478bd9Sstevel@tonic-gate * Heads 2 1317c478bd9Sstevel@tonic-gate * Tracks 160 1327c478bd9Sstevel@tonic-gate * Rotational speed 300 rpm 1337c478bd9Sstevel@tonic-gate * Transfer rate 250/500 kbps 1347c478bd9Sstevel@tonic-gate * Latency (average) 100 ms 1357c478bd9Sstevel@tonic-gate * Access time 1367c478bd9Sstevel@tonic-gate * Average 95 ms 1377c478bd9Sstevel@tonic-gate * Track to track 3 ms 1387c478bd9Sstevel@tonic-gate * Head settling time 15 ms 1397c478bd9Sstevel@tonic-gate * Motor start time 500 ms 1407c478bd9Sstevel@tonic-gate * Head load time ? ms 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* 1447c478bd9Sstevel@tonic-gate * The max_fd_dma_len is used only when southbridge is present. 1457c478bd9Sstevel@tonic-gate * It has been observed that when IFB tests are run the floppy dma could get 1467c478bd9Sstevel@tonic-gate * starved and result in underrun errors. After experimenting it was found that 1477c478bd9Sstevel@tonic-gate * doing dma in chunks of 2048 works OK. 1487c478bd9Sstevel@tonic-gate * The reason for making this a global variable is that there could be 1497c478bd9Sstevel@tonic-gate * situations under which the customer would like to get full performance 1507c478bd9Sstevel@tonic-gate * from floppy. He may not be having IFB boards that cause underrun errors. 1517c478bd9Sstevel@tonic-gate * Under those conditions we could set this value to a much higher value 1527c478bd9Sstevel@tonic-gate * by editing /etc/system file. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate int max_fd_dma_len = 2048; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate static void quiesce_fd_interrupt(struct fdctlr *); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * Character/block entry points function prototypes 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate static int fd_open(dev_t *, int, int, cred_t *); 1627c478bd9Sstevel@tonic-gate static int fd_close(dev_t, int, int, cred_t *); 1637c478bd9Sstevel@tonic-gate static int fd_strategy(struct buf *); 1647c478bd9Sstevel@tonic-gate static int fd_read(dev_t, struct uio *, cred_t *); 1657c478bd9Sstevel@tonic-gate static int fd_write(dev_t, struct uio *, cred_t *); 1667c478bd9Sstevel@tonic-gate static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1677c478bd9Sstevel@tonic-gate static int 1687c478bd9Sstevel@tonic-gate fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * Device operations (dev_ops) entries function prototypes 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate static int fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1747c478bd9Sstevel@tonic-gate void **result); 1757c478bd9Sstevel@tonic-gate static int fd_attach(dev_info_t *, ddi_attach_cmd_t); 1767c478bd9Sstevel@tonic-gate static int fd_detach(dev_info_t *, ddi_detach_cmd_t); 1777c478bd9Sstevel@tonic-gate static int fd_power(dev_info_t *dip, int component, int level); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Internal functions 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate static int fd_attach_check_drive(struct fdctlr *fdc); 1837c478bd9Sstevel@tonic-gate static int fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc); 1847c478bd9Sstevel@tonic-gate static int fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc); 1857c478bd9Sstevel@tonic-gate static int fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc, 1867c478bd9Sstevel@tonic-gate int *hard); 1877c478bd9Sstevel@tonic-gate static int fd_build_label_vtoc(struct fdunit *, struct vtoc *); 1887c478bd9Sstevel@tonic-gate static void fd_build_user_vtoc(struct fdunit *, struct vtoc *); 1897c478bd9Sstevel@tonic-gate static int fdcheckdisk(struct fdctlr *fdc, int unit); 1907c478bd9Sstevel@tonic-gate static int fd_check_media(dev_t dev, enum dkio_state state); 1917c478bd9Sstevel@tonic-gate static void fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard, 1927c478bd9Sstevel@tonic-gate int locks); 1937c478bd9Sstevel@tonic-gate static void fdeject(struct fdctlr *, int unit); 1947c478bd9Sstevel@tonic-gate static int fdexec(struct fdctlr *fdc, int flags); 1957c478bd9Sstevel@tonic-gate static void fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit); 1967c478bd9Sstevel@tonic-gate static int fdformat(struct fdctlr *fdc, int unit, int cyl, int hd); 1977c478bd9Sstevel@tonic-gate static caddr_t fd_getauxiova(); 1987c478bd9Sstevel@tonic-gate static struct fdctlr *fd_getctlr(dev_t); 1997c478bd9Sstevel@tonic-gate static void fdgetcsb(struct fdctlr *); 2007c478bd9Sstevel@tonic-gate static int fdgetlabel(struct fdctlr *fdc, int unit); 2017c478bd9Sstevel@tonic-gate enum dkio_state fd_get_media_state(struct fdctlr *, int); 2027c478bd9Sstevel@tonic-gate static uint_t fdintr_dma(); 2037c478bd9Sstevel@tonic-gate static int fd_isauxiodip(dev_info_t *); 2047c478bd9Sstevel@tonic-gate static uint_t fd_lointr(caddr_t arg); 2057c478bd9Sstevel@tonic-gate static void fd_media_watch(void *); 2067c478bd9Sstevel@tonic-gate static void fdmotoff(void *); 2077c478bd9Sstevel@tonic-gate static int fd_part_is_open(struct fdunit *un, int part); 2087c478bd9Sstevel@tonic-gate static int fdrawioctl(struct fdctlr *, int, intptr_t, int); 2097c478bd9Sstevel@tonic-gate static int fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg); 2107c478bd9Sstevel@tonic-gate static int fdrecover(struct fdctlr *); 2117c478bd9Sstevel@tonic-gate static void fdretcsb(struct fdctlr *); 2127c478bd9Sstevel@tonic-gate static int fdreset(struct fdctlr *); 2137c478bd9Sstevel@tonic-gate static int fdrw(struct fdctlr *fdc, int, int, int, int, int, caddr_t, uint_t); 2147c478bd9Sstevel@tonic-gate static void fdselect(struct fdctlr *fdc, int unit, int onoff); 2157c478bd9Sstevel@tonic-gate static int fdsensedrv(struct fdctlr *fdc, int unit); 2167c478bd9Sstevel@tonic-gate static int fdsense_chng(struct fdctlr *, int unit); 2177c478bd9Sstevel@tonic-gate static void fdstart(struct fdctlr *); 2187c478bd9Sstevel@tonic-gate static int fdstart_dma(register struct fdctlr *fdc, caddr_t addr, uint_t len); 2197c478bd9Sstevel@tonic-gate static int fd_unit_is_open(struct fdunit *); 2207c478bd9Sstevel@tonic-gate static void fdunpacklabel(struct packed_label *, struct dk_label *); 2217c478bd9Sstevel@tonic-gate static int fd_unbind_handle(struct fdctlr *); 2227c478bd9Sstevel@tonic-gate static void fdwatch(void *); 2237c478bd9Sstevel@tonic-gate static void set_rotational_speed(struct fdctlr *, int); 2247c478bd9Sstevel@tonic-gate static int fd_get_media_info(struct fdunit *un, caddr_t buf, int flag); 2257c478bd9Sstevel@tonic-gate static int fd_pm_lower_power(struct fdctlr *fdc); 2267c478bd9Sstevel@tonic-gate static int fd_pm_raise_power(struct fdctlr *fdc); 2277c478bd9Sstevel@tonic-gate static void create_pm_components(dev_info_t *dip); 2287c478bd9Sstevel@tonic-gate static void set_data_count_register(struct fdctlr *fdc, uint32_t count); 2297c478bd9Sstevel@tonic-gate static uint32_t get_data_count_register(struct fdctlr *fdc); 2307c478bd9Sstevel@tonic-gate static void reset_dma_controller(struct fdctlr *fdc); 2317c478bd9Sstevel@tonic-gate static void set_data_address_register(struct fdctlr *fdc, uint32_t address); 2327c478bd9Sstevel@tonic-gate static uint32_t get_dma_control_register(struct fdctlr *fdc); 2337c478bd9Sstevel@tonic-gate static void set_dma_mode(struct fdctlr *fdc, int val); 2347c478bd9Sstevel@tonic-gate static void set_dma_control_register(struct fdctlr *fdc, uint32_t val); 2357c478bd9Sstevel@tonic-gate static void release_sb_dma(struct fdctlr *fdc); 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * External functions 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate extern uint_t fd_intr(caddr_t); /* defined in fd_asm.s */ 2417c478bd9Sstevel@tonic-gate extern void set_auxioreg(); 2427c478bd9Sstevel@tonic-gate extern void call_debug(); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * The following macro checks whether the device in a SUSPENDED state. 2487c478bd9Sstevel@tonic-gate * As per WDD guide lines the I/O requests to a suspended device should 2497c478bd9Sstevel@tonic-gate * be blocked until the device is resumed. 2507c478bd9Sstevel@tonic-gate * Here we cv_wait on c_suspend_cv, and there is a cv_broadcast() in 2517c478bd9Sstevel@tonic-gate * DDI_RESUME to wake up this thread. 2527c478bd9Sstevel@tonic-gate * 2537c478bd9Sstevel@tonic-gate * NOTE: This code is not tested because the kernel threads are suspended 2547c478bd9Sstevel@tonic-gate * before the device is suspended. So there can not be any I/O requests on 2557c478bd9Sstevel@tonic-gate * a suspended device until the cpr implementation changes.. 2567c478bd9Sstevel@tonic-gate */ 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate #define CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc) \ 2597c478bd9Sstevel@tonic-gate {\ 2607c478bd9Sstevel@tonic-gate while (fdc->c_un->un_state == FD_STATE_SUSPENDED) {\ 2617c478bd9Sstevel@tonic-gate cv_wait(&fdc->c_suspend_cv, \ 2627c478bd9Sstevel@tonic-gate &fdc->c_lolock);\ 2637c478bd9Sstevel@tonic-gate }\ 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * bss (uninitialized data) 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate struct fdctlr *fdctlrs; /* linked list of controllers */ 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* 2727c478bd9Sstevel@tonic-gate * initialized data 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate static int fd_check_media_time = 5000000; /* 5 second state check */ 2767c478bd9Sstevel@tonic-gate static int fd_pollable = 0; 2777c478bd9Sstevel@tonic-gate static uchar_t rwretry = 10; 2787c478bd9Sstevel@tonic-gate static uchar_t skretry = 5; 2797c478bd9Sstevel@tonic-gate /* This variable allows the dynamic change of the burst size */ 2807c478bd9Sstevel@tonic-gate static int fd_burstsize = DCSR_BURST_0 | DCSR_BURST_1; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate static struct driver_minor_data { 2837c478bd9Sstevel@tonic-gate char *name; 2847c478bd9Sstevel@tonic-gate int minor; 2857c478bd9Sstevel@tonic-gate int type; 2867c478bd9Sstevel@tonic-gate } fd_minor [] = { 2877c478bd9Sstevel@tonic-gate { "a", 0, S_IFBLK}, 2887c478bd9Sstevel@tonic-gate { "b", 1, S_IFBLK}, 2897c478bd9Sstevel@tonic-gate { "c", 2, S_IFBLK}, 2907c478bd9Sstevel@tonic-gate { "a,raw", 0, S_IFCHR}, 2917c478bd9Sstevel@tonic-gate { "b,raw", 1, S_IFCHR}, 2927c478bd9Sstevel@tonic-gate { "c,raw", 2, S_IFCHR}, 2937c478bd9Sstevel@tonic-gate {0} 2947c478bd9Sstevel@tonic-gate }; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * If the interrupt handler is invoked and no controllers expect an 2987c478bd9Sstevel@tonic-gate * interrupt, the kernel panics. The following message is printed out. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate char *panic_msg = "fd_intr: unexpected interrupt\n"; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * Specify/Configure cmd parameters 3047c478bd9Sstevel@tonic-gate */ 3057c478bd9Sstevel@tonic-gate static uchar_t fdspec[2] = { 0xc2, 0x33 }; /* "specify" parameters */ 3067c478bd9Sstevel@tonic-gate static uchar_t fdconf[3] = { 0x64, 0x58, 0x00 }; /* "configure" parameters */ 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* When DMA is used, set the ND bit to 0 */ 3097c478bd9Sstevel@tonic-gate #define SPEC_DMA_MODE 0x32 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * default characteristics 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate static struct fd_char fdtypes[] = { 3157c478bd9Sstevel@tonic-gate { /* struct fd_char fdchar_1.7MB density */ 3167c478bd9Sstevel@tonic-gate 0, /* medium */ 3177c478bd9Sstevel@tonic-gate 500, /* transfer rate */ 3187c478bd9Sstevel@tonic-gate 80, /* number of cylinders */ 3197c478bd9Sstevel@tonic-gate 2, /* number of heads */ 3207c478bd9Sstevel@tonic-gate 512, /* sector size */ 3217c478bd9Sstevel@tonic-gate 21, /* sectors per track */ 3227c478bd9Sstevel@tonic-gate -1, /* (NA) # steps per data track */ 3237c478bd9Sstevel@tonic-gate }, 3247c478bd9Sstevel@tonic-gate { /* struct fd_char fdchar_highdens */ 3257c478bd9Sstevel@tonic-gate 0, /* medium */ 3267c478bd9Sstevel@tonic-gate 500, /* transfer rate */ 3277c478bd9Sstevel@tonic-gate 80, /* number of cylinders */ 3287c478bd9Sstevel@tonic-gate 2, /* number of heads */ 3297c478bd9Sstevel@tonic-gate 512, /* sector size */ 3307c478bd9Sstevel@tonic-gate 18, /* sectors per track */ 3317c478bd9Sstevel@tonic-gate -1, /* (NA) # steps per data track */ 3327c478bd9Sstevel@tonic-gate }, 3337c478bd9Sstevel@tonic-gate { /* struct fd_char fdchar_meddens */ 3347c478bd9Sstevel@tonic-gate 1, /* medium */ 3357c478bd9Sstevel@tonic-gate 500, /* transfer rate */ 3367c478bd9Sstevel@tonic-gate 77, /* number of cylinders */ 3377c478bd9Sstevel@tonic-gate 2, /* number of heads */ 3387c478bd9Sstevel@tonic-gate 1024, /* sector size */ 3397c478bd9Sstevel@tonic-gate 8, /* sectors per track */ 3407c478bd9Sstevel@tonic-gate -1, /* (NA) # steps per data track */ 3417c478bd9Sstevel@tonic-gate }, 3427c478bd9Sstevel@tonic-gate { /* struct fd_char fdchar_lowdens */ 3437c478bd9Sstevel@tonic-gate 0, /* medium */ 3447c478bd9Sstevel@tonic-gate 250, /* transfer rate */ 3457c478bd9Sstevel@tonic-gate 80, /* number of cylinders */ 3467c478bd9Sstevel@tonic-gate 2, /* number of heads */ 3477c478bd9Sstevel@tonic-gate 512, /* sector size */ 3487c478bd9Sstevel@tonic-gate 9, /* sectors per track */ 3497c478bd9Sstevel@tonic-gate -1, /* (NA) # steps per data track */ 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate }; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate static int nfdtypes = sizeof (fdtypes) / sizeof (fdtypes[0]); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * Default Label & partition maps 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_high_21 = { 3627c478bd9Sstevel@tonic-gate { "3.5\" floppy cyl 80 alt 0 hd 2 sec 21" }, 3637c478bd9Sstevel@tonic-gate 300, /* rotations per minute */ 3647c478bd9Sstevel@tonic-gate 80, /* # physical cylinders */ 3657c478bd9Sstevel@tonic-gate 0, /* alternates per cylinder */ 3667c478bd9Sstevel@tonic-gate 1, /* interleave factor */ 3677c478bd9Sstevel@tonic-gate 80, /* # of data cylinders */ 3687c478bd9Sstevel@tonic-gate 0, /* # of alternate cylinders */ 3697c478bd9Sstevel@tonic-gate 2, /* # of heads in this partition */ 3707c478bd9Sstevel@tonic-gate 21, /* # of 512 byte sectors per track */ 3717c478bd9Sstevel@tonic-gate { 3727c478bd9Sstevel@tonic-gate { 0, 79 * 2 * 21 }, /* part 0 - all but last cyl */ 3737c478bd9Sstevel@tonic-gate { 79, 1 * 2 * 21 }, /* part 1 - just the last cyl */ 3747c478bd9Sstevel@tonic-gate { 0, 80 * 2 * 21 }, /* part 2 - "the whole thing" */ 3757c478bd9Sstevel@tonic-gate }, 3767c478bd9Sstevel@tonic-gate { 0, /* version */ 3777c478bd9Sstevel@tonic-gate "", /* volume label */ 3787c478bd9Sstevel@tonic-gate 3, /* no. of partitions */ 3797c478bd9Sstevel@tonic-gate { 0 }, /* partition hdrs, sec 2 */ 3807c478bd9Sstevel@tonic-gate { 0 }, /* mboot info. unsupported */ 3817c478bd9Sstevel@tonic-gate VTOC_SANE, /* verify vtoc sanity */ 3827c478bd9Sstevel@tonic-gate { 0 }, /* reserved space */ 3837c478bd9Sstevel@tonic-gate 0, /* timestamp */ 3847c478bd9Sstevel@tonic-gate }, 3857c478bd9Sstevel@tonic-gate }; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_high_80 = { 3887c478bd9Sstevel@tonic-gate { "3.5\" floppy cyl 80 alt 0 hd 2 sec 18" }, 3897c478bd9Sstevel@tonic-gate 300, /* rotations per minute */ 3907c478bd9Sstevel@tonic-gate 80, /* # physical cylinders */ 3917c478bd9Sstevel@tonic-gate 0, /* alternates per cylinder */ 3927c478bd9Sstevel@tonic-gate 1, /* interleave factor */ 3937c478bd9Sstevel@tonic-gate 80, /* # of data cylinders */ 3947c478bd9Sstevel@tonic-gate 0, /* # of alternate cylinders */ 3957c478bd9Sstevel@tonic-gate 2, /* # of heads in this partition */ 3967c478bd9Sstevel@tonic-gate 18, /* # of 512 byte sectors per track */ 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate { 0, 79 * 2 * 18 }, /* part 0 - all but last cyl */ 3997c478bd9Sstevel@tonic-gate { 79, 1 * 2 * 18 }, /* part 1 - just the last cyl */ 4007c478bd9Sstevel@tonic-gate { 0, 80 * 2 * 18 }, /* part 2 - "the whole thing" */ 4017c478bd9Sstevel@tonic-gate }, 4027c478bd9Sstevel@tonic-gate { 0, /* version */ 4037c478bd9Sstevel@tonic-gate "", /* volume label */ 4047c478bd9Sstevel@tonic-gate 3, /* no. of partitions */ 4057c478bd9Sstevel@tonic-gate { 0 }, /* partition hdrs, sec 2 */ 4067c478bd9Sstevel@tonic-gate { 0 }, /* mboot info. unsupported */ 4077c478bd9Sstevel@tonic-gate VTOC_SANE, /* verify vtoc sanity */ 4087c478bd9Sstevel@tonic-gate { 0 }, /* reserved space */ 4097c478bd9Sstevel@tonic-gate 0, /* timestamp */ 4107c478bd9Sstevel@tonic-gate }, 4117c478bd9Sstevel@tonic-gate }; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * A medium density diskette has 1024 byte sectors. The dk_label structure 4157c478bd9Sstevel@tonic-gate * assumes a sector is DEVBSIZE (512) bytes. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_medium_80 = { 4187c478bd9Sstevel@tonic-gate { "3.5\" floppy cyl 77 alt 0 hd 2 sec 8" }, 4197c478bd9Sstevel@tonic-gate 360, /* rotations per minute */ 4207c478bd9Sstevel@tonic-gate 77, /* # physical cylinders */ 4217c478bd9Sstevel@tonic-gate 0, /* alternates per cylinder */ 4227c478bd9Sstevel@tonic-gate 1, /* interleave factor */ 4237c478bd9Sstevel@tonic-gate 77, /* # of data cylinders */ 4247c478bd9Sstevel@tonic-gate 0, /* # of alternate cylinders */ 4257c478bd9Sstevel@tonic-gate 2, /* # of heads in this partition */ 4267c478bd9Sstevel@tonic-gate 16, /* # of 512 byte sectors per track */ 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate { 0, 76 * 2 * 8 * 2 }, /* part 0 - all but last cyl */ 4297c478bd9Sstevel@tonic-gate { 76, 1 * 2 * 8 * 2 }, /* part 1 - just the last cyl */ 4307c478bd9Sstevel@tonic-gate { 0, 77 * 2 * 8 * 2 }, /* part 2 - "the whole thing" */ 4317c478bd9Sstevel@tonic-gate }, 4327c478bd9Sstevel@tonic-gate { 0, /* version */ 4337c478bd9Sstevel@tonic-gate "", /* volume label */ 4347c478bd9Sstevel@tonic-gate 3, /* no. of partitions */ 4357c478bd9Sstevel@tonic-gate { 0 }, /* partition hdrs, sec 2 */ 4367c478bd9Sstevel@tonic-gate { 0 }, /* mboot info. unsupported */ 4377c478bd9Sstevel@tonic-gate VTOC_SANE, /* verify vtoc sanity */ 4387c478bd9Sstevel@tonic-gate { 0 }, /* reserved space */ 4397c478bd9Sstevel@tonic-gate 0, /* timestamp */ 4407c478bd9Sstevel@tonic-gate }, 4417c478bd9Sstevel@tonic-gate }; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate static struct packed_label fdlbl_low_80 = { 4447c478bd9Sstevel@tonic-gate { "3.5\" floppy cyl 80 alt 0 hd 2 sec 9" }, 4457c478bd9Sstevel@tonic-gate 300, /* rotations per minute */ 4467c478bd9Sstevel@tonic-gate 80, /* # physical cylinders */ 4477c478bd9Sstevel@tonic-gate 0, /* alternates per cylinder */ 4487c478bd9Sstevel@tonic-gate 1, /* interleave factor */ 4497c478bd9Sstevel@tonic-gate 80, /* # of data cylinders */ 4507c478bd9Sstevel@tonic-gate 0, /* # of alternate cylinders */ 4517c478bd9Sstevel@tonic-gate 2, /* # of heads in this partition */ 4527c478bd9Sstevel@tonic-gate 9, /* # of 512 byte sectors per track */ 4537c478bd9Sstevel@tonic-gate { 4547c478bd9Sstevel@tonic-gate { 0, 79 * 2 * 9 }, /* part 0 - all but last cyl */ 4557c478bd9Sstevel@tonic-gate { 79, 1 * 2 * 9 }, /* part 1 - just the last cyl */ 4567c478bd9Sstevel@tonic-gate { 0, 80 * 2 * 9 }, /* part 2 - "the whole thing" */ 4577c478bd9Sstevel@tonic-gate }, 4587c478bd9Sstevel@tonic-gate { 0, /* version */ 4597c478bd9Sstevel@tonic-gate "", /* volume label */ 4607c478bd9Sstevel@tonic-gate 3, /* no. of partitions */ 4617c478bd9Sstevel@tonic-gate { 0 }, /* partition hdrs, sec 2 */ 4627c478bd9Sstevel@tonic-gate { 0 }, /* mboot info. unsupported */ 4637c478bd9Sstevel@tonic-gate VTOC_SANE, /* verify vtoc sanity */ 4647c478bd9Sstevel@tonic-gate { 0 }, /* reserved space */ 4657c478bd9Sstevel@tonic-gate 0, /* timestamp */ 4667c478bd9Sstevel@tonic-gate }, 4677c478bd9Sstevel@tonic-gate }; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate static struct fdcmdinfo { 4707c478bd9Sstevel@tonic-gate char *cmdname; /* command name */ 4717c478bd9Sstevel@tonic-gate uchar_t ncmdbytes; /* number of bytes of command */ 4727c478bd9Sstevel@tonic-gate uchar_t nrsltbytes; /* number of bytes in result */ 4737c478bd9Sstevel@tonic-gate uchar_t cmdtype; /* characteristics */ 4747c478bd9Sstevel@tonic-gate } fdcmds[] = { 4757c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 4767c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 4777c478bd9Sstevel@tonic-gate "read_track", 9, 7, 1, /* 2 */ 4787c478bd9Sstevel@tonic-gate "specify", 3, 0, 3, /* 3 */ 4797c478bd9Sstevel@tonic-gate "sense_drv_status", 2, 1, 3, /* 4 */ 4807c478bd9Sstevel@tonic-gate "write", 9, 7, 1, /* 5 */ 4817c478bd9Sstevel@tonic-gate "read", 9, 7, 1, /* 6 */ 4827c478bd9Sstevel@tonic-gate "recalibrate", 2, 0, 2, /* 7 */ 4837c478bd9Sstevel@tonic-gate "sense_int_status", 1, 2, 3, /* 8 */ 4847c478bd9Sstevel@tonic-gate "write_del", 9, 7, 1, /* 9 */ 4857c478bd9Sstevel@tonic-gate "read_id", 2, 7, 2, /* A */ 4867c478bd9Sstevel@tonic-gate "motor_on/off", 1, 0, 4, /* B */ 4877c478bd9Sstevel@tonic-gate "read_del", 9, 7, 1, /* C */ 4887c478bd9Sstevel@tonic-gate "format_track", 10, 7, 1, /* D */ 4897c478bd9Sstevel@tonic-gate "dump_reg", 1, 10, 4, /* E */ 4907c478bd9Sstevel@tonic-gate "seek", 3, 0, 2, /* F */ 4917c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 4927c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 4937c478bd9Sstevel@tonic-gate "", 0, 0, 0, /* - */ 4947c478bd9Sstevel@tonic-gate "configure", 4, 0, 4, /* 13 */ 4957c478bd9Sstevel@tonic-gate /* relative seek */ 4967c478bd9Sstevel@tonic-gate }; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate static struct cb_ops fd_cb_ops = { 4997c478bd9Sstevel@tonic-gate fd_open, /* open */ 5007c478bd9Sstevel@tonic-gate fd_close, /* close */ 5017c478bd9Sstevel@tonic-gate fd_strategy, /* strategy */ 5027c478bd9Sstevel@tonic-gate nodev, /* print */ 5037c478bd9Sstevel@tonic-gate nodev, /* dump */ 5047c478bd9Sstevel@tonic-gate fd_read, /* read */ 5057c478bd9Sstevel@tonic-gate fd_write, /* write */ 5067c478bd9Sstevel@tonic-gate fd_ioctl, /* ioctl */ 5077c478bd9Sstevel@tonic-gate nodev, /* devmap */ 5087c478bd9Sstevel@tonic-gate nodev, /* mmap */ 5097c478bd9Sstevel@tonic-gate nodev, /* segmap */ 5107c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 5117c478bd9Sstevel@tonic-gate fd_prop_op, /* cb_prop_op */ 5127c478bd9Sstevel@tonic-gate 0, /* streamtab */ 5137c478bd9Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 5147c478bd9Sstevel@tonic-gate }; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate static struct dev_ops fd_ops = { 5177c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 5187c478bd9Sstevel@tonic-gate 0, /* refcnt */ 5197c478bd9Sstevel@tonic-gate fd_info, /* info */ 5207c478bd9Sstevel@tonic-gate nulldev, /* identify */ 5217c478bd9Sstevel@tonic-gate nulldev, /* probe */ 5227c478bd9Sstevel@tonic-gate fd_attach, /* attach */ 5237c478bd9Sstevel@tonic-gate fd_detach, /* detach */ 5247c478bd9Sstevel@tonic-gate nodev, /* reset */ 5257c478bd9Sstevel@tonic-gate &fd_cb_ops, /* driver operations */ 5267c478bd9Sstevel@tonic-gate (struct bus_ops *)0, /* bus operations */ 52719397407SSherry Moore fd_power, /* power */ 52819397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 5297c478bd9Sstevel@tonic-gate }; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * error handling 5347c478bd9Sstevel@tonic-gate * 5357c478bd9Sstevel@tonic-gate * for debugging, set rwretry and skretry = 1 5367c478bd9Sstevel@tonic-gate * set fderrlevel to 1 5377c478bd9Sstevel@tonic-gate * set fderrmask to 224 or 100644 5387c478bd9Sstevel@tonic-gate * 5397c478bd9Sstevel@tonic-gate * after debug set rwretry to 10, skretry to 5, and fderrlevel to 3 5407c478bd9Sstevel@tonic-gate * set fderrmask to FDEM_ALL 5417c478bd9Sstevel@tonic-gate * remove the define FD_DEBUG 5427c478bd9Sstevel@tonic-gate * 5437c478bd9Sstevel@tonic-gate */ 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate static unsigned int fderrmask = (unsigned int)FDEM_ALL; 5467c478bd9Sstevel@tonic-gate static int fderrlevel = 3; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate static int tosec = 16; /* long timeouts for sundiag for now */ 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * loadable module support 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 5577c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 5587c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. driver here */ 55919397407SSherry Moore "Floppy Driver", /* Name of the module. */ 5607c478bd9Sstevel@tonic-gate &fd_ops, /* Driver ops vector */ 5617c478bd9Sstevel@tonic-gate }; 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 5647c478bd9Sstevel@tonic-gate MODREV_1, 5657c478bd9Sstevel@tonic-gate &modldrv, 5667c478bd9Sstevel@tonic-gate NULL 5677c478bd9Sstevel@tonic-gate }; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate int 5707c478bd9Sstevel@tonic-gate _init(void) 5717c478bd9Sstevel@tonic-gate { 5727c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate int 5767c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 5777c478bd9Sstevel@tonic-gate { 5787c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate int 5827c478bd9Sstevel@tonic-gate _fini(void) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate int e; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) 5877c478bd9Sstevel@tonic-gate return (e); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* ddi_soft_state_fini() */ 5907c478bd9Sstevel@tonic-gate return (0); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5947c478bd9Sstevel@tonic-gate static int 5957c478bd9Sstevel@tonic-gate fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 5987c478bd9Sstevel@tonic-gate struct driver_minor_data *dmdp; 5997c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 6007c478bd9Sstevel@tonic-gate int hard_intr_set = 0; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: start\n")); 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate switch (cmd) { 6057c478bd9Sstevel@tonic-gate case DDI_ATTACH: 6067c478bd9Sstevel@tonic-gate break; 6077c478bd9Sstevel@tonic-gate case DDI_RESUME: 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate if (!(fdc = fd_getctlr(instance << FDINSTSHIFT))) { 6107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate quiesce_fd_interrupt(fdc); 6137c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) 6147c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, &fdc->c_block, 0, 6157c478bd9Sstevel@tonic-gate fdintr_dma, (caddr_t)0) != DDI_SUCCESS) { 6167c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, PM_LEVEL_ON); 6207c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 6217c478bd9Sstevel@tonic-gate /* 6227c478bd9Sstevel@tonic-gate * Wake up any thread blocked due to I/O requests 6237c478bd9Sstevel@tonic-gate * while the device was suspended. 6247c478bd9Sstevel@tonic-gate */ 6257c478bd9Sstevel@tonic-gate cv_broadcast(&fdc->c_suspend_cv); 6267c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 6277c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate default: 6307c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* 6357c478bd9Sstevel@tonic-gate * Check for the pollable property 6367c478bd9Sstevel@tonic-gate * A pollable floppy drive currently only exists on the 6377c478bd9Sstevel@tonic-gate * Sparcstation Voyager. This drive does not need to 6387c478bd9Sstevel@tonic-gate * be turned on in order to sense whether or not a diskette 6397c478bd9Sstevel@tonic-gate * is present. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, dip, 6427c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, FD_POLLABLE_PROP, 0)) 6437c478bd9Sstevel@tonic-gate fd_pollable = 1; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate fdc = kmem_zalloc(sizeof (*fdc), KM_SLEEP); 6467c478bd9Sstevel@tonic-gate fdc->c_dip = dip; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate fdc->c_next = fdctlrs; 6507c478bd9Sstevel@tonic-gate fdctlrs = fdc; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* Determine which type of controller is present and initialize it */ 6537c478bd9Sstevel@tonic-gate if (fd_attach_det_ctlr(dip, fdc) == DDI_FAILURE) { 6547c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, hard_intr_set, 0); 6557c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate /* Finish mapping the device registers & setting up structures */ 6587c478bd9Sstevel@tonic-gate if (fd_attach_map_regs(dip, fdc) == DDI_FAILURE) { 6597c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, hard_intr_set, 0); 6607c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Initialize the DMA limit structures if it's being used. 6657c478bd9Sstevel@tonic-gate */ 6667c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 6677c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_version = DMA_ATTR_V0; 6687c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_addr_lo = 0x00000000ull; 6697c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_addr_hi = 0xfffffffeull; 6707c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_count_max = 0xffffff; 6717c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 6727c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_align = FD_SB_DMA_ALIGN; 6737c478bd9Sstevel@tonic-gate } else { 6747c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_align = 1; 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_burstsizes = 0x0; 6777c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_minxfer = 1; 6787c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_maxxfer = 0xffff; 6797c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_seg = 0xffff; 6807c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_sgllen = 1; 6817c478bd9Sstevel@tonic-gate fdc->c_fd_dma_lim.dma_attr_granular = 512; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(dip, &fdc->c_fd_dma_lim, 6847c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, 0, &fdc->c_dmahandle) != DDI_SUCCESS) { 6857c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, hard_intr_set, 0); 6867c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 6907c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 6917c478bd9Sstevel@tonic-gate size_t rlen; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6947c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 6957c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(fdc->c_dmahandle, 6987c478bd9Sstevel@tonic-gate (size_t)(32*1024), &dev_attr, DDI_DMA_CONSISTENT, 6997c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, (caddr_t *)&fdc->dma_buf, 7007c478bd9Sstevel@tonic-gate &rlen, &fdc->c_dma_buf_handle) != DDI_SUCCESS) { 7017c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, hard_intr_set, 0); 7027c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* Register the interrupts */ 7107c478bd9Sstevel@tonic-gate if (fd_attach_register_interrupts(dip, fdc, 7117c478bd9Sstevel@tonic-gate &hard_intr_set) == DDI_FAILURE) { 7127c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, hard_intr_set, 0); 7137c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 7147c478bd9Sstevel@tonic-gate (C, "fd_attach: registering interrupts failed\n")); 7157c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * set initial controller/drive/disk "characteristics/geometry" 7217c478bd9Sstevel@tonic-gate * 7227c478bd9Sstevel@tonic-gate * NOTE: The driver only supports one floppy drive. The hardware 7237c478bd9Sstevel@tonic-gate * only supports one drive because there is only one auxio register 7247c478bd9Sstevel@tonic-gate * for one drive. 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate fdc->c_un = kmem_zalloc(sizeof (struct fdunit), KM_SLEEP); 7277c478bd9Sstevel@tonic-gate fdc->c_un->un_chars = kmem_alloc(sizeof (struct fd_char), KM_SLEEP); 7287c478bd9Sstevel@tonic-gate fdc->c_un->un_iostat = kstat_create("fd", 0, "fd0", "disk", 7297c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 7307c478bd9Sstevel@tonic-gate if (fdc->c_un->un_iostat) { 7317c478bd9Sstevel@tonic-gate fdc->c_un->un_iostat->ks_lock = &fdc->c_lolock; 7327c478bd9Sstevel@tonic-gate kstat_install(fdc->c_un->un_iostat); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate fdc->c_un->un_drive = kmem_zalloc(sizeof (struct fd_drive), KM_SLEEP); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* check for the manual eject property */ 7387c478bd9Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, dip, 7397c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, FD_MANUAL_EJECT, 0)) { 7407c478bd9Sstevel@tonic-gate fdc->c_un->un_drive->fdd_ejectable = 0; 7417c478bd9Sstevel@tonic-gate } else { 7427c478bd9Sstevel@tonic-gate /* an absence of the property indicates auto eject */ 7437c478bd9Sstevel@tonic-gate fdc->c_un->un_drive->fdd_ejectable = -1; 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: ejectable? %d\n", 7477c478bd9Sstevel@tonic-gate fdc->c_un->un_drive->fdd_ejectable)); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate /* 7507c478bd9Sstevel@tonic-gate * Check for the drive id. If the drive id property doesn't exist 7517c478bd9Sstevel@tonic-gate * then the drive id is set to 0 7527c478bd9Sstevel@tonic-gate */ 7537c478bd9Sstevel@tonic-gate fdc->c_un->un_unit_no = ddi_getprop(DDI_DEV_T_ANY, dip, 7547c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, FD_UNIT, 0); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 7587c478bd9Sstevel@tonic-gate fdc->sb_dma_channel = ddi_getprop(DDI_DEV_T_ANY, dip, 7597c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "dma-channel", 0); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: unit %d\n", 7647c478bd9Sstevel@tonic-gate fdc->c_un->un_unit_no)); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* Initially set the characteristics to high density */ 7677c478bd9Sstevel@tonic-gate fdc->c_un->un_curfdtype = 1; 7687c478bd9Sstevel@tonic-gate *fdc->c_un->un_chars = fdtypes[fdc->c_un->un_curfdtype]; 7697c478bd9Sstevel@tonic-gate fdunpacklabel(&fdlbl_high_80, &fdc->c_un->un_label); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* Make sure drive is present */ 7727c478bd9Sstevel@tonic-gate if (fd_attach_check_drive(fdc) == DDI_FAILURE) { 7737c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, hard_intr_set, 1); 7747c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) { 7787c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, dmdp->name, dmdp->type, 7797c478bd9Sstevel@tonic-gate (instance << FDINSTSHIFT) | dmdp->minor, 7807c478bd9Sstevel@tonic-gate DDI_NT_FD, 0) == DDI_FAILURE) { 7817c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, hard_intr_set, 1); 7827c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate create_pm_components(dip); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * Add a zero-length attribute to tell the world we support 7907c478bd9Sstevel@tonic-gate * kernel ioctls (for layered drivers) 7917c478bd9Sstevel@tonic-gate */ 7927c478bd9Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 7937c478bd9Sstevel@tonic-gate DDI_KERNEL_IOCTL, NULL, 0); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 7987c478bd9Sstevel@tonic-gate (C, "attached 0x%x\n", ddi_get_instance(dip))); 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate /* 8047c478bd9Sstevel@tonic-gate * Finish mapping the registers and initializing structures 8057c478bd9Sstevel@tonic-gate */ 8067c478bd9Sstevel@tonic-gate static int 8077c478bd9Sstevel@tonic-gate fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc) 8087c478bd9Sstevel@tonic-gate { 8097c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 8127c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 8137c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate /* Map the DMA registers of the platform supports DMA */ 8167c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 8177c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs, 8187c478bd9Sstevel@tonic-gate 0, sizeof (struct sb_dma_reg), &attr, 8197c478bd9Sstevel@tonic-gate &fdc->c_handlep_dma)) { 8207c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate } else if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 8257c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs, 8267c478bd9Sstevel@tonic-gate 0, sizeof (struct cheerio_dma_reg), &attr, 8277c478bd9Sstevel@tonic-gate &fdc->c_handlep_dma)) { 8287c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* Reset the DMA engine and enable floppy interrupts */ 8337c478bd9Sstevel@tonic-gate reset_dma_controller(fdc); 8347c478bd9Sstevel@tonic-gate set_dma_control_register(fdc, DCSR_INIT_BITS); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* Finish initializing structures associated with the device regs */ 8377c478bd9Sstevel@tonic-gate switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) { 8387c478bd9Sstevel@tonic-gate case FDCTYPE_82077: 8397c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "type is 82077\n")); 8407c478bd9Sstevel@tonic-gate /* 8417c478bd9Sstevel@tonic-gate * Initialize addrs of key registers 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate fdc->c_control = 8447c478bd9Sstevel@tonic-gate (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_control; 8457c478bd9Sstevel@tonic-gate fdc->c_fifo = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_fifo; 8467c478bd9Sstevel@tonic-gate fdc->c_dor = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dor; 8477c478bd9Sstevel@tonic-gate fdc->c_dir = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dir; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, ((int)C, 8517c478bd9Sstevel@tonic-gate (char *)"fdattach: msr/dsr at %p\n", 8527c478bd9Sstevel@tonic-gate (void *)fdc->c_control)); 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * The 82077 doesn't use the first configuration parameter 8567c478bd9Sstevel@tonic-gate * so let's adjust that while we know we're an 82077. 8577c478bd9Sstevel@tonic-gate */ 8587c478bd9Sstevel@tonic-gate fdconf[0] = 0; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate quiesce_fd_interrupt(fdc); 8617c478bd9Sstevel@tonic-gate break; 8627c478bd9Sstevel@tonic-gate default: 8637c478bd9Sstevel@tonic-gate break; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate return (0); 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate /* 8707c478bd9Sstevel@tonic-gate * Determine which type of floppy controller is present and 8717c478bd9Sstevel@tonic-gate * initialize the registers accordingly 8727c478bd9Sstevel@tonic-gate */ 8737c478bd9Sstevel@tonic-gate static int 8747c478bd9Sstevel@tonic-gate fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc) 8757c478bd9Sstevel@tonic-gate { 8767c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 8777c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 8787c478bd9Sstevel@tonic-gate /* DDI_NEVERSWAP_ACC since the controller has a byte interface. */ 8797c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 8807c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 8837c478bd9Sstevel@tonic-gate (C, "fdattach_det_cltr: start \n")); 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* 8867c478bd9Sstevel@tonic-gate * First, map in the controller's registers 8877c478bd9Sstevel@tonic-gate * The controller has an 8-bit interface, so byte 8887c478bd9Sstevel@tonic-gate * swapping isn't needed 8897c478bd9Sstevel@tonic-gate */ 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0, (caddr_t *)&fdc->c_reg, 8927c478bd9Sstevel@tonic-gate 0, sizeof (union fdcreg), 8937c478bd9Sstevel@tonic-gate &attr, 8947c478bd9Sstevel@tonic-gate &fdc->c_handlep_cont)) { 8957c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 8997c478bd9Sstevel@tonic-gate (C, "fdattach_det_cltr: mapped floppy regs\n")); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* 9037c478bd9Sstevel@tonic-gate * Set platform specific characteristics based on the device-tree 9047c478bd9Sstevel@tonic-gate * node name. 9057c478bd9Sstevel@tonic-gate */ 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate if (strcmp(ddi_get_name(dip), "SUNW,fdtwo") == 0) { 9097c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_SLAVIO; 9107c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_82077; 9117c478bd9Sstevel@tonic-gate fdc->c_auxiova = fd_getauxiova(dip); 9127c478bd9Sstevel@tonic-gate fdc->c_auxiodata = (uchar_t)(AUX_MBO4M|AUX_TC4M); 9137c478bd9Sstevel@tonic-gate fdc->c_auxiodata2 = (uchar_t)AUX_TC4M; 9147c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 9157c478bd9Sstevel@tonic-gate (C, "fdattach: slavio will be used!\n")); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate /* 9197c478bd9Sstevel@tonic-gate * Check the binding name to identify whether it is a South bridge based 9207c478bd9Sstevel@tonic-gate * system or not. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate } else if (strcmp(ddi_get_name(dip), "pnpALI,1533,0") == 0) { 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_SB; 9257c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_82077; 9267c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_DMA; 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 9297c478bd9Sstevel@tonic-gate (C, "fdattach: southbridge will be used!\n")); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate /* 9327c478bd9Sstevel@tonic-gate * The driver assumes high density characteristics until 9337c478bd9Sstevel@tonic-gate * the diskette is looked at. 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_DMA8237; 9377c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n")); 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate } else if (strcmp(ddi_get_name(dip), "fdthree") == 0) { 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_CHEERIO; 9437c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_82077; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 9467c478bd9Sstevel@tonic-gate (C, "fdattach: cheerio will be used!\n")); 9477c478bd9Sstevel@tonic-gate /* 9487c478bd9Sstevel@tonic-gate * The cheerio auxio register should be memory mapped. The 9497c478bd9Sstevel@tonic-gate * auxio register on other platforms is shared and mapped 9507c478bd9Sstevel@tonic-gate * elsewhere in the kernel 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 2, (caddr_t *)&fdc->c_auxio_reg, 9537c478bd9Sstevel@tonic-gate 0, sizeof (uint_t), &attr, &fdc->c_handlep_aux)) { 9547c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* 9587c478bd9Sstevel@tonic-gate * The driver assumes high density characteristics until 9597c478bd9Sstevel@tonic-gate * the diskette is looked at. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate Set_auxio(fdc, AUX_HIGH_DENSITY); 9627c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 9637c478bd9Sstevel@tonic-gate (C, "fdattach: auxio register 0x%x\n", 9647c478bd9Sstevel@tonic-gate *fdc->c_auxio_reg)); 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate fdc->c_fdtype |= FDCTYPE_DMA; 9677c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n")); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate if (fdc->c_fdtype == 0) { 9727c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 9737c478bd9Sstevel@tonic-gate (C, "fdattach: no controller!\n")); 9747c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9757c478bd9Sstevel@tonic-gate } else { 9767c478bd9Sstevel@tonic-gate return (0); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * Register the floppy interrupts 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate static int 9857c478bd9Sstevel@tonic-gate fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc, int *hard) 9867c478bd9Sstevel@tonic-gate { 9877c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie_soft; 9887c478bd9Sstevel@tonic-gate int status; 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * First call ddi_get_iblock_cookie() to retrieve the 9927c478bd9Sstevel@tonic-gate * the interrupt block cookie so that the mutexes may 9937c478bd9Sstevel@tonic-gate * be initialized before adding the interrupt. If the 9947c478bd9Sstevel@tonic-gate * mutexes are initialized after adding the interrupt, there 9957c478bd9Sstevel@tonic-gate * could be a race condition. 9967c478bd9Sstevel@tonic-gate */ 9977c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, 0, &fdc->c_block) != DDI_SUCCESS) { 9987c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 9997c478bd9Sstevel@tonic-gate (C, "fdattach: ddi_get_iblock_cookie failed\n")); 10007c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* Initialize high level mutex */ 10057c478bd9Sstevel@tonic-gate mutex_init(&fdc->c_hilock, NULL, MUTEX_DRIVER, fdc->c_block); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * Try to register fast trap handler, if unable try standard 10097c478bd9Sstevel@tonic-gate * interrupt handler, else bad 10107c478bd9Sstevel@tonic-gate */ 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 10137c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, &fdc->c_block, 0, 10147c478bd9Sstevel@tonic-gate fdintr_dma, (caddr_t)0) == DDI_SUCCESS) { 10157c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 10167c478bd9Sstevel@tonic-gate (C, "fdattach: standard intr\n")); 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate /* 10197c478bd9Sstevel@tonic-gate * When DMA is used, the low level lock 10207c478bd9Sstevel@tonic-gate * is used in the hard interrupt handler. 10217c478bd9Sstevel@tonic-gate */ 10227c478bd9Sstevel@tonic-gate mutex_init(&fdc->c_lolock, NULL, 10237c478bd9Sstevel@tonic-gate MUTEX_DRIVER, fdc->c_block); 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate *hard = 1; 10267c478bd9Sstevel@tonic-gate } else { 10277c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 10287c478bd9Sstevel@tonic-gate (C, "fdattach: can't add dma intr\n")); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate mutex_destroy(&fdc->c_hilock); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate } else { 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Platforms that don't support DMA have both hard 10377c478bd9Sstevel@tonic-gate * and soft interrupts. 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, &fdc->c_block, 0, 10407c478bd9Sstevel@tonic-gate fd_intr, (caddr_t)0) == DDI_SUCCESS) { 10417c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 10427c478bd9Sstevel@tonic-gate (C, "fdattach: standard intr\n")); 10437c478bd9Sstevel@tonic-gate *hard = 1; 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* fast traps are not enabled */ 10467c478bd9Sstevel@tonic-gate fdc->c_fasttrap = 0; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate } else { 10497c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 10507c478bd9Sstevel@tonic-gate (C, "fdattach: can't add intr\n")); 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate mutex_destroy(&fdc->c_hilock); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate /* 10597c478bd9Sstevel@tonic-gate * Initialize the soft interrupt handler. First call 10607c478bd9Sstevel@tonic-gate * ddi_get_soft_iblock_cookie() so that the mutex may 10617c478bd9Sstevel@tonic-gate * be initialized before the handler is added. 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate status = ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW, 10647c478bd9Sstevel@tonic-gate &iblock_cookie_soft); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) { 10687c478bd9Sstevel@tonic-gate mutex_destroy(&fdc->c_hilock); 10697c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * Initialize low level mutex which is used in the soft 10747c478bd9Sstevel@tonic-gate * interrupt handler 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate mutex_init(&fdc->c_lolock, NULL, MUTEX_DRIVER, 10777c478bd9Sstevel@tonic-gate iblock_cookie_soft); 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &fdc->c_softid, 10807c478bd9Sstevel@tonic-gate NULL, NULL, 10817c478bd9Sstevel@tonic-gate fd_lointr, 10827c478bd9Sstevel@tonic-gate (caddr_t)fdc) != DDI_SUCCESS) { 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate mutex_destroy(&fdc->c_hilock); 10857c478bd9Sstevel@tonic-gate mutex_destroy(&fdc->c_lolock); 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate fdc->c_intrstat = kstat_create("fd", 0, "fdc0", "controller", 10927c478bd9Sstevel@tonic-gate KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 10937c478bd9Sstevel@tonic-gate if (fdc->c_intrstat) { 10947c478bd9Sstevel@tonic-gate fdc->c_hiintct = &KIOIP->intrs[KSTAT_INTR_HARD]; 10957c478bd9Sstevel@tonic-gate kstat_install(fdc->c_intrstat); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* condition variable to wait on while an io transaction occurs */ 10997c478bd9Sstevel@tonic-gate cv_init(&fdc->c_iocv, NULL, CV_DRIVER, NULL); 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate /* condition variable for the csb */ 11027c478bd9Sstevel@tonic-gate cv_init(&fdc->c_csbcv, NULL, CV_DRIVER, NULL); 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* condition variable for motor on waiting period */ 11057c478bd9Sstevel@tonic-gate cv_init(&fdc->c_motoncv, NULL, CV_DRIVER, NULL); 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate /* semaphore to serialize opens and closes */ 11087c478bd9Sstevel@tonic-gate sema_init(&fdc->c_ocsem, 1, NULL, SEMA_DRIVER, NULL); 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* condition variable to wait on suspended floppy controller. */ 11117c478bd9Sstevel@tonic-gate cv_init(&fdc->c_suspend_cv, NULL, CV_DRIVER, NULL); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate return (0); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate /* 11177c478bd9Sstevel@tonic-gate * Make sure the drive is present 11187c478bd9Sstevel@tonic-gate * - acquires the low level lock 11197c478bd9Sstevel@tonic-gate */ 11207c478bd9Sstevel@tonic-gate static int 11217c478bd9Sstevel@tonic-gate fd_attach_check_drive(struct fdctlr *fdc) 11227c478bd9Sstevel@tonic-gate { 11237c478bd9Sstevel@tonic-gate int tmp_fderrlevel; 11247c478bd9Sstevel@tonic-gate int unit = fdc->c_un->un_unit_no; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 11277c478bd9Sstevel@tonic-gate (C, "fd_attach_check_drive\n")); 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 11317c478bd9Sstevel@tonic-gate switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) { 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate /* insure that the eject line is reset */ 11347c478bd9Sstevel@tonic-gate case FDCTYPE_82077: 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * Everything but the motor enable, drive select, 11387c478bd9Sstevel@tonic-gate * and reset bits are turned off. These three 11397c478bd9Sstevel@tonic-gate * bits remain as they are. 11407c478bd9Sstevel@tonic-gate */ 11417c478bd9Sstevel@tonic-gate /* LINTED */ 11427c478bd9Sstevel@tonic-gate Set_dor(fdc, ~((MOTEN(unit))|DRVSEL|RESET), 0); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 11457c478bd9Sstevel@tonic-gate (C, "fdattach: Dor 0x%x\n", Dor(fdc))); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate drv_usecwait(5); 11487c478bd9Sstevel@tonic-gate if (unit == 0) { 11497c478bd9Sstevel@tonic-gate /* LINTED */ 11507c478bd9Sstevel@tonic-gate Set_dor(fdc, RESET|DRVSEL, 1); 11517c478bd9Sstevel@tonic-gate } else { 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* LINTED */ 11547c478bd9Sstevel@tonic-gate Set_dor(fdc, DRVSEL, 0); 11557c478bd9Sstevel@tonic-gate /* LINTED */ 11567c478bd9Sstevel@tonic-gate Set_dor(fdc, RESET, 1); 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate drv_usecwait(5); 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 11627c478bd9Sstevel@tonic-gate (C, "fdattach: Dor 0x%x\n", Dor(fdc))); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate if (!((fdc->c_fdtype & FDCTYPE_CHEERIO) || 11657c478bd9Sstevel@tonic-gate (fdc->c_fdtype & FDCTYPE_SB))) { 11667c478bd9Sstevel@tonic-gate set_auxioreg(AUX_TC4M, 0); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate break; 11697c478bd9Sstevel@tonic-gate default: 11707c478bd9Sstevel@tonic-gate break; 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 11757c478bd9Sstevel@tonic-gate if (fdreset(fdc) != 0) { 11767c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 11777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* check for drive present */ 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate tmp_fderrlevel = fderrlevel; 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate fderrlevel = FDEP_LMAX; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 11897c478bd9Sstevel@tonic-gate (C, "fdattach: call fdrecalseek\n")); 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate /* Make sure the drive is present */ 11927c478bd9Sstevel@tonic-gate if (fdrecalseek(fdc, unit, -1, 0) != 0) { 11937c478bd9Sstevel@tonic-gate timeout_id_t timeid = fdc->c_mtimeid; 11947c478bd9Sstevel@tonic-gate fderrlevel = tmp_fderrlevel; 11957c478bd9Sstevel@tonic-gate fdc->c_mtimeid = 0; 11967c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* Do not hold the mutex over the call to untimeout */ 12007c478bd9Sstevel@tonic-gate if (timeid) { 12017c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_ATTA, 12057c478bd9Sstevel@tonic-gate (C, "fd_attach: no drive?\n")); 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate fderrlevel = tmp_fderrlevel; 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 0); /* deselect drive zero (used in fdreset) */ 12137c478bd9Sstevel@tonic-gate fdretcsb(fdc); 12147c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate return (0); 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * Clean up routine used by fd_detach and fd_attach 12217c478bd9Sstevel@tonic-gate * 12227c478bd9Sstevel@tonic-gate * Note: if the soft id is non-zero, then ddi_add_softintr() completed 12237c478bd9Sstevel@tonic-gate * successfully. I can not make the same assumption about the iblock_cookie 12247c478bd9Sstevel@tonic-gate * for the high level interrupt handler. So, the hard parameter indicates 12257c478bd9Sstevel@tonic-gate * whether or not a high level interrupt handler has been added. 12267c478bd9Sstevel@tonic-gate * 12277c478bd9Sstevel@tonic-gate * If the locks parameter is nonzero, then all mutexes, semaphores and 12287c478bd9Sstevel@tonic-gate * condition variables will be destroyed. 12297c478bd9Sstevel@tonic-gate * 12307c478bd9Sstevel@tonic-gate * Does not assume the low level mutex is held. 12317c478bd9Sstevel@tonic-gate * 12327c478bd9Sstevel@tonic-gate */ 12337c478bd9Sstevel@tonic-gate static void 12347c478bd9Sstevel@tonic-gate fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard, int locks) 12357c478bd9Sstevel@tonic-gate { 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 123929df58e5Spc157239 (C, "fd_cleanup instance: %d ctlr: 0x%p\n", 124029df58e5Spc157239 ddi_get_instance(dip), (void *)fdc)); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (fdc == NULL) { 12447c478bd9Sstevel@tonic-gate return; 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate /* 12487c478bd9Sstevel@tonic-gate * Remove interrupt handlers first before anything else 12497c478bd9Sstevel@tonic-gate * is deallocated. 12507c478bd9Sstevel@tonic-gate */ 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate /* Remove hard interrupt if one is registered */ 12537c478bd9Sstevel@tonic-gate if (hard) { 12547c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, (uint_t)0, fdc->c_block); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* Remove soft interrupt if one is registered */ 12587c478bd9Sstevel@tonic-gate if (fdc->c_softid != NULL) 12597c478bd9Sstevel@tonic-gate ddi_remove_softintr(fdc->c_softid); 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* Remove timers */ 12637c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_82077) { 12647c478bd9Sstevel@tonic-gate if (fdc->c_mtimeid) 12657c478bd9Sstevel@tonic-gate (void) untimeout(fdc->c_mtimeid); 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Need to turn off motor (includes select/LED for South Bridge 12687c478bd9Sstevel@tonic-gate * chipset) just in case it was on when timer was removed 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate fdmotoff(fdc); 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate if (fdc->c_timeid) 12737c478bd9Sstevel@tonic-gate (void) untimeout(fdc->c_timeid); 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate /* Remove memory handles */ 12777c478bd9Sstevel@tonic-gate if (fdc->c_handlep_cont) 12787c478bd9Sstevel@tonic-gate ddi_regs_map_free(&fdc->c_handlep_cont); 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate if (fdc->c_handlep_aux) 12817c478bd9Sstevel@tonic-gate ddi_regs_map_free(&fdc->c_handlep_aux); 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate if (fdc->c_handlep_dma) 12847c478bd9Sstevel@tonic-gate ddi_regs_map_free(&fdc->c_handlep_dma); 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate if (fdc->c_dma_buf_handle != NULL) 12877c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&fdc->c_dma_buf_handle); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate if (fdc->c_dmahandle != NULL) 12907c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&fdc->c_dmahandle); 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate /* Remove all minor nodes */ 12947c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate /* Remove unit structure if one exists */ 12997c478bd9Sstevel@tonic-gate if (fdc->c_un != (struct fdunit *)NULL) { 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&fdc->c_lolock)); 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate if (fdc->c_un->un_iostat) 13047c478bd9Sstevel@tonic-gate kstat_delete(fdc->c_un->un_iostat); 13057c478bd9Sstevel@tonic-gate fdc->c_un->un_iostat = NULL; 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate if (fdc->c_un->un_chars) 13087c478bd9Sstevel@tonic-gate kmem_free(fdc->c_un->un_chars, sizeof (struct fd_char)); 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate if (fdc->c_un->un_drive) 13117c478bd9Sstevel@tonic-gate kmem_free(fdc->c_un->un_drive, 13127c478bd9Sstevel@tonic-gate sizeof (struct fd_drive)); 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate kmem_free((caddr_t)fdc->c_un, sizeof (struct fdunit)); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate if (fdc->c_intrstat) { 13187c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 13197c478bd9Sstevel@tonic-gate (C, "fd_cleanup: delete intrstat\n")); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate kstat_delete(fdc->c_intrstat); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate fdc->c_intrstat = NULL; 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate if (locks) { 13277c478bd9Sstevel@tonic-gate cv_destroy(&fdc->c_iocv); 13287c478bd9Sstevel@tonic-gate cv_destroy(&fdc->c_csbcv); 13297c478bd9Sstevel@tonic-gate cv_destroy(&fdc->c_motoncv); 13307c478bd9Sstevel@tonic-gate cv_destroy(&fdc->c_suspend_cv); 13317c478bd9Sstevel@tonic-gate sema_destroy(&fdc->c_ocsem); 13327c478bd9Sstevel@tonic-gate mutex_destroy(&fdc->c_hilock); 13337c478bd9Sstevel@tonic-gate mutex_destroy(&fdc->c_lolock); 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate fdctlrs = fdc->c_next; 13387c478bd9Sstevel@tonic-gate kmem_free(fdc, sizeof (*fdc)); 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate static int 13457c478bd9Sstevel@tonic-gate fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 13467c478bd9Sstevel@tonic-gate { 13477c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 13487c478bd9Sstevel@tonic-gate struct fdctlr *fdc = fd_getctlr(instance << FDINSTSHIFT); 13497c478bd9Sstevel@tonic-gate timeout_id_t c_mtimeid; 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_detach\n")); 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate switch (cmd) { 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate case DDI_DETACH: 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate * The hard parameter is set to 1. If detach is called, then 13587c478bd9Sstevel@tonic-gate * attach must have passed meaning that the high level 13597c478bd9Sstevel@tonic-gate * interrupt handler was successfully added. 13607c478bd9Sstevel@tonic-gate * Similarly, the locks parameter is also set to 1. 13617c478bd9Sstevel@tonic-gate */ 13627c478bd9Sstevel@tonic-gate fd_cleanup(dip, fdc, 1, 1); 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 13697c478bd9Sstevel@tonic-gate if (!fdc) 13707c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 13747c478bd9Sstevel@tonic-gate fdgetcsb(fdc); /* Wait for I/O to finish */ 13757c478bd9Sstevel@tonic-gate c_mtimeid = fdc->c_mtimeid; 13767c478bd9Sstevel@tonic-gate fdretcsb(fdc); 13777c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate (void) untimeout(c_mtimeid); 13807c478bd9Sstevel@tonic-gate /* 13817c478bd9Sstevel@tonic-gate * After suspend, the system could be powered off. 13827c478bd9Sstevel@tonic-gate * When it is later powered on the southbridge floppy 13837c478bd9Sstevel@tonic-gate * controller will tristate the interrupt line causing 13847c478bd9Sstevel@tonic-gate * continuous dma interrupts. 13857c478bd9Sstevel@tonic-gate * To avoid getting continuous fd interrupts we will remove the 13867c478bd9Sstevel@tonic-gate * dma interrupt handler installed. We will re-install the 13877c478bd9Sstevel@tonic-gate * handler when we RESUME. 13887c478bd9Sstevel@tonic-gate */ 13897c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) 13907c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, fdc->c_block); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate fdc->c_un->un_state = FD_STATE_SUSPENDED; 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate default: 13977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14027c478bd9Sstevel@tonic-gate static int 14037c478bd9Sstevel@tonic-gate fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 14047c478bd9Sstevel@tonic-gate { 14057c478bd9Sstevel@tonic-gate register struct fdctlr *fdc; 14067c478bd9Sstevel@tonic-gate register int error; 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate switch (infocmd) { 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 14117c478bd9Sstevel@tonic-gate if ((fdc = fd_getctlr((dev_t)arg)) == NULL) { 14127c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 14137c478bd9Sstevel@tonic-gate } else { 14147c478bd9Sstevel@tonic-gate *result = fdc->c_dip; 14157c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate break; 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 14207c478bd9Sstevel@tonic-gate *result = 0; 14217c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 14227c478bd9Sstevel@tonic-gate break; 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate default: 14257c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate return (error); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * property operation routine. return the number of blocks for the partition 14327c478bd9Sstevel@tonic-gate * in question or forward the request to the property facilities. 14337c478bd9Sstevel@tonic-gate */ 14347c478bd9Sstevel@tonic-gate static int 14357c478bd9Sstevel@tonic-gate fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 14367c478bd9Sstevel@tonic-gate char *name, caddr_t valuep, int *lengthp) 14377c478bd9Sstevel@tonic-gate { 14387c478bd9Sstevel@tonic-gate struct fdunit *un; 14397c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 14407c478bd9Sstevel@tonic-gate uint64_t nblocks64; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /* 14437c478bd9Sstevel@tonic-gate * Our dynamic properties are all device specific and size oriented. 14447c478bd9Sstevel@tonic-gate * Requests issued under conditions where size is valid are passed 14457c478bd9Sstevel@tonic-gate * to ddi_prop_op_nblocks with the size information, otherwise the 14467c478bd9Sstevel@tonic-gate * request is passed to ddi_prop_op. 14477c478bd9Sstevel@tonic-gate */ 14487c478bd9Sstevel@tonic-gate if (dev == DDI_DEV_T_ANY) { 14497c478bd9Sstevel@tonic-gate pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 14507c478bd9Sstevel@tonic-gate name, valuep, lengthp)); 14517c478bd9Sstevel@tonic-gate } else { 14527c478bd9Sstevel@tonic-gate fdc = fd_getctlr(dev); 14537c478bd9Sstevel@tonic-gate if (fdc == NULL) 14547c478bd9Sstevel@tonic-gate goto pass; 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate /* we have size if diskette opened and label read */ 14577c478bd9Sstevel@tonic-gate un = fdc->c_un; 14587c478bd9Sstevel@tonic-gate if ((un == NULL) || !fd_unit_is_open(fdc->c_un)) 14597c478bd9Sstevel@tonic-gate goto pass; 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate /* get nblocks value */ 14627c478bd9Sstevel@tonic-gate nblocks64 = (ulong_t) 14637c478bd9Sstevel@tonic-gate un->un_label.dkl_map[FDPARTITION(dev)].dkl_nblk; 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags, 14667c478bd9Sstevel@tonic-gate name, valuep, lengthp, nblocks64)); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 14717c478bd9Sstevel@tonic-gate static int 14727c478bd9Sstevel@tonic-gate fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 14737c478bd9Sstevel@tonic-gate { 14747c478bd9Sstevel@tonic-gate dev_t dev; 14757c478bd9Sstevel@tonic-gate int part; 14767c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 14777c478bd9Sstevel@tonic-gate struct fdunit *un; 14787c478bd9Sstevel@tonic-gate struct dk_map32 *dkm; 14797c478bd9Sstevel@tonic-gate uchar_t pbit; 14807c478bd9Sstevel@tonic-gate int err, part_is_open; 14817c478bd9Sstevel@tonic-gate int unit; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate dev = *devp; 14847c478bd9Sstevel@tonic-gate fdc = fd_getctlr(dev); 14857c478bd9Sstevel@tonic-gate if ((fdc == NULL) || ((un = fdc->c_un) == NULL)) { 14867c478bd9Sstevel@tonic-gate return (ENXIO); 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate unit = fdc->c_un->un_unit_no; 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate /* 14927c478bd9Sstevel@tonic-gate * Serialize opens/closes 14937c478bd9Sstevel@tonic-gate */ 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate sema_p(&fdc->c_ocsem); 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate /* check partition */ 14987c478bd9Sstevel@tonic-gate part = FDPARTITION(dev); 14997c478bd9Sstevel@tonic-gate pbit = 1 << part; 15007c478bd9Sstevel@tonic-gate dkm = &un->un_label.dkl_map[part]; 15017c478bd9Sstevel@tonic-gate if (dkm->dkl_nblk == 0) { 15027c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 15037c478bd9Sstevel@tonic-gate return (ENXIO); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_OPEN, 15077c478bd9Sstevel@tonic-gate (C, "fdopen: ctlr %d unit %d part %d\n", 15087c478bd9Sstevel@tonic-gate ddi_get_instance(fdc->c_dip), unit, part)); 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_OPEN, 15117c478bd9Sstevel@tonic-gate (C, "fdopen: flag 0x%x", flag)); 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate /* 15157c478bd9Sstevel@tonic-gate * Insure that drive is present with a recalibrate on first open. 15167c478bd9Sstevel@tonic-gate */ 15177c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 15247c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 15257c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON)) 15267c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 15277c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \ 15287c478bd9Sstevel@tonic-gate failed. \n")); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 15317c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 15327c478bd9Sstevel@tonic-gate return (EIO); 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate if (fd_unit_is_open(un) == 0) { 15377c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 15387c478bd9Sstevel@tonic-gate /* 15397c478bd9Sstevel@tonic-gate * no check changed! 15407c478bd9Sstevel@tonic-gate */ 15417c478bd9Sstevel@tonic-gate err = fdrecalseek(fdc, unit, -1, 0); 15427c478bd9Sstevel@tonic-gate fdretcsb(fdc); 15437c478bd9Sstevel@tonic-gate if (err) { 15447c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_OPEN, 15457c478bd9Sstevel@tonic-gate (C, "fd%d: drive not ready\n", 0)); 15467c478bd9Sstevel@tonic-gate /* deselect drv on last close */ 15477c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 0); 15487c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 15497c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 15507c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 15517c478bd9Sstevel@tonic-gate return (EIO); 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate /* 15567c478bd9Sstevel@tonic-gate * Check for previous exclusive open, or trying to exclusive open 15577c478bd9Sstevel@tonic-gate */ 15587c478bd9Sstevel@tonic-gate if (otyp == OTYP_LYR) { 15597c478bd9Sstevel@tonic-gate part_is_open = (un->un_lyropen[part] != 0); 15607c478bd9Sstevel@tonic-gate } else { 15617c478bd9Sstevel@tonic-gate part_is_open = fd_part_is_open(un, part); 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate if ((un->un_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) { 15647c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 15657c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 15667c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_OPEN, (C, "fd:just return\n")); 15677c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 15687c478bd9Sstevel@tonic-gate return (EBUSY); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* don't attempt access, just return successfully */ 15727c478bd9Sstevel@tonic-gate if (flag & (FNDELAY | FNONBLOCK)) { 15737c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_OPEN, 15747c478bd9Sstevel@tonic-gate (C, "fd: return busy..\n")); 15757c478bd9Sstevel@tonic-gate goto out; 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate fdc->c_csb.csb_unit = (uchar_t)unit; 15797c478bd9Sstevel@tonic-gate if (fdgetlabel(fdc, unit)) { 15807c478bd9Sstevel@tonic-gate /* didn't find label (couldn't read anything) */ 15817c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_OPEN, 15827c478bd9Sstevel@tonic-gate (C, 15837c478bd9Sstevel@tonic-gate "fd%d: unformatted diskette or no diskette in the drive\n", 15847c478bd9Sstevel@tonic-gate 0)); 15857c478bd9Sstevel@tonic-gate if (fd_unit_is_open(un) == 0) { 15867c478bd9Sstevel@tonic-gate /* deselect drv on last close */ 15877c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 0); 15887c478bd9Sstevel@tonic-gate } 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 15917c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 15927c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 15937c478bd9Sstevel@tonic-gate return (EIO); 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate /* 15977c478bd9Sstevel@tonic-gate * if opening for writing, check write protect on diskette 15987c478bd9Sstevel@tonic-gate */ 15997c478bd9Sstevel@tonic-gate if (flag & FWRITE) { 16007c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 16017c478bd9Sstevel@tonic-gate err = fdsensedrv(fdc, unit) & WP_SR3; 16027c478bd9Sstevel@tonic-gate fdretcsb(fdc); 16037c478bd9Sstevel@tonic-gate if (err) { 16047c478bd9Sstevel@tonic-gate if (fd_unit_is_open(un) == 0) 16057c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 0); 16067c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 16077c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 16087c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 16097c478bd9Sstevel@tonic-gate return (EROFS); 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate out: 16147c478bd9Sstevel@tonic-gate /* 16157c478bd9Sstevel@tonic-gate * mark open as having succeeded 16167c478bd9Sstevel@tonic-gate */ 16177c478bd9Sstevel@tonic-gate if (flag & FEXCL) { 16187c478bd9Sstevel@tonic-gate un->un_exclmask |= pbit; 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate if (otyp == OTYP_LYR) { 16217c478bd9Sstevel@tonic-gate un->un_lyropen[part]++; 16227c478bd9Sstevel@tonic-gate } else { 16237c478bd9Sstevel@tonic-gate un->un_regopen[otyp] |= pbit; 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 16267c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 16277c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 16287c478bd9Sstevel@tonic-gate return (0); 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate /* 16317c478bd9Sstevel@tonic-gate * fd_part_is_open 16327c478bd9Sstevel@tonic-gate * return 1 if the partition is open 16337c478bd9Sstevel@tonic-gate * return 0 otherwise 16347c478bd9Sstevel@tonic-gate */ 16357c478bd9Sstevel@tonic-gate static int 16367c478bd9Sstevel@tonic-gate fd_part_is_open(struct fdunit *un, int part) 16377c478bd9Sstevel@tonic-gate { 16387c478bd9Sstevel@tonic-gate int i; 16397c478bd9Sstevel@tonic-gate for (i = 0; i < OTYPCNT - 1; i++) 16407c478bd9Sstevel@tonic-gate if (un->un_regopen[i] & (1 << part)) 16417c478bd9Sstevel@tonic-gate return (1); 16427c478bd9Sstevel@tonic-gate return (0); 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate /* ARGSUSED */ 16477c478bd9Sstevel@tonic-gate static int 16487c478bd9Sstevel@tonic-gate fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 16497c478bd9Sstevel@tonic-gate { 16507c478bd9Sstevel@tonic-gate int unit, part_is_closed, part; 16517c478bd9Sstevel@tonic-gate register struct fdctlr *fdc; 16527c478bd9Sstevel@tonic-gate register struct fdunit *un; 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate fdc = fd_getctlr(dev); 16557c478bd9Sstevel@tonic-gate if (!fdc || !(un = fdc->c_un)) 16567c478bd9Sstevel@tonic-gate return (ENXIO); 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate unit = fdc->c_un->un_unit_no; 16607c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_CLOS, (C, "fd_close\n")); 16617c478bd9Sstevel@tonic-gate part = FDPARTITION(dev); 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate sema_p(&fdc->c_ocsem); 16647c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate if (otyp == OTYP_LYR) { 16677c478bd9Sstevel@tonic-gate un->un_lyropen[part]--; 16687c478bd9Sstevel@tonic-gate part_is_closed = (un->un_lyropen[part] == 0); 16697c478bd9Sstevel@tonic-gate } else { 16707c478bd9Sstevel@tonic-gate un->un_regopen[otyp] &= ~(1<<part); 16717c478bd9Sstevel@tonic-gate part_is_closed = 1; 16727c478bd9Sstevel@tonic-gate } 16737c478bd9Sstevel@tonic-gate if (part_is_closed) 16747c478bd9Sstevel@tonic-gate un->un_exclmask &= ~(1<<part); 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate if (fd_unit_is_open(un) == 0) { 16777c478bd9Sstevel@tonic-gate /* deselect drive on last close */ 16787c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 0); 16797c478bd9Sstevel@tonic-gate un->un_flags &= ~FDUNIT_CHANGED; 16807c478bd9Sstevel@tonic-gate } 16817c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 16827c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate return (0); 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate /* 16887c478bd9Sstevel@tonic-gate * fd_strategy 16897c478bd9Sstevel@tonic-gate * checks operation, hangs buf struct off fdctlr, calls fdstart 16907c478bd9Sstevel@tonic-gate * if not already busy. Note that if we call start, then the operation 16917c478bd9Sstevel@tonic-gate * will already be done on return (start sleeps). 16927c478bd9Sstevel@tonic-gate */ 16937c478bd9Sstevel@tonic-gate static int 16947c478bd9Sstevel@tonic-gate fd_strategy(register struct buf *bp) 16957c478bd9Sstevel@tonic-gate { 16967c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 16977c478bd9Sstevel@tonic-gate struct fdunit *un; 16987c478bd9Sstevel@tonic-gate uint_t phys_blkno; 16997c478bd9Sstevel@tonic-gate struct dk_map32 *dkm; 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRA, 17027c478bd9Sstevel@tonic-gate (C, "fd_strategy: bp = 0x%p, dev = 0x%lx\n", 17037c478bd9Sstevel@tonic-gate (void *)bp, bp->b_edev)); 17047c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRA, 17057c478bd9Sstevel@tonic-gate (C, "b_blkno=%x b_flags=%x b_count=%x\n", 17067c478bd9Sstevel@tonic-gate (int)bp->b_blkno, bp->b_flags, (int)bp->b_bcount)); 17077c478bd9Sstevel@tonic-gate fdc = fd_getctlr(bp->b_edev); 17087c478bd9Sstevel@tonic-gate un = fdc->c_un; 17097c478bd9Sstevel@tonic-gate dkm = &un->un_label.dkl_map[FDPARTITION(bp->b_edev)]; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate /* 17127c478bd9Sstevel@tonic-gate * If it's medium density and the block no. isn't a multiple 17137c478bd9Sstevel@tonic-gate * of 1K, then return an error. 17147c478bd9Sstevel@tonic-gate */ 17157c478bd9Sstevel@tonic-gate if (un->un_chars->fdc_medium) { 17167c478bd9Sstevel@tonic-gate phys_blkno = (uint_t)bp->b_blkno >> 1; 17177c478bd9Sstevel@tonic-gate if (bp->b_blkno & 1) { 17187c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRA, 17197c478bd9Sstevel@tonic-gate (C, "b_blkno=0x%lx is not 1k aligned\n", 17207c478bd9Sstevel@tonic-gate (long)bp->b_blkno)); 17217c478bd9Sstevel@tonic-gate bp->b_error = EINVAL; 17227c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 17237c478bd9Sstevel@tonic-gate bp->b_flags |= B_ERROR; 17247c478bd9Sstevel@tonic-gate biodone(bp); 17257c478bd9Sstevel@tonic-gate return (0); 17267c478bd9Sstevel@tonic-gate } 17277c478bd9Sstevel@tonic-gate } else { 17287c478bd9Sstevel@tonic-gate phys_blkno = (uint_t)bp->b_blkno; 17297c478bd9Sstevel@tonic-gate } 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate /* If the block number is past the end, return an error */ 17337c478bd9Sstevel@tonic-gate if ((phys_blkno > dkm->dkl_nblk)) { 17347c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRA, 17357c478bd9Sstevel@tonic-gate (C, "fd%d: block %ld is past the end! (nblk=%d)\n", 17367c478bd9Sstevel@tonic-gate 0, (long)bp->b_blkno, dkm->dkl_nblk)); 17377c478bd9Sstevel@tonic-gate bp->b_error = ENOSPC; 17387c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 17397c478bd9Sstevel@tonic-gate bp->b_flags |= B_ERROR; 17407c478bd9Sstevel@tonic-gate biodone(bp); 17417c478bd9Sstevel@tonic-gate return (0); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate /* if at end of file, skip out now */ 17457c478bd9Sstevel@tonic-gate if (phys_blkno == dkm->dkl_nblk) { 17467c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRA, 17477c478bd9Sstevel@tonic-gate (C, "b_blkno is at the end!\n")); 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate if ((bp->b_flags & B_READ) == 0) { 17507c478bd9Sstevel@tonic-gate /* a write needs to get an error! */ 17517c478bd9Sstevel@tonic-gate bp->b_error = ENOSPC; 17527c478bd9Sstevel@tonic-gate bp->b_flags |= B_ERROR; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRA, 17557c478bd9Sstevel@tonic-gate (C, "block is at end and this is a write\n")); 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 17607c478bd9Sstevel@tonic-gate biodone(bp); 17617c478bd9Sstevel@tonic-gate return (0); 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate /* if operation not a multiple of sector size, is error! */ 17657c478bd9Sstevel@tonic-gate if (bp->b_bcount % un->un_chars->fdc_sec_size) { 17667c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRA, 17677c478bd9Sstevel@tonic-gate (C, "fd%d: requested transfer size(0x%lx) is not" 17687c478bd9Sstevel@tonic-gate " multiple of sector size(0x%x)\n", 0, 17697c478bd9Sstevel@tonic-gate bp->b_bcount, un->un_chars->fdc_sec_size)); 17707c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRA, 17717c478bd9Sstevel@tonic-gate (C, " b_blkno=0x%lx b_flags=0x%x\n", 17727c478bd9Sstevel@tonic-gate (long)bp->b_blkno, bp->b_flags)); 17737c478bd9Sstevel@tonic-gate bp->b_error = EINVAL; 17747c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 17757c478bd9Sstevel@tonic-gate bp->b_flags |= B_ERROR; 17767c478bd9Sstevel@tonic-gate biodone(bp); 17777c478bd9Sstevel@tonic-gate return (0); 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate /* 17827c478bd9Sstevel@tonic-gate * Put the buf request in the controller's queue, FIFO. 17837c478bd9Sstevel@tonic-gate */ 17847c478bd9Sstevel@tonic-gate bp->av_forw = 0; 17857c478bd9Sstevel@tonic-gate sema_p(&fdc->c_ocsem); 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 17947c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 17957c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON)) 17967c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 17977c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 17987c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 17997c478bd9Sstevel@tonic-gate bp->b_error = EIO; 18007c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 18017c478bd9Sstevel@tonic-gate bp->b_flags |= B_ERROR; 18027c478bd9Sstevel@tonic-gate biodone(bp); 18037c478bd9Sstevel@tonic-gate return (0); 18047c478bd9Sstevel@tonic-gate } else { 18057c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 18067c478bd9Sstevel@tonic-gate } 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate if (un->un_iostat) { 18097c478bd9Sstevel@tonic-gate kstat_waitq_enter(KIOSP); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate if (fdc->c_actf) 18127c478bd9Sstevel@tonic-gate fdc->c_actl->av_forw = bp; 18137c478bd9Sstevel@tonic-gate else 18147c478bd9Sstevel@tonic-gate fdc->c_actf = bp; 18157c478bd9Sstevel@tonic-gate fdc->c_actl = bp; 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate 18187c478bd9Sstevel@tonic-gate /* call fdstart to start the transfer */ 18197c478bd9Sstevel@tonic-gate fdstart(fdc); 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 18227c478bd9Sstevel@tonic-gate sema_v(&fdc->c_ocsem); 18237c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 18247c478bd9Sstevel@tonic-gate return (0); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 18287c478bd9Sstevel@tonic-gate static int 18297c478bd9Sstevel@tonic-gate fd_read(dev_t dev, struct uio *uio, cred_t *cred_p) 18307c478bd9Sstevel@tonic-gate { 18317c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_read\n")); 18327c478bd9Sstevel@tonic-gate return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio)); 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate 18357c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 18367c478bd9Sstevel@tonic-gate static int 18377c478bd9Sstevel@tonic-gate fd_write(dev_t dev, struct uio *uio, cred_t *cred_p) 18387c478bd9Sstevel@tonic-gate { 18397c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_write\n")); 18407c478bd9Sstevel@tonic-gate return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio)); 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate static void 18447c478bd9Sstevel@tonic-gate fdmotoff(void *arg) 18457c478bd9Sstevel@tonic-gate { 18467c478bd9Sstevel@tonic-gate struct fdctlr *fdc = arg; 18477c478bd9Sstevel@tonic-gate int unit = fdc->c_un->un_unit_no; 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* Just return if we're about to call untimeout */ 18527c478bd9Sstevel@tonic-gate if (fdc->c_mtimeid == 0) { 18537c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 18547c478bd9Sstevel@tonic-gate return; 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_MOFF, (C, "fdmotoff\n")); 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate fdc->c_mtimeid = 0; 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate if (!(Msr(fdc) & CB) && (Dor(fdc) & (MOTEN(unit)))) { 18627c478bd9Sstevel@tonic-gate /* LINTED */ 18637c478bd9Sstevel@tonic-gate Set_dor(fdc, MOTEN(unit), 0); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate /* ARGSUSED */ 18707c478bd9Sstevel@tonic-gate static int 18717c478bd9Sstevel@tonic-gate fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, 18727c478bd9Sstevel@tonic-gate cred_t *cred_p, int *rval_p) 18737c478bd9Sstevel@tonic-gate { 18747c478bd9Sstevel@tonic-gate union { 18757c478bd9Sstevel@tonic-gate struct dk_cinfo dki; 18767c478bd9Sstevel@tonic-gate struct dk_geom dkg; 18777c478bd9Sstevel@tonic-gate struct dk_allmap32 dka; 18787c478bd9Sstevel@tonic-gate struct fd_char fdchar; 18797c478bd9Sstevel@tonic-gate struct fd_drive drvchar; 18807c478bd9Sstevel@tonic-gate int temp; 18817c478bd9Sstevel@tonic-gate } cpy; 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate struct vtoc vtoc; 18847c478bd9Sstevel@tonic-gate struct fdunit *un; 18857c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 18867c478bd9Sstevel@tonic-gate int unit, dkunit; 18877c478bd9Sstevel@tonic-gate int err = 0; 18887c478bd9Sstevel@tonic-gate uint_t sec_size; 18897c478bd9Sstevel@tonic-gate enum dkio_state state; 18907c478bd9Sstevel@tonic-gate int transfer_rate; 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_IOCT, 18937c478bd9Sstevel@tonic-gate (C, "fd_ioctl: cmd 0x%x, arg 0x%lx\n", cmd, (long)arg)); 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate /* The minor number should always be 0 */ 18967c478bd9Sstevel@tonic-gate if (FDUNIT(dev) != 0) 18977c478bd9Sstevel@tonic-gate return (ENXIO); 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate fdc = fd_getctlr(dev); 19007c478bd9Sstevel@tonic-gate unit = fdc->c_un->un_unit_no; 19017c478bd9Sstevel@tonic-gate un = fdc->c_un; 19027c478bd9Sstevel@tonic-gate sec_size = un->un_chars->fdc_sec_size; 19037c478bd9Sstevel@tonic-gate bzero(&cpy, sizeof (cpy)); 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate switch (cmd) { 19067c478bd9Sstevel@tonic-gate case DKIOCINFO: 19077c478bd9Sstevel@tonic-gate cpy.dki.dki_addr = 0; 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * The meaning of the dki_slave and dki_unit fields 19117c478bd9Sstevel@tonic-gate * is unclear. The sparc floppy driver follows the same 19127c478bd9Sstevel@tonic-gate * convention as sd.c in that the instance number is 19137c478bd9Sstevel@tonic-gate * returned in the dki_cnum field. The dki_slave field is 19147c478bd9Sstevel@tonic-gate * ignored. 19157c478bd9Sstevel@tonic-gate * 19167c478bd9Sstevel@tonic-gate * The dki_cnum contains the controller instance 19177c478bd9Sstevel@tonic-gate * and its value can be any positive number. Even 19187c478bd9Sstevel@tonic-gate * though currently Sparc platforms only support 19197c478bd9Sstevel@tonic-gate * one controller, the controller instance number 19207c478bd9Sstevel@tonic-gate * can be any number since it is assigned by the 19217c478bd9Sstevel@tonic-gate * system depending on the device properties. 19227c478bd9Sstevel@tonic-gate */ 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate cpy.dki.dki_cnum = FDCTLR(dev); 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate /* 19277c478bd9Sstevel@tonic-gate * Sparc platforms support only one floppy drive. 19287c478bd9Sstevel@tonic-gate * The device node for the controller is the same as 19297c478bd9Sstevel@tonic-gate * the device node for the drive. The x86 driver is 19307c478bd9Sstevel@tonic-gate * different in that it has a node for the controller 19317c478bd9Sstevel@tonic-gate * and a child node for each drive. Since Sparc supports 19327c478bd9Sstevel@tonic-gate * only one drive, the unit number will always be zero. 19337c478bd9Sstevel@tonic-gate */ 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate cpy.dki.dki_unit = FDUNIT(dev); 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate /* 19387c478bd9Sstevel@tonic-gate * The meaning of the dki_slave field is unclear. 19397c478bd9Sstevel@tonic-gate * So, I will leave it set to 0. 19407c478bd9Sstevel@tonic-gate */ 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate cpy.dki.dki_slave = 0; 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate cpy.dki.dki_ctype = (ushort_t)-1; 19457c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_82077) 19467c478bd9Sstevel@tonic-gate cpy.dki.dki_ctype = DKC_INTEL82077; 19477c478bd9Sstevel@tonic-gate cpy.dki.dki_flags = DKI_FMTTRK; 19487c478bd9Sstevel@tonic-gate cpy.dki.dki_partition = FDPARTITION(dev); 19497c478bd9Sstevel@tonic-gate cpy.dki.dki_maxtransfer = maxphys / DEV_BSIZE; 19507c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&cpy.dki, (caddr_t)arg, 19517c478bd9Sstevel@tonic-gate sizeof (cpy.dki), flag)) 19527c478bd9Sstevel@tonic-gate err = EFAULT; 19537c478bd9Sstevel@tonic-gate break; 19547c478bd9Sstevel@tonic-gate case DKIOCGGEOM: 19557c478bd9Sstevel@tonic-gate cpy.dkg.dkg_ncyl = un->un_chars->fdc_ncyl; 19567c478bd9Sstevel@tonic-gate cpy.dkg.dkg_nhead = un->un_chars->fdc_nhead; 19577c478bd9Sstevel@tonic-gate cpy.dkg.dkg_nsect = un->un_chars->fdc_secptrack; 19587c478bd9Sstevel@tonic-gate cpy.dkg.dkg_intrlv = un->un_label.dkl_intrlv; 19597c478bd9Sstevel@tonic-gate cpy.dkg.dkg_rpm = un->un_label.dkl_rpm; 19607c478bd9Sstevel@tonic-gate cpy.dkg.dkg_pcyl = un->un_chars->fdc_ncyl; 19617c478bd9Sstevel@tonic-gate cpy.dkg.dkg_read_reinstruct = 19627c478bd9Sstevel@tonic-gate (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000; 19637c478bd9Sstevel@tonic-gate cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct; 19647c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&cpy.dkg, (caddr_t)arg, 19657c478bd9Sstevel@tonic-gate sizeof (cpy.dkg), flag)) 19667c478bd9Sstevel@tonic-gate err = EFAULT; 19677c478bd9Sstevel@tonic-gate break; 19687c478bd9Sstevel@tonic-gate case DKIOCSGEOM: 19697c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_IOCT, 19707c478bd9Sstevel@tonic-gate (C, "fd_ioctl: DKIOCSGEOM not supported\n")); 19717c478bd9Sstevel@tonic-gate err = ENOTTY; 19727c478bd9Sstevel@tonic-gate break; 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate /* 19757c478bd9Sstevel@tonic-gate * return the map of all logical partitions 19767c478bd9Sstevel@tonic-gate */ 19777c478bd9Sstevel@tonic-gate case DKIOCGAPART: 19787c478bd9Sstevel@tonic-gate /* 19797c478bd9Sstevel@tonic-gate * We don't have anything to do if the application is ILP32 19807c478bd9Sstevel@tonic-gate * because the label map has a 32-bit format. Otherwise 19817c478bd9Sstevel@tonic-gate * convert. 19827c478bd9Sstevel@tonic-gate */ 19837c478bd9Sstevel@tonic-gate if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) { 19847c478bd9Sstevel@tonic-gate if (ddi_copyout(&un->un_label.dkl_map, 19857c478bd9Sstevel@tonic-gate (void *)arg, sizeof (struct dk_allmap32), flag)) 19867c478bd9Sstevel@tonic-gate err = EFAULT; 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 19897c478bd9Sstevel@tonic-gate else { 19907c478bd9Sstevel@tonic-gate struct dk_allmap dk_allmap; 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64); 19937c478bd9Sstevel@tonic-gate for (dkunit = 0; dkunit < NDKMAP; dkunit++) { 19947c478bd9Sstevel@tonic-gate dk_allmap.dka_map[dkunit].dkl_cylno = 19957c478bd9Sstevel@tonic-gate un->un_label.dkl_map[dkunit].dkl_cylno; 19967c478bd9Sstevel@tonic-gate dk_allmap.dka_map[dkunit].dkl_nblk = 19977c478bd9Sstevel@tonic-gate un->un_label.dkl_map[dkunit].dkl_nblk; 19987c478bd9Sstevel@tonic-gate } 19997c478bd9Sstevel@tonic-gate if (ddi_copyout(&dk_allmap, (void *)arg, 20007c478bd9Sstevel@tonic-gate sizeof (struct dk_allmap), flag)) 20017c478bd9Sstevel@tonic-gate err = EFAULT; 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 20047c478bd9Sstevel@tonic-gate break; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* 20077c478bd9Sstevel@tonic-gate * Set the map of all logical partitions 20087c478bd9Sstevel@tonic-gate */ 20097c478bd9Sstevel@tonic-gate case DKIOCSAPART: 20107c478bd9Sstevel@tonic-gate if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) { 20117c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &cpy.dka, 20127c478bd9Sstevel@tonic-gate sizeof (cpy.dka), flag)) 20137c478bd9Sstevel@tonic-gate return (EFAULT); 20147c478bd9Sstevel@tonic-gate else { 20157c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 20167c478bd9Sstevel@tonic-gate for (dkunit = 0; dkunit < NDKMAP; dkunit++) { 20177c478bd9Sstevel@tonic-gate un->un_label.dkl_map[dkunit] = 20187c478bd9Sstevel@tonic-gate cpy.dka.dka_map[dkunit]; 20197c478bd9Sstevel@tonic-gate } 20207c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 20247c478bd9Sstevel@tonic-gate else { 20257c478bd9Sstevel@tonic-gate struct dk_allmap dk_allmap; 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64); 20287c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &dk_allmap, 20297c478bd9Sstevel@tonic-gate sizeof (dk_allmap), flag)) 20307c478bd9Sstevel@tonic-gate return (EFAULT); 20317c478bd9Sstevel@tonic-gate else { 20327c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 20337c478bd9Sstevel@tonic-gate for (dkunit = 0; dkunit < NDKMAP; dkunit++) { 20347c478bd9Sstevel@tonic-gate un->un_label.dkl_map[dkunit].dkl_cylno = 20357c478bd9Sstevel@tonic-gate dk_allmap.dka_map[dkunit].dkl_cylno; 20367c478bd9Sstevel@tonic-gate un->un_label.dkl_map[dkunit].dkl_nblk = 20377c478bd9Sstevel@tonic-gate dk_allmap.dka_map[dkunit].dkl_nblk; 20387c478bd9Sstevel@tonic-gate } 20397c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate } 20427c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 20437c478bd9Sstevel@tonic-gate break; 20447c478bd9Sstevel@tonic-gate 20457c478bd9Sstevel@tonic-gate case DKIOCGVTOC: 20467c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate /* 20497c478bd9Sstevel@tonic-gate * Exit if the diskette has no label. 20507c478bd9Sstevel@tonic-gate * Also, get the label to make sure the 20517c478bd9Sstevel@tonic-gate * correct one is being used since the diskette 20527c478bd9Sstevel@tonic-gate * may have changed 20537c478bd9Sstevel@tonic-gate */ 20547c478bd9Sstevel@tonic-gate if (fdgetlabel(fdc, unit)) { 20557c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 20567c478bd9Sstevel@tonic-gate err = EINVAL; 20577c478bd9Sstevel@tonic-gate break; 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate /* Build a vtoc from the diskette's label */ 20617c478bd9Sstevel@tonic-gate fd_build_user_vtoc(un, &vtoc); 20627c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 20657c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 20667c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: { 20677c478bd9Sstevel@tonic-gate struct vtoc32 vtoc32; 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate vtoctovtoc32(vtoc, vtoc32); 20707c478bd9Sstevel@tonic-gate if (ddi_copyout(&vtoc32, (void *)arg, 20717c478bd9Sstevel@tonic-gate sizeof (struct vtoc32), flag)) 20727c478bd9Sstevel@tonic-gate return (EFAULT); 20737c478bd9Sstevel@tonic-gate break; 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate 20767c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 20777c478bd9Sstevel@tonic-gate if (ddi_copyout(&vtoc, (void *)arg, 20787c478bd9Sstevel@tonic-gate sizeof (vtoc), flag)) 20797c478bd9Sstevel@tonic-gate return (EFAULT); 20807c478bd9Sstevel@tonic-gate break; 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 20837c478bd9Sstevel@tonic-gate if (ddi_copyout(&vtoc, (void *)arg, sizeof (vtoc), flag)) 20847c478bd9Sstevel@tonic-gate return (EFAULT); 20857c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 20867c478bd9Sstevel@tonic-gate break; 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate case DKIOCSVTOC: 20897c478bd9Sstevel@tonic-gate 20907c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 20917c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 20927c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: { 20937c478bd9Sstevel@tonic-gate struct vtoc32 vtoc32; 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &vtoc32, 20967c478bd9Sstevel@tonic-gate sizeof (struct vtoc32), flag)) { 20977c478bd9Sstevel@tonic-gate return (EFAULT); 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate vtoc32tovtoc(vtoc32, vtoc); 21007c478bd9Sstevel@tonic-gate break; 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 21047c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &vtoc, 21057c478bd9Sstevel@tonic-gate sizeof (vtoc), flag)) { 21067c478bd9Sstevel@tonic-gate return (EFAULT); 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate break; 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 21117c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &vtoc, sizeof (vtoc), flag)) 21127c478bd9Sstevel@tonic-gate return (EFAULT); 21137c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate /* 21187c478bd9Sstevel@tonic-gate * The characteristics structure must be filled in because 21197c478bd9Sstevel@tonic-gate * it helps build the vtoc. 21207c478bd9Sstevel@tonic-gate */ 21217c478bd9Sstevel@tonic-gate if ((un->un_chars->fdc_ncyl == 0) || 21227c478bd9Sstevel@tonic-gate (un->un_chars->fdc_nhead == 0) || 21237c478bd9Sstevel@tonic-gate (un->un_chars->fdc_secptrack == 0)) { 21247c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 21257c478bd9Sstevel@tonic-gate err = EINVAL; 21267c478bd9Sstevel@tonic-gate break; 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate if ((err = fd_build_label_vtoc(un, &vtoc)) != 0) { 21307c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 21317c478bd9Sstevel@tonic-gate break; 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate err = fdrw(fdc, unit, FDWRITE, 0, 0, 1, 21377c478bd9Sstevel@tonic-gate (caddr_t)&un->un_label, sizeof (struct dk_label)); 21387c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 21397c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 21407c478bd9Sstevel@tonic-gate break; 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate case DKIOCSTATE: 21437c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&state, 21447c478bd9Sstevel@tonic-gate sizeof (int), flag)) { 21457c478bd9Sstevel@tonic-gate err = EFAULT; 21467c478bd9Sstevel@tonic-gate break; 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate err = fd_check_media(dev, state); 21517c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&un->un_media_state, 21547c478bd9Sstevel@tonic-gate (caddr_t)arg, sizeof (int), flag)) 21557c478bd9Sstevel@tonic-gate err = EFAULT; 21567c478bd9Sstevel@tonic-gate break; 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate case FDIOGCHAR: 21597c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)un->un_chars, (caddr_t)arg, 21607c478bd9Sstevel@tonic-gate sizeof (struct fd_char), flag)) 21617c478bd9Sstevel@tonic-gate err = EFAULT; 21627c478bd9Sstevel@tonic-gate break; 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate case FDIOSCHAR: 21657c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.fdchar, 21667c478bd9Sstevel@tonic-gate sizeof (struct fd_char), flag)) { 21677c478bd9Sstevel@tonic-gate err = EFAULT; 21687c478bd9Sstevel@tonic-gate break; 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate /* 21727c478bd9Sstevel@tonic-gate * Check the fields in the fdchar structure that are either 21737c478bd9Sstevel@tonic-gate * driver or controller dependent. 21747c478bd9Sstevel@tonic-gate */ 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate transfer_rate = cpy.fdchar.fdc_transfer_rate; 21777c478bd9Sstevel@tonic-gate if ((transfer_rate != 500) && (transfer_rate != 300) && 21787c478bd9Sstevel@tonic-gate (transfer_rate != 250) && (transfer_rate != 1000)) { 21797c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_IOCT, 21807c478bd9Sstevel@tonic-gate (C, "fd_ioctl: FDIOSCHAR odd transfer rate %d\n", 21817c478bd9Sstevel@tonic-gate cpy.fdchar.fdc_transfer_rate)); 21827c478bd9Sstevel@tonic-gate err = EINVAL; 21837c478bd9Sstevel@tonic-gate break; 21847c478bd9Sstevel@tonic-gate } 21857c478bd9Sstevel@tonic-gate 21867c478bd9Sstevel@tonic-gate if ((cpy.fdchar.fdc_nhead < 1) || 21877c478bd9Sstevel@tonic-gate (cpy.fdchar.fdc_nhead > 2)) { 21887c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_IOCT, 21897c478bd9Sstevel@tonic-gate (C, "fd_ioctl: FDIOSCHAR bad no. of heads %d\n", 21907c478bd9Sstevel@tonic-gate cpy.fdchar.fdc_nhead)); 21917c478bd9Sstevel@tonic-gate err = EINVAL; 21927c478bd9Sstevel@tonic-gate break; 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate /* 21967c478bd9Sstevel@tonic-gate * The number of cylinders must be between 0 and 255 21977c478bd9Sstevel@tonic-gate */ 21987c478bd9Sstevel@tonic-gate if ((cpy.fdchar.fdc_ncyl < 0) || (cpy.fdchar.fdc_ncyl > 255)) { 21997c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_IOCT, 22007c478bd9Sstevel@tonic-gate (C, "fd_ioctl: FDIOSCHAR bad cyl no %d\n", 22017c478bd9Sstevel@tonic-gate cpy.fdchar.fdc_ncyl)); 22027c478bd9Sstevel@tonic-gate err = EINVAL; 22037c478bd9Sstevel@tonic-gate break; 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate /* Copy the fdchar structure */ 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 22097c478bd9Sstevel@tonic-gate *(un->un_chars) = cpy.fdchar; 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate un->un_curfdtype = -1; 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate break; 22167c478bd9Sstevel@tonic-gate case FDEJECT: /* eject disk */ 22177c478bd9Sstevel@tonic-gate case DKIOCEJECT: 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate /* 22207c478bd9Sstevel@tonic-gate * Fail the ioctl if auto-eject isn't supported 22217c478bd9Sstevel@tonic-gate */ 22227c478bd9Sstevel@tonic-gate if (fdc->c_un->un_drive->fdd_ejectable == 0) { 22237c478bd9Sstevel@tonic-gate 22247c478bd9Sstevel@tonic-gate err = ENOSYS; 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate } else { 22277c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 22327c478bd9Sstevel@tonic-gate 22337c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 22347c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 22357c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, 22367c478bd9Sstevel@tonic-gate PM_LEVEL_ON)) != DDI_SUCCESS) { 22377c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 22387c478bd9Sstevel@tonic-gate err = EIO; 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate if (err == 0) { 22447c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 1); 22457c478bd9Sstevel@tonic-gate fdeject(fdc, unit); 22467c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 22477c478bd9Sstevel@tonic-gate } 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* 22527c478bd9Sstevel@tonic-gate * Make sure the drive is turned off 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_82077) { 22557c478bd9Sstevel@tonic-gate if (fdc->c_mtimeid == 0) { 22567c478bd9Sstevel@tonic-gate fdc->c_mtimeid = timeout(fdmotoff, fdc, 22577c478bd9Sstevel@tonic-gate Motoff_delay); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate } 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate break; 22627c478bd9Sstevel@tonic-gate case FDGETCHANGE: /* disk changed */ 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.temp, 22657c478bd9Sstevel@tonic-gate sizeof (int), flag)) { 22667c478bd9Sstevel@tonic-gate err = EFAULT; 22677c478bd9Sstevel@tonic-gate break; 22687c478bd9Sstevel@tonic-gate } 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate /* zero out the user's parameter */ 22717c478bd9Sstevel@tonic-gate cpy.temp = 0; 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 22767c478bd9Sstevel@tonic-gate 22777c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 22807c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 22817c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON)) 22827c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 22837c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \ 22847c478bd9Sstevel@tonic-gate change failed. \n")); 22857c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 22867c478bd9Sstevel@tonic-gate return (EIO); 22877c478bd9Sstevel@tonic-gate } 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 22907c478bd9Sstevel@tonic-gate } 22917c478bd9Sstevel@tonic-gate if (un->un_flags & FDUNIT_CHANGED) 22927c478bd9Sstevel@tonic-gate cpy.temp |= FDGC_HISTORY; 22937c478bd9Sstevel@tonic-gate else 22947c478bd9Sstevel@tonic-gate cpy.temp &= ~FDGC_HISTORY; 22957c478bd9Sstevel@tonic-gate un->un_flags &= ~FDUNIT_CHANGED; 22967c478bd9Sstevel@tonic-gate 22977c478bd9Sstevel@tonic-gate if (fd_pollable) { 22987c478bd9Sstevel@tonic-gate /* 22997c478bd9Sstevel@tonic-gate * If it's a "pollable" floppy, then we don't 23007c478bd9Sstevel@tonic-gate * have to do all the fdcheckdisk nastyness to 23017c478bd9Sstevel@tonic-gate * figure out if the thing is still there. 23027c478bd9Sstevel@tonic-gate */ 23037c478bd9Sstevel@tonic-gate if (fdsense_chng(fdc, unit)) { 23047c478bd9Sstevel@tonic-gate cpy.temp |= FDGC_CURRENT; 23057c478bd9Sstevel@tonic-gate } else { 23067c478bd9Sstevel@tonic-gate cpy.temp &= ~FDGC_CURRENT; 23077c478bd9Sstevel@tonic-gate } 23087c478bd9Sstevel@tonic-gate } else { 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate if (fdsense_chng(fdc, unit)) { 23117c478bd9Sstevel@tonic-gate /* 23127c478bd9Sstevel@tonic-gate * check disk change signal is asserted. 23137c478bd9Sstevel@tonic-gate * Now find out if the floppy is 23147c478bd9Sstevel@tonic-gate * inserted 23157c478bd9Sstevel@tonic-gate */ 23167c478bd9Sstevel@tonic-gate if (fdcheckdisk(fdc, unit)) { 23177c478bd9Sstevel@tonic-gate cpy.temp |= FDGC_CURRENT; 23187c478bd9Sstevel@tonic-gate } else { 23197c478bd9Sstevel@tonic-gate /* 23207c478bd9Sstevel@tonic-gate * Yes, the floppy was 23217c478bd9Sstevel@tonic-gate * reinserted. Implies 23227c478bd9Sstevel@tonic-gate * floppy change. 23237c478bd9Sstevel@tonic-gate */ 23247c478bd9Sstevel@tonic-gate cpy.temp &= ~FDGC_CURRENT; 23257c478bd9Sstevel@tonic-gate cpy.temp |= FDGC_HISTORY; 23267c478bd9Sstevel@tonic-gate } 23277c478bd9Sstevel@tonic-gate } else { 23287c478bd9Sstevel@tonic-gate cpy.temp &= ~FDGC_CURRENT; 23297c478bd9Sstevel@tonic-gate } 23307c478bd9Sstevel@tonic-gate } 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate /* 23337c478bd9Sstevel@tonic-gate * For a pollable floppy, the floppy_change signal 23347c478bd9Sstevel@tonic-gate * reflects whether the floppy is in there or not. 23357c478bd9Sstevel@tonic-gate * We can not detect a floppy change if we don't poll 23367c478bd9Sstevel@tonic-gate * this signal when the floppy is being changed. 23377c478bd9Sstevel@tonic-gate * Because as soon as the floppy is put back, the 23387c478bd9Sstevel@tonic-gate * signal is reset. 23397c478bd9Sstevel@tonic-gate * BUT the pollable floppies are available only on 23407c478bd9Sstevel@tonic-gate * Sparcstation Voyager Voyagers (Gypsy) only and 23417c478bd9Sstevel@tonic-gate * those are motorized floppies. For motorized floppies, 23427c478bd9Sstevel@tonic-gate * the floppy can only (assuming the user doesn't use a 23437c478bd9Sstevel@tonic-gate * pin to take out the floppy) be taken out by 23447c478bd9Sstevel@tonic-gate * issuing 'eject' command which sets the 23457c478bd9Sstevel@tonic-gate * un->un_ejected flag. So, if the following 23467c478bd9Sstevel@tonic-gate * condition is true, we can assume there 23477c478bd9Sstevel@tonic-gate * was a floppy change. 23487c478bd9Sstevel@tonic-gate */ 23497c478bd9Sstevel@tonic-gate if (un->un_ejected && !(cpy.temp & FDGC_CURRENT)) { 23507c478bd9Sstevel@tonic-gate cpy.temp |= FDGC_HISTORY; 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate un->un_ejected = 0; 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate /* return the write-protection status */ 23567c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 23577c478bd9Sstevel@tonic-gate if (fdsensedrv(fdc, unit) & WP_SR3) { 23587c478bd9Sstevel@tonic-gate cpy.temp |= FDGC_CURWPROT; 23597c478bd9Sstevel@tonic-gate } 23607c478bd9Sstevel@tonic-gate fdretcsb(fdc); 23617c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&cpy.temp, (caddr_t)arg, 23647c478bd9Sstevel@tonic-gate sizeof (int), flag)) 23657c478bd9Sstevel@tonic-gate err = EFAULT; 23667c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 23677c478bd9Sstevel@tonic-gate break; 23687c478bd9Sstevel@tonic-gate 23697c478bd9Sstevel@tonic-gate case FDGETDRIVECHAR: 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.drvchar, 23727c478bd9Sstevel@tonic-gate sizeof (struct fd_drive), flag)) { 23737c478bd9Sstevel@tonic-gate err = EFAULT; 23747c478bd9Sstevel@tonic-gate break; 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate /* 23787c478bd9Sstevel@tonic-gate * Return the ejectable value based on the FD_MANUAL_EJECT 23797c478bd9Sstevel@tonic-gate * property 23807c478bd9Sstevel@tonic-gate */ 23817c478bd9Sstevel@tonic-gate cpy.drvchar.fdd_ejectable = fdc->c_un->un_drive->fdd_ejectable; 23827c478bd9Sstevel@tonic-gate cpy.drvchar.fdd_maxsearch = nfdtypes; /* 3 - hi m lo density */ 23837c478bd9Sstevel@tonic-gate if (fd_pollable) /* pollable device */ 23847c478bd9Sstevel@tonic-gate cpy.drvchar.fdd_flags |= FDD_POLLABLE; 23857c478bd9Sstevel@tonic-gate 23867c478bd9Sstevel@tonic-gate /* the rest of the fd_drive struct is meaningless to us */ 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&cpy.drvchar, (caddr_t)arg, 23897c478bd9Sstevel@tonic-gate sizeof (struct fd_drive), flag)) 23907c478bd9Sstevel@tonic-gate err = EFAULT; 23917c478bd9Sstevel@tonic-gate break; 23927c478bd9Sstevel@tonic-gate 23937c478bd9Sstevel@tonic-gate case FDSETDRIVECHAR: 23947c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_IOCT, 23957c478bd9Sstevel@tonic-gate (C, "fd_ioctl: FDSETDRIVECHAR not supportedn\n")); 23967c478bd9Sstevel@tonic-gate err = ENOTTY; 23977c478bd9Sstevel@tonic-gate break; 23987c478bd9Sstevel@tonic-gate 23997c478bd9Sstevel@tonic-gate case DKIOCREMOVABLE: { 24007c478bd9Sstevel@tonic-gate int i = 1; 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate /* no brainer: floppies are always removable */ 24037c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&i, (caddr_t)arg, sizeof (int), 24047c478bd9Sstevel@tonic-gate flag)) { 24057c478bd9Sstevel@tonic-gate err = EFAULT; 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate break; 24087c478bd9Sstevel@tonic-gate } 24097c478bd9Sstevel@tonic-gate case DKIOCGMEDIAINFO: 24107c478bd9Sstevel@tonic-gate err = fd_get_media_info(un, (caddr_t)arg, flag); 24117c478bd9Sstevel@tonic-gate break; 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate 24147c478bd9Sstevel@tonic-gate case FDIOCMD: 24157c478bd9Sstevel@tonic-gate { 24167c478bd9Sstevel@tonic-gate struct fd_cmd fc; 24177c478bd9Sstevel@tonic-gate int cyl, hd, spc, spt; 24187c478bd9Sstevel@tonic-gate int nblks; /* total no. of blocks */ 24197c478bd9Sstevel@tonic-gate 24207c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 24217c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 24227c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: { 24237c478bd9Sstevel@tonic-gate struct fd_cmd32 fc32; 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &fc32, 24267c478bd9Sstevel@tonic-gate sizeof (fc32), flag)) { 24277c478bd9Sstevel@tonic-gate return (EFAULT); 24287c478bd9Sstevel@tonic-gate } 24297c478bd9Sstevel@tonic-gate fc.fdc_cmd = fc32.fdc_cmd; 24307c478bd9Sstevel@tonic-gate fc.fdc_flags = fc32.fdc_flags; 24317c478bd9Sstevel@tonic-gate fc.fdc_blkno = (daddr_t)fc32.fdc_blkno; 24327c478bd9Sstevel@tonic-gate fc.fdc_secnt = fc32.fdc_secnt; 243329df58e5Spc157239 fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr; 24347c478bd9Sstevel@tonic-gate fc.fdc_buflen = fc32.fdc_buflen; 24357c478bd9Sstevel@tonic-gate fc.fdc_cmd = fc32.fdc_cmd; 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate break; 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 24417c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &fc, 24427c478bd9Sstevel@tonic-gate sizeof (fc), flag)) { 24437c478bd9Sstevel@tonic-gate return (EFAULT); 24447c478bd9Sstevel@tonic-gate } 24457c478bd9Sstevel@tonic-gate break; 24467c478bd9Sstevel@tonic-gate } 24477c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 24487c478bd9Sstevel@tonic-gate if (ddi_copyin((const void *)arg, &fc, sizeof (fc), flag)) { 24497c478bd9Sstevel@tonic-gate return (EFAULT); 24507c478bd9Sstevel@tonic-gate } 24517c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 24527c478bd9Sstevel@tonic-gate 24537c478bd9Sstevel@tonic-gate if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) { 24547c478bd9Sstevel@tonic-gate auto struct iovec aiov; 24557c478bd9Sstevel@tonic-gate auto struct uio auio; 24567c478bd9Sstevel@tonic-gate struct uio *uio = &auio; 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE; 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate bzero(&auio, sizeof (struct uio)); 24617c478bd9Sstevel@tonic-gate bzero(&aiov, sizeof (struct iovec)); 24627c478bd9Sstevel@tonic-gate aiov.iov_base = fc.fdc_bufaddr; 24637c478bd9Sstevel@tonic-gate aiov.iov_len = (uint_t)fc.fdc_secnt * sec_size; 24647c478bd9Sstevel@tonic-gate uio->uio_iov = &aiov; 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate uio->uio_iovcnt = 1; 24677c478bd9Sstevel@tonic-gate uio->uio_resid = aiov.iov_len; 24687c478bd9Sstevel@tonic-gate uio->uio_segflg = UIO_USERSPACE; 24697c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_IOCT, 24707c478bd9Sstevel@tonic-gate (C, "fd_ioctl: call physio\n")); 24717c478bd9Sstevel@tonic-gate err = physio(fd_strategy, NULL, dev, 24727c478bd9Sstevel@tonic-gate spc, minphys, uio); 24737c478bd9Sstevel@tonic-gate break; 24747c478bd9Sstevel@tonic-gate } else if (fc.fdc_cmd != FDCMD_FORMAT_TRACK) { 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate /* 24777c478bd9Sstevel@tonic-gate * The manpage states that only the FDCMD_WRITE, 24787c478bd9Sstevel@tonic-gate * FDCMD_READ, and the FDCMD_FORMAT_TR are available. 24797c478bd9Sstevel@tonic-gate */ 24807c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_IOCT, 24817c478bd9Sstevel@tonic-gate (C, "fd_ioctl: FDIOCMD invalid command\n")); 24827c478bd9Sstevel@tonic-gate err = EINVAL; 24837c478bd9Sstevel@tonic-gate break; 24847c478bd9Sstevel@tonic-gate } 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate /* The command is FDCMD_FORMAT_TRACK */ 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate spt = un->un_chars->fdc_secptrack; /* sec/trk */ 24897c478bd9Sstevel@tonic-gate spc = un->un_chars->fdc_nhead * spt; /* sec/cyl */ 24907c478bd9Sstevel@tonic-gate cyl = fc.fdc_blkno / spc; 24917c478bd9Sstevel@tonic-gate hd = (fc.fdc_blkno % spc) / spt; 24927c478bd9Sstevel@tonic-gate 24937c478bd9Sstevel@tonic-gate /* 24947c478bd9Sstevel@tonic-gate * Make sure the specified block number is in the correct 24957c478bd9Sstevel@tonic-gate * range. (block numbers start at 0) 24967c478bd9Sstevel@tonic-gate */ 24977c478bd9Sstevel@tonic-gate nblks = spc * un->un_chars->fdc_ncyl; 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate if (fc.fdc_blkno < 0 || fc.fdc_blkno > (nblks - 1)) { 25007c478bd9Sstevel@tonic-gate err = EINVAL; 25017c478bd9Sstevel@tonic-gate break; 25027c478bd9Sstevel@tonic-gate } 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 25057c478bd9Sstevel@tonic-gate 25067c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 25077c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 25087c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 25097c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 25107c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON)) 25117c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 25127c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \ 25137c478bd9Sstevel@tonic-gate change failed. \n")); 25147c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 25157c478bd9Sstevel@tonic-gate return (EIO); 25167c478bd9Sstevel@tonic-gate } 25177c478bd9Sstevel@tonic-gate 25187c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 25197c478bd9Sstevel@tonic-gate } 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate if (fdformat(fdc, unit, cyl, hd)) 25227c478bd9Sstevel@tonic-gate err = EIO; 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 25257c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate break; 25287c478bd9Sstevel@tonic-gate } 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate case FDRAW: 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate (void) pm_busy_component(fdc->c_dip, 0); 25337c478bd9Sstevel@tonic-gate err = fdrawioctl(fdc, unit, arg, flag); 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 25367c478bd9Sstevel@tonic-gate 25377c478bd9Sstevel@tonic-gate break; 25387c478bd9Sstevel@tonic-gate #ifdef FD_DEBUG 25397c478bd9Sstevel@tonic-gate case IOCTL_DEBUG: 25407c478bd9Sstevel@tonic-gate fderrlevel--; 25417c478bd9Sstevel@tonic-gate if (fderrlevel < 0) 25427c478bd9Sstevel@tonic-gate fderrlevel = 3; 25437c478bd9Sstevel@tonic-gate cmn_err(C, "fdioctl: CHANGING debug to %d", fderrlevel); 25447c478bd9Sstevel@tonic-gate return (0); 25457c478bd9Sstevel@tonic-gate #endif /* FD_DEBUG */ 25467c478bd9Sstevel@tonic-gate default: 25477c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_IOCT, 25487c478bd9Sstevel@tonic-gate (C, "fd_ioctl: invalid ioctl 0x%x\n", cmd)); 25497c478bd9Sstevel@tonic-gate err = ENOTTY; 25507c478bd9Sstevel@tonic-gate break; 25517c478bd9Sstevel@tonic-gate } 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate return (err); 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /* 25577c478bd9Sstevel@tonic-gate * fdrawioctl 25587c478bd9Sstevel@tonic-gate * 25597c478bd9Sstevel@tonic-gate * - acquires the low level lock 25607c478bd9Sstevel@tonic-gate */ 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate static int 25637c478bd9Sstevel@tonic-gate fdrawioctl(struct fdctlr *fdc, int unit, intptr_t arg, int mode) 25647c478bd9Sstevel@tonic-gate { 25657c478bd9Sstevel@tonic-gate struct fd_raw fdr; 25667c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 25677c478bd9Sstevel@tonic-gate struct fd_raw32 fdr32; 25687c478bd9Sstevel@tonic-gate #endif 25697c478bd9Sstevel@tonic-gate struct fdcsb *csb; 25707c478bd9Sstevel@tonic-gate int i, err, flag; 25717c478bd9Sstevel@tonic-gate caddr_t fa; 25727c478bd9Sstevel@tonic-gate uint_t fc; 25737c478bd9Sstevel@tonic-gate size_t real_length; 25747c478bd9Sstevel@tonic-gate int res; 25757c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 25767c478bd9Sstevel@tonic-gate ddi_acc_handle_t mem_handle; 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 25797c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 25807c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate flag = B_READ; 25857c478bd9Sstevel@tonic-gate err = 0; 25867c478bd9Sstevel@tonic-gate fa = NULL; 25877c478bd9Sstevel@tonic-gate fc = (uint_t)0; 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate /* Copy in the arguments */ 25907c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode)) { 25917c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 25927c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 25937c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr32, 25947c478bd9Sstevel@tonic-gate sizeof (fdr32), mode)) { 25957c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 25967c478bd9Sstevel@tonic-gate (C, "fdrawioctl: copyin error, args32\n")); 25977c478bd9Sstevel@tonic-gate return (EFAULT); 25987c478bd9Sstevel@tonic-gate } 25997c478bd9Sstevel@tonic-gate bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd)); 26007c478bd9Sstevel@tonic-gate fdr.fdr_cnum = fdr32.fdr_cnum; 26017c478bd9Sstevel@tonic-gate bcopy(fdr32.fdr_result, fdr.fdr_result, 26027c478bd9Sstevel@tonic-gate sizeof (fdr.fdr_result)); 26037c478bd9Sstevel@tonic-gate fdr.fdr_nbytes = fdr32.fdr_nbytes; 260429df58e5Spc157239 fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr; 26057c478bd9Sstevel@tonic-gate break; 26067c478bd9Sstevel@tonic-gate #endif 26077c478bd9Sstevel@tonic-gate default: 26087c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 26097c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr, 26107c478bd9Sstevel@tonic-gate sizeof (fdr), mode)) { 26117c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 26127c478bd9Sstevel@tonic-gate (C, "fdrawioctl: copyin error, args\n")); 26137c478bd9Sstevel@tonic-gate return (EFAULT); 26147c478bd9Sstevel@tonic-gate } 26157c478bd9Sstevel@tonic-gate break; 26167c478bd9Sstevel@tonic-gate } 26177c478bd9Sstevel@tonic-gate 2618*427f591eSFred Herard FDERRPRINT(FDEP_L1, FDEM_RAWI, 2619*427f591eSFred Herard (C, "fdrawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0])); 2620*427f591eSFred Herard 26217c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 26267c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 26277c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON)) 26287c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 26297c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \ 26307c478bd9Sstevel@tonic-gate failed. \n")); 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 26337c478bd9Sstevel@tonic-gate return (EIO); 26347c478bd9Sstevel@tonic-gate } 26357c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 26367c478bd9Sstevel@tonic-gate } 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 26397c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 26407c478bd9Sstevel@tonic-gate csb->csb_unit = (uchar_t)unit; 26417c478bd9Sstevel@tonic-gate 26427c478bd9Sstevel@tonic-gate /* copy cmd bytes into csb */ 26437c478bd9Sstevel@tonic-gate for (i = 0; i <= fdr.fdr_cnum; i++) 26447c478bd9Sstevel@tonic-gate csb->csb_cmds[i] = fdr.fdr_cmd[i]; 26457c478bd9Sstevel@tonic-gate csb->csb_ncmds = (uchar_t)fdr.fdr_cnum; 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate csb->csb_maxretry = 0; /* let the application deal with errors */ 26487c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 26497c478bd9Sstevel@tonic-gate 26507c478bd9Sstevel@tonic-gate switch (fdr.fdr_cmd[0] & 0x0f) { 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate case FDRAW_SPECIFY: 26537c478bd9Sstevel@tonic-gate /* 26547c478bd9Sstevel@tonic-gate * Ensure that the right DMA mode is selected. There is 26557c478bd9Sstevel@tonic-gate * currently no way for the user to tell if DMA is 26567c478bd9Sstevel@tonic-gate * happening so set the value for the user. 26577c478bd9Sstevel@tonic-gate */ 26587c478bd9Sstevel@tonic-gate 26597c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) 26607c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = csb->csb_cmds[2] & 0xFE; 26617c478bd9Sstevel@tonic-gate else 26627c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = csb->csb_cmds[2] | 0x1; 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFNORESULTS; 26657c478bd9Sstevel@tonic-gate csb->csb_nrslts = 0; 26667c478bd9Sstevel@tonic-gate break; 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate case FDRAW_SENSE_DRV: 26697c478bd9Sstevel@tonic-gate /* Insert the appropriate drive number */ 26707c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK); 26717c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFIMMEDIATE; 26727c478bd9Sstevel@tonic-gate csb->csb_nrslts = 1; 26737c478bd9Sstevel@tonic-gate break; 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate case FDRAW_REZERO: 26767c478bd9Sstevel@tonic-gate case FDRAW_SEEK: 26777c478bd9Sstevel@tonic-gate /* Insert the appropriate drive number */ 26787c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK); 26797c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFSEEKOPS + CSB_OFTIMEIT; 26807c478bd9Sstevel@tonic-gate csb->csb_nrslts = 2; 26817c478bd9Sstevel@tonic-gate break; 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate case FDRAW_FORMAT: 26847c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 26857c478bd9Sstevel@tonic-gate (C, "fdrawioctl: cmd is fdfraw format\n")); 26867c478bd9Sstevel@tonic-gate 26877c478bd9Sstevel@tonic-gate /* Insert the appropriate drive number */ 26887c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK); 26897c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT; 26907c478bd9Sstevel@tonic-gate csb->csb_nrslts = NRBRW; 26917c478bd9Sstevel@tonic-gate flag = B_WRITE; 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate /* 26947c478bd9Sstevel@tonic-gate * Allocate memory for the command. 26957c478bd9Sstevel@tonic-gate * If PIO is being used, then add an extra 16 bytes 26967c478bd9Sstevel@tonic-gate */ 26977c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate fc = (uint_t)(fdr.fdr_nbytes); 27007c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc, 27037c478bd9Sstevel@tonic-gate &attr, DDI_DMA_STREAMING, 27047c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, 0, &fa, &real_length, 27057c478bd9Sstevel@tonic-gate &mem_handle); 27067c478bd9Sstevel@tonic-gate 27077c478bd9Sstevel@tonic-gate if (res != DDI_SUCCESS) { 27087c478bd9Sstevel@tonic-gate fdretcsb(fdc); 27097c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 27107c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 27117c478bd9Sstevel@tonic-gate return (EIO); 27127c478bd9Sstevel@tonic-gate } 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_WRITE; 27157c478bd9Sstevel@tonic-gate if (fdstart_dma(fdc, fa, fc) != 0) { 27167c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 27177c478bd9Sstevel@tonic-gate fdretcsb(fdc); 27187c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 27197c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 27207c478bd9Sstevel@tonic-gate return (EIO); 27217c478bd9Sstevel@tonic-gate } 27227c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate } else { 27257c478bd9Sstevel@tonic-gate fc = (uint_t)(fdr.fdr_nbytes + 16); 27267c478bd9Sstevel@tonic-gate fa = kmem_zalloc(fc, KM_SLEEP); 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate 27297c478bd9Sstevel@tonic-gate /* copy in the user's command bytes */ 27307c478bd9Sstevel@tonic-gate if (ddi_copyin(fdr.fdr_addr, fa, 27317c478bd9Sstevel@tonic-gate (uint_t)fdr.fdr_nbytes, mode)) { 27327c478bd9Sstevel@tonic-gate fdretcsb(fdc); 27337c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 27367c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 27377c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 27387c478bd9Sstevel@tonic-gate (C, "fdrawioctl: (err)free dma memory\n")); 27397c478bd9Sstevel@tonic-gate } else { 27407c478bd9Sstevel@tonic-gate kmem_free(fa, fc); 27417c478bd9Sstevel@tonic-gate } 27427c478bd9Sstevel@tonic-gate 27437c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 27447c478bd9Sstevel@tonic-gate (C, "fdrawioctl: ddi_copyin error\n")); 27457c478bd9Sstevel@tonic-gate return (EFAULT); 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate break; 27497c478bd9Sstevel@tonic-gate case FDRAW_WRCMD: 27507c478bd9Sstevel@tonic-gate case FDRAW_WRITEDEL: 27517c478bd9Sstevel@tonic-gate flag = B_WRITE; 27527c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 27537c478bd9Sstevel@tonic-gate case FDRAW_RDCMD: 27547c478bd9Sstevel@tonic-gate case FDRAW_READDEL: 27557c478bd9Sstevel@tonic-gate case FDRAW_READTRACK: 27567c478bd9Sstevel@tonic-gate /* Insert the appropriate drive number */ 27577c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK); 27587c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) 27597c478bd9Sstevel@tonic-gate csb->csb_cmds[1] |= IPS; 27607c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT; 27617c478bd9Sstevel@tonic-gate csb->csb_nrslts = NRBRW; 27627c478bd9Sstevel@tonic-gate break; 27637c478bd9Sstevel@tonic-gate 27647c478bd9Sstevel@tonic-gate default: 27657c478bd9Sstevel@tonic-gate fdretcsb(fdc); 27667c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 27677c478bd9Sstevel@tonic-gate return (EINVAL); 27687c478bd9Sstevel@tonic-gate } 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate if ((csb->csb_opflags & CSB_OFXFEROPS) && (fdr.fdr_nbytes == 0)) { 27717c478bd9Sstevel@tonic-gate fdretcsb(fdc); 27727c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 27737c478bd9Sstevel@tonic-gate return (EINVAL); 27747c478bd9Sstevel@tonic-gate } 27757c478bd9Sstevel@tonic-gate csb->csb_opflags |= CSB_OFRAWIOCTL; 27767c478bd9Sstevel@tonic-gate 27777c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 27787c478bd9Sstevel@tonic-gate (C, "fdrawioctl: nbytes = %u\n", fdr.fdr_nbytes)); 27797c478bd9Sstevel@tonic-gate 27807c478bd9Sstevel@tonic-gate if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT) { 27817c478bd9Sstevel@tonic-gate if ((fc = (uint_t)fdr.fdr_nbytes) > 0) { 27827c478bd9Sstevel@tonic-gate /* 27837c478bd9Sstevel@tonic-gate * In SunOS 4.X, we used to as_fault things in. 27847c478bd9Sstevel@tonic-gate * We really cannot do this in 5.0/SVr4. Unless 27857c478bd9Sstevel@tonic-gate * someone really believes that speed is of the 27867c478bd9Sstevel@tonic-gate * essence here, it is just much simpler to do 27877c478bd9Sstevel@tonic-gate * this in kernel space and use copyin/copyout. 27887c478bd9Sstevel@tonic-gate */ 27897c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 27907c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 27917c478bd9Sstevel@tonic-gate res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc, 27927c478bd9Sstevel@tonic-gate &attr, DDI_DMA_STREAMING, 27937c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, 0, &fa, &real_length, 27947c478bd9Sstevel@tonic-gate &mem_handle); 27957c478bd9Sstevel@tonic-gate 27967c478bd9Sstevel@tonic-gate if (res != DDI_SUCCESS) { 27977c478bd9Sstevel@tonic-gate fdretcsb(fdc); 27987c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 27997c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 28007c478bd9Sstevel@tonic-gate return (EIO); 28017c478bd9Sstevel@tonic-gate } 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate if (flag == B_WRITE) 28047c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_WRITE; 28057c478bd9Sstevel@tonic-gate else 28067c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_READ; 28077c478bd9Sstevel@tonic-gate 28087c478bd9Sstevel@tonic-gate if (fdstart_dma(fdc, fa, fc) != 0) { 28097c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 28107c478bd9Sstevel@tonic-gate fdretcsb(fdc); 28117c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 28127c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 28137c478bd9Sstevel@tonic-gate return (EIO); 28147c478bd9Sstevel@tonic-gate } 28157c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate } else { 28187c478bd9Sstevel@tonic-gate fa = kmem_zalloc(fc, KM_SLEEP); 28197c478bd9Sstevel@tonic-gate } 28207c478bd9Sstevel@tonic-gate 28217c478bd9Sstevel@tonic-gate if (flag == B_WRITE) { 28227c478bd9Sstevel@tonic-gate if (ddi_copyin(fdr.fdr_addr, fa, fc, mode)) { 28237c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) 28247c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 28257c478bd9Sstevel@tonic-gate else 28267c478bd9Sstevel@tonic-gate kmem_free(fa, fc); 28277c478bd9Sstevel@tonic-gate fdretcsb(fdc); 28287c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 282919397407SSherry Moore FDERRPRINT(FDEP_L1, FDEM_RAWI, (C, 283019397407SSherry Moore "fdrawioctl: can't copy data\n")); 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate return (EFAULT); 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate } 28357c478bd9Sstevel@tonic-gate csb->csb_addr = fa; 28367c478bd9Sstevel@tonic-gate csb->csb_len = fc; 28377c478bd9Sstevel@tonic-gate } else { 28387c478bd9Sstevel@tonic-gate csb->csb_addr = 0; 28397c478bd9Sstevel@tonic-gate csb->csb_len = 0; 28407c478bd9Sstevel@tonic-gate } 28417c478bd9Sstevel@tonic-gate } else { 28427c478bd9Sstevel@tonic-gate csb->csb_addr = fa; 28437c478bd9Sstevel@tonic-gate csb->csb_len = fc; 28447c478bd9Sstevel@tonic-gate } 28457c478bd9Sstevel@tonic-gate 28467c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 28477c478bd9Sstevel@tonic-gate (C, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmds[0], 28487c478bd9Sstevel@tonic-gate csb->csb_cmds[1], csb->csb_cmds[2], csb->csb_cmds[3], 28497c478bd9Sstevel@tonic-gate csb->csb_cmds[4], csb->csb_cmds[5], csb->csb_cmds[6], 28507c478bd9Sstevel@tonic-gate csb->csb_cmds[7], csb->csb_cmds[8], csb->csb_cmds[9])); 28517c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 28527c478bd9Sstevel@tonic-gate (C, "nbytes: %x, opflags: %x, addr: %p, len: %x\n", 28537c478bd9Sstevel@tonic-gate csb->csb_ncmds, csb->csb_opflags, (void *)csb->csb_addr, 28547c478bd9Sstevel@tonic-gate csb->csb_len)); 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate 28577c478bd9Sstevel@tonic-gate /* 28587c478bd9Sstevel@tonic-gate * Note that we ignore any error return s from fdexec. 28597c478bd9Sstevel@tonic-gate * This is the way the driver has been, and it may be 28607c478bd9Sstevel@tonic-gate * that the raw ioctl senders simply don't want to 28617c478bd9Sstevel@tonic-gate * see any errors returned in this fashion. 28627c478bd9Sstevel@tonic-gate */ 28637c478bd9Sstevel@tonic-gate 28647c478bd9Sstevel@tonic-gate if ((csb->csb_opflags & CSB_OFNORESULTS) || 28657c478bd9Sstevel@tonic-gate (csb->csb_opflags & CSB_OFIMMEDIATE)) { 28667c478bd9Sstevel@tonic-gate (void) fdexec(fdc, 0); /* don't sleep, don't check change */ 28677c478bd9Sstevel@tonic-gate } else { 28687c478bd9Sstevel@tonic-gate (void) fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG); 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 28737c478bd9Sstevel@tonic-gate (C, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0], 28747c478bd9Sstevel@tonic-gate csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3], 28757c478bd9Sstevel@tonic-gate csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6], 28767c478bd9Sstevel@tonic-gate csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9])); 28777c478bd9Sstevel@tonic-gate 28787c478bd9Sstevel@tonic-gate if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT && fc && 28797c478bd9Sstevel@tonic-gate flag == B_READ && err == 0) { 28807c478bd9Sstevel@tonic-gate if (ddi_copyout(fa, fdr.fdr_addr, fc, mode)) { 28817c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 28827c478bd9Sstevel@tonic-gate (C, "fdrawioctl: can't copy read data\n")); 28837c478bd9Sstevel@tonic-gate 28847c478bd9Sstevel@tonic-gate err = EFAULT; 28857c478bd9Sstevel@tonic-gate } 28867c478bd9Sstevel@tonic-gate } 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate 28897c478bd9Sstevel@tonic-gate if (fc) { 28907c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 28917c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 28927c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 28937c478bd9Sstevel@tonic-gate (C, "fdrawioctl: free dma memory\n")); 28947c478bd9Sstevel@tonic-gate } else { 28957c478bd9Sstevel@tonic-gate kmem_free(fa, fc); 28967c478bd9Sstevel@tonic-gate } 28977c478bd9Sstevel@tonic-gate } 28987c478bd9Sstevel@tonic-gate 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate /* copy cmd results into fdr */ 29017c478bd9Sstevel@tonic-gate for (i = 0; (int)i <= (int)csb->csb_nrslts; i++) 29027c478bd9Sstevel@tonic-gate fdr.fdr_result[i] = csb->csb_rslt[i]; 29037c478bd9Sstevel@tonic-gate fdr.fdr_nbytes = fdc->c_csb.csb_rlen; /* return resid */ 29047c478bd9Sstevel@tonic-gate 29057c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode)) { 29067c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 29077c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 29087c478bd9Sstevel@tonic-gate bcopy(fdr.fdr_cmd, fdr32.fdr_cmd, sizeof (fdr32.fdr_cmd)); 29097c478bd9Sstevel@tonic-gate fdr32.fdr_cnum = fdr.fdr_cnum; 29107c478bd9Sstevel@tonic-gate bcopy(fdr.fdr_result, fdr32.fdr_result, 29117c478bd9Sstevel@tonic-gate sizeof (fdr32.fdr_result)); 29127c478bd9Sstevel@tonic-gate fdr32.fdr_nbytes = fdr.fdr_nbytes; 291329df58e5Spc157239 fdr32.fdr_addr = (caddr32_t)(uintptr_t)fdr.fdr_addr; 29147c478bd9Sstevel@tonic-gate if (ddi_copyout(&fdr32, (caddr_t)arg, sizeof (fdr32), mode)) { 29157c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 29167c478bd9Sstevel@tonic-gate (C, "fdrawioctl: can't copy results32\n")); 29177c478bd9Sstevel@tonic-gate err = EFAULT; 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate break; 29207c478bd9Sstevel@tonic-gate #endif 29217c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 29227c478bd9Sstevel@tonic-gate default: 29237c478bd9Sstevel@tonic-gate if (ddi_copyout(&fdr, (caddr_t)arg, sizeof (fdr), mode)) { 29247c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 29257c478bd9Sstevel@tonic-gate (C, "fdrawioctl: can't copy results\n")); 29267c478bd9Sstevel@tonic-gate err = EFAULT; 29277c478bd9Sstevel@tonic-gate } 29287c478bd9Sstevel@tonic-gate break; 29297c478bd9Sstevel@tonic-gate } 29307c478bd9Sstevel@tonic-gate 29317c478bd9Sstevel@tonic-gate fdretcsb(fdc); 29327c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 29337c478bd9Sstevel@tonic-gate return (0); 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate /* 29377c478bd9Sstevel@tonic-gate * fdformat 29387c478bd9Sstevel@tonic-gate * format a track 29397c478bd9Sstevel@tonic-gate * For PIO, builds a table of sector data values with 16 bytes 29407c478bd9Sstevel@tonic-gate * (sizeof fdc's fifo) of dummy on end. This is so than when fdc->c_len 29417c478bd9Sstevel@tonic-gate * goes to 0 and fd_intr sends a TC that all the real formatting will 29427c478bd9Sstevel@tonic-gate * have already been done. 29437c478bd9Sstevel@tonic-gate * 29447c478bd9Sstevel@tonic-gate * - called with the low level lock held 29457c478bd9Sstevel@tonic-gate */ 29467c478bd9Sstevel@tonic-gate static int 29477c478bd9Sstevel@tonic-gate fdformat(struct fdctlr *fdc, int unit, int cyl, int hd) 29487c478bd9Sstevel@tonic-gate { 29497c478bd9Sstevel@tonic-gate struct fdcsb *csb; 29507c478bd9Sstevel@tonic-gate struct fdunit *un; 29517c478bd9Sstevel@tonic-gate struct fd_char *ch; 29527c478bd9Sstevel@tonic-gate int cmdresult; 29537c478bd9Sstevel@tonic-gate uchar_t *fmthdrs; 29547c478bd9Sstevel@tonic-gate caddr_t fd; 29557c478bd9Sstevel@tonic-gate int i; 29567c478bd9Sstevel@tonic-gate size_t real_length; 29577c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 29587c478bd9Sstevel@tonic-gate ddi_acc_handle_t mem_handle; 29597c478bd9Sstevel@tonic-gate 29607c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_FORM, 29617c478bd9Sstevel@tonic-gate (C, "fdformat cyl %d, hd %d\n", cyl, hd)); 29627c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 29657c478bd9Sstevel@tonic-gate 29667c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 29677c478bd9Sstevel@tonic-gate un = fdc->c_un; 29687c478bd9Sstevel@tonic-gate ch = un->un_chars; 29697c478bd9Sstevel@tonic-gate 29707c478bd9Sstevel@tonic-gate /* setup common things in csb */ 29717c478bd9Sstevel@tonic-gate csb->csb_unit = (uchar_t)unit; 29727c478bd9Sstevel@tonic-gate 29737c478bd9Sstevel@tonic-gate /* 29747c478bd9Sstevel@tonic-gate * The controller needs to do a seek before 29757c478bd9Sstevel@tonic-gate * each format to get to right cylinder. 29767c478bd9Sstevel@tonic-gate */ 29777c478bd9Sstevel@tonic-gate if (fdrecalseek(fdc, unit, cyl, FDXC_CHECKCHG)) { 29787c478bd9Sstevel@tonic-gate fdretcsb(fdc); 29797c478bd9Sstevel@tonic-gate return (EIO); 29807c478bd9Sstevel@tonic-gate } 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate /* 29837c478bd9Sstevel@tonic-gate * now do the format itself 29847c478bd9Sstevel@tonic-gate */ 29857c478bd9Sstevel@tonic-gate csb->csb_nrslts = NRBRW; 29867c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT; 29877c478bd9Sstevel@tonic-gate 29887c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = FDRAW_FORMAT; 29897c478bd9Sstevel@tonic-gate /* always or in MFM bit */ 29907c478bd9Sstevel@tonic-gate csb->csb_cmds[0] |= MFM; 29917c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = (hd << 2) | (unit & 0x03); 29927c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = ch->fdc_medium ? 3 : 2; 29937c478bd9Sstevel@tonic-gate csb->csb_cmds[3] = ch->fdc_secptrack; 29947c478bd9Sstevel@tonic-gate csb->csb_cmds[4] = GPLF; 29957c478bd9Sstevel@tonic-gate csb->csb_cmds[5] = FDATA; 29967c478bd9Sstevel@tonic-gate csb->csb_ncmds = 6; 29977c478bd9Sstevel@tonic-gate csb->csb_maxretry = rwretry; 29987c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 29997c478bd9Sstevel@tonic-gate 30007c478bd9Sstevel@tonic-gate /* 30017c478bd9Sstevel@tonic-gate * NOTE: have to add size of fifo also - for dummy format action 30027c478bd9Sstevel@tonic-gate * if PIO is being used. 30037c478bd9Sstevel@tonic-gate */ 30047c478bd9Sstevel@tonic-gate 30057c478bd9Sstevel@tonic-gate 30067c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 30077c478bd9Sstevel@tonic-gate 30087c478bd9Sstevel@tonic-gate csb->csb_len = (uint_t)4 * ch->fdc_secptrack; 30097c478bd9Sstevel@tonic-gate 30107c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 30117c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 30127c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 30137c478bd9Sstevel@tonic-gate 30147c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 30157c478bd9Sstevel@tonic-gate 30167c478bd9Sstevel@tonic-gate cmdresult = ddi_dma_mem_alloc(fdc->c_dmahandle, csb->csb_len, 30177c478bd9Sstevel@tonic-gate &attr, DDI_DMA_STREAMING, 30187c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, 0, &fd, &real_length, 30197c478bd9Sstevel@tonic-gate &mem_handle); 30207c478bd9Sstevel@tonic-gate 30217c478bd9Sstevel@tonic-gate if (cmdresult != DDI_SUCCESS) { 30227c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 30237c478bd9Sstevel@tonic-gate return (cmdresult); 30247c478bd9Sstevel@tonic-gate } 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_WRITE; 30277c478bd9Sstevel@tonic-gate if (fdstart_dma(fdc, fd, csb->csb_len) != 0) { 30287c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 30297c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 30307c478bd9Sstevel@tonic-gate return (-1); 30317c478bd9Sstevel@tonic-gate } 30327c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate 30357c478bd9Sstevel@tonic-gate } else { 30367c478bd9Sstevel@tonic-gate csb->csb_len = (uint_t)4 * ch->fdc_secptrack + 16; 30377c478bd9Sstevel@tonic-gate fd = kmem_zalloc(csb->csb_len, KM_SLEEP); 30387c478bd9Sstevel@tonic-gate fmthdrs = (uchar_t *)fd; 30397c478bd9Sstevel@tonic-gate } 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate csb->csb_addr = (caddr_t)fd; 30427c478bd9Sstevel@tonic-gate 30437c478bd9Sstevel@tonic-gate for (i = 1; i <= ch->fdc_secptrack; i++) { 30447c478bd9Sstevel@tonic-gate *fd++ = (uchar_t)cyl; /* cylinder */ 30457c478bd9Sstevel@tonic-gate *fd++ = (uchar_t)hd; /* head */ 30467c478bd9Sstevel@tonic-gate *fd++ = (uchar_t)i; /* sector number */ 30477c478bd9Sstevel@tonic-gate *fd++ = ch->fdc_medium ? 3 : 2; /* sec_size code */ 30487c478bd9Sstevel@tonic-gate } 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate if ((cmdresult = fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG)) == 0) { 30517c478bd9Sstevel@tonic-gate if (csb->csb_cmdstat) 30527c478bd9Sstevel@tonic-gate cmdresult = EIO; /* XXX TBD NYD for now */ 30537c478bd9Sstevel@tonic-gate } 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 30567c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 30577c478bd9Sstevel@tonic-gate } else { 30587c478bd9Sstevel@tonic-gate kmem_free((caddr_t)fmthdrs, csb->csb_len); 30597c478bd9Sstevel@tonic-gate } 30607c478bd9Sstevel@tonic-gate 30617c478bd9Sstevel@tonic-gate fdretcsb(fdc); 30627c478bd9Sstevel@tonic-gate 30637c478bd9Sstevel@tonic-gate return (cmdresult); 30647c478bd9Sstevel@tonic-gate } 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate /* 30677c478bd9Sstevel@tonic-gate * fdstart 30687c478bd9Sstevel@tonic-gate * called from fd_strategy() or from fdXXXX() to setup and 30697c478bd9Sstevel@tonic-gate * start operations of read or write only (using buf structs). 30707c478bd9Sstevel@tonic-gate * Because the chip doesn't handle crossing cylinder boundaries on 30717c478bd9Sstevel@tonic-gate * the fly, this takes care of those boundary conditions. Note that 30727c478bd9Sstevel@tonic-gate * it sleeps until the operation is done *within fdstart* - so that 30737c478bd9Sstevel@tonic-gate * when fdstart returns, the operation is already done. 30747c478bd9Sstevel@tonic-gate * 30757c478bd9Sstevel@tonic-gate * - called with the low level lock held 30767c478bd9Sstevel@tonic-gate * 30777c478bd9Sstevel@tonic-gate */ 30787c478bd9Sstevel@tonic-gate 30797c478bd9Sstevel@tonic-gate static int slavio_index_pulse_work_around = 0; 30807c478bd9Sstevel@tonic-gate 30817c478bd9Sstevel@tonic-gate static void 30827c478bd9Sstevel@tonic-gate fdstart(struct fdctlr *fdc) 30837c478bd9Sstevel@tonic-gate { 30847c478bd9Sstevel@tonic-gate struct buf *bp; 30857c478bd9Sstevel@tonic-gate struct fdcsb *csb; 30867c478bd9Sstevel@tonic-gate struct fdunit *un; 30877c478bd9Sstevel@tonic-gate struct fd_char *ch; 30887c478bd9Sstevel@tonic-gate struct dk_map32 *dkm; 30897c478bd9Sstevel@tonic-gate uint_t part; /* partition number for the transfer */ 30907c478bd9Sstevel@tonic-gate uint_t start_part; /* starting block of the partition */ 30917c478bd9Sstevel@tonic-gate uint_t last_part; /* last block of the partition */ 30927c478bd9Sstevel@tonic-gate uint_t blk; /* starting block of transfer on diskette */ 30937c478bd9Sstevel@tonic-gate uint_t sect; /* starting block's offset into track */ 30947c478bd9Sstevel@tonic-gate uint_t cyl; /* starting cylinder of the transfer */ 30957c478bd9Sstevel@tonic-gate uint_t bincyl; /* starting blocks's offset into cylinder */ 30967c478bd9Sstevel@tonic-gate uint_t secpcyl; /* number of sectors per cylinder */ 30977c478bd9Sstevel@tonic-gate uint_t phys_blkno; /* no. of blocks on the diskette */ 30987c478bd9Sstevel@tonic-gate uint_t head; /* one of two diskette heads */ 30997c478bd9Sstevel@tonic-gate uint_t unit; 31007c478bd9Sstevel@tonic-gate uint_t len, tlen; 31017c478bd9Sstevel@tonic-gate caddr_t addr; 31027c478bd9Sstevel@tonic-gate caddr_t temp_addr; 31037c478bd9Sstevel@tonic-gate uint_t partial_read = 0; 31047c478bd9Sstevel@tonic-gate int sb_temp_buf_used = 0; 31057c478bd9Sstevel@tonic-gate 31067c478bd9Sstevel@tonic-gate bp = fdc->c_actf; 31077c478bd9Sstevel@tonic-gate 31087c478bd9Sstevel@tonic-gate while (bp != NULL) { 31097c478bd9Sstevel@tonic-gate 31107c478bd9Sstevel@tonic-gate fdc->c_actf = bp->av_forw; 31117c478bd9Sstevel@tonic-gate fdc->c_current = bp; 31127c478bd9Sstevel@tonic-gate 31137c478bd9Sstevel@tonic-gate /* 31147c478bd9Sstevel@tonic-gate * Initialize the buf structure. The residual count is 31157c478bd9Sstevel@tonic-gate * initially the number of bytes to be read or written 31167c478bd9Sstevel@tonic-gate */ 31177c478bd9Sstevel@tonic-gate bp->b_flags &= ~B_ERROR; 31187c478bd9Sstevel@tonic-gate bp->b_error = 0; 31197c478bd9Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 31207c478bd9Sstevel@tonic-gate bp_mapin(bp); /* map in buffers */ 31217c478bd9Sstevel@tonic-gate 31227c478bd9Sstevel@tonic-gate addr = bp->b_un.b_addr; /* assign buffer address */ 31237c478bd9Sstevel@tonic-gate 31247c478bd9Sstevel@tonic-gate /* 31257c478bd9Sstevel@tonic-gate * Find the unit and partition numbers. 31267c478bd9Sstevel@tonic-gate */ 31277c478bd9Sstevel@tonic-gate unit = fdc->c_un->un_unit_no; 31287c478bd9Sstevel@tonic-gate un = fdc->c_un; 31297c478bd9Sstevel@tonic-gate ch = un->un_chars; 31307c478bd9Sstevel@tonic-gate part = FDPARTITION(bp->b_edev); 31317c478bd9Sstevel@tonic-gate dkm = &un->un_label.dkl_map[part]; 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate if (un->un_chars->fdc_medium) { 31347c478bd9Sstevel@tonic-gate phys_blkno = bp->b_blkno >> 1; 31357c478bd9Sstevel@tonic-gate } else { 31367c478bd9Sstevel@tonic-gate phys_blkno = bp->b_blkno; 31377c478bd9Sstevel@tonic-gate } 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate if (un->un_iostat) { 31407c478bd9Sstevel@tonic-gate kstat_waitq_to_runq(KIOSP); 31417c478bd9Sstevel@tonic-gate } 31427c478bd9Sstevel@tonic-gate 31437c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRT, 31447c478bd9Sstevel@tonic-gate (C, "fdstart: bp=0x%p blkno=0x%x bcount=0x%x\n", 31457c478bd9Sstevel@tonic-gate (void *)bp, (int)bp->b_blkno, (int)bp->b_bcount)); 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate /* 31487c478bd9Sstevel@tonic-gate * Get the csb and initialize the values that are the same 31497c478bd9Sstevel@tonic-gate * for DMA and PIO. 31507c478bd9Sstevel@tonic-gate */ 31517c478bd9Sstevel@tonic-gate fdgetcsb(fdc); /* get csb (maybe wait for it) */ 31527c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 31537c478bd9Sstevel@tonic-gate csb->csb_unit = unit; /* floppy unit number */ 31547c478bd9Sstevel@tonic-gate 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate /* 31577c478bd9Sstevel@tonic-gate * bugID:4133425 : If the controller is SLAVIO, and 31587c478bd9Sstevel@tonic-gate * the read does not reach end of track, then modify 31597c478bd9Sstevel@tonic-gate * the tlen to read until the end of track to a temp 31607c478bd9Sstevel@tonic-gate * buffer and disable MT. After the read is over, 31617c478bd9Sstevel@tonic-gate * copy the useful portion of the data to 'addr'. 31627c478bd9Sstevel@tonic-gate * Enable this feature only when 31637c478bd9Sstevel@tonic-gate * slavio_index_pulse_work_aound variable is 31647c478bd9Sstevel@tonic-gate * set in /etc/system. 31657c478bd9Sstevel@tonic-gate */ 31667c478bd9Sstevel@tonic-gate 31677c478bd9Sstevel@tonic-gate 31687c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 31697c478bd9Sstevel@tonic-gate if (((fdc->c_fdtype & FDCTYPE_SLAVIO) && 31707c478bd9Sstevel@tonic-gate slavio_index_pulse_work_around) || 31717c478bd9Sstevel@tonic-gate (fdc->c_fdtype & FDCTYPE_TCBUG)) 31727c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = SK | FDRAW_RDCMD | MFM; 31737c478bd9Sstevel@tonic-gate else 31747c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = MT | SK | FDRAW_RDCMD | MFM; 31757c478bd9Sstevel@tonic-gate } else { 31767c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_TCBUG) 31777c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = FDRAW_WRCMD | MFM; 31787c478bd9Sstevel@tonic-gate else 31797c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = MT | FDRAW_WRCMD | MFM; 31807c478bd9Sstevel@tonic-gate } 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate 31837c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) 31847c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_READ; 31857c478bd9Sstevel@tonic-gate else 31867c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_WRITE; 31877c478bd9Sstevel@tonic-gate 31887c478bd9Sstevel@tonic-gate 31897c478bd9Sstevel@tonic-gate csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size */ 31907c478bd9Sstevel@tonic-gate csb->csb_cmds[6] = ch->fdc_secptrack; /* EOT-# of sectors/trk */ 31917c478bd9Sstevel@tonic-gate csb->csb_cmds[7] = GPLN; /* GPL - gap 3 size code */ 31927c478bd9Sstevel@tonic-gate csb->csb_cmds[8] = SSSDTL; /* DTL - be 0xFF if N != 0 */ 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate csb->csb_ncmds = NCBRW; /* number of command bytes */ 31957c478bd9Sstevel@tonic-gate csb->csb_nrslts = NRBRW; /* number of result bytes */ 31967c478bd9Sstevel@tonic-gate 31977c478bd9Sstevel@tonic-gate 31987c478bd9Sstevel@tonic-gate /* 31997c478bd9Sstevel@tonic-gate * opflags for interrupt handler, et.al. 32007c478bd9Sstevel@tonic-gate */ 32017c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT; 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate 32047c478bd9Sstevel@tonic-gate /* 32057c478bd9Sstevel@tonic-gate * Make sure the transfer does not go off the end 32067c478bd9Sstevel@tonic-gate * of the partition. Limit the actual amount transferred 32077c478bd9Sstevel@tonic-gate * to fit the partition. 32087c478bd9Sstevel@tonic-gate */ 32097c478bd9Sstevel@tonic-gate 32107c478bd9Sstevel@tonic-gate blk = phys_blkno; 32117c478bd9Sstevel@tonic-gate start_part = (dkm->dkl_cylno * ch->fdc_secptrack 32127c478bd9Sstevel@tonic-gate * ch->fdc_nhead); 32137c478bd9Sstevel@tonic-gate blk = blk + start_part; 32147c478bd9Sstevel@tonic-gate last_part = start_part + dkm->dkl_nblk; 32157c478bd9Sstevel@tonic-gate 32167c478bd9Sstevel@tonic-gate if ((blk + (bp->b_bcount / ch->fdc_sec_size)) > last_part) 32177c478bd9Sstevel@tonic-gate len = (last_part - blk) * ch->fdc_sec_size; 32187c478bd9Sstevel@tonic-gate else 32197c478bd9Sstevel@tonic-gate len = (uint_t)bp->b_bcount; 32207c478bd9Sstevel@tonic-gate 32217c478bd9Sstevel@tonic-gate /* 32227c478bd9Sstevel@tonic-gate * now we have the real start blk, 32237c478bd9Sstevel@tonic-gate * addr and len for xfer op 32247c478bd9Sstevel@tonic-gate * sectors per cylinder 32257c478bd9Sstevel@tonic-gate */ 32267c478bd9Sstevel@tonic-gate secpcyl = ch->fdc_nhead * ch->fdc_secptrack; 32277c478bd9Sstevel@tonic-gate 32287c478bd9Sstevel@tonic-gate /* 32297c478bd9Sstevel@tonic-gate * The controller can transfer up to a cylinder at a time. 32307c478bd9Sstevel@tonic-gate * Early revs of the 82077 have a bug that causes the chip to 32317c478bd9Sstevel@tonic-gate * fail to respond to the Terminal Count signal. Due to this 32327c478bd9Sstevel@tonic-gate * bug, controllers with type FDCTYPE_TCBUG, only transfer up 32337c478bd9Sstevel@tonic-gate * to a track at a time. 32347c478bd9Sstevel@tonic-gate * See earlier comment for bugID:4133425 for index pulse 32357c478bd9Sstevel@tonic-gate * work around. 32367c478bd9Sstevel@tonic-gate */ 32377c478bd9Sstevel@tonic-gate 32387c478bd9Sstevel@tonic-gate while (len != 0) { 32397c478bd9Sstevel@tonic-gate 32407c478bd9Sstevel@tonic-gate cyl = blk / secpcyl; /* cylinder of transfer */ 32417c478bd9Sstevel@tonic-gate bincyl = blk % secpcyl; /* blk within cylinder */ 32427c478bd9Sstevel@tonic-gate head = bincyl / ch->fdc_secptrack; 32437c478bd9Sstevel@tonic-gate sect = (bincyl % ch->fdc_secptrack) + 1; 32447c478bd9Sstevel@tonic-gate /* sect w/in track */ 32457c478bd9Sstevel@tonic-gate 32467c478bd9Sstevel@tonic-gate /* 32477c478bd9Sstevel@tonic-gate * If the desired block and length will go beyond the 32487c478bd9Sstevel@tonic-gate * cylinder end, limit it to the cylinder end. 32497c478bd9Sstevel@tonic-gate */ 32507c478bd9Sstevel@tonic-gate 32517c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_SLAVIO) && 32527c478bd9Sstevel@tonic-gate slavio_index_pulse_work_around && 32537c478bd9Sstevel@tonic-gate (fdc->c_csb.csb_read == CSB_READ)) { 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate tlen = (ch->fdc_secptrack - sect + 1) * 32567c478bd9Sstevel@tonic-gate ch->fdc_sec_size; 32577c478bd9Sstevel@tonic-gate if (len < tlen) { 32587c478bd9Sstevel@tonic-gate partial_read = 1; 32597c478bd9Sstevel@tonic-gate temp_addr = (caddr_t)kmem_alloc(tlen, 32607c478bd9Sstevel@tonic-gate KM_SLEEP); 32617c478bd9Sstevel@tonic-gate } 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate } else if (fdc->c_fdtype & FDCTYPE_TCBUG) { 32647c478bd9Sstevel@tonic-gate tlen = len; 32657c478bd9Sstevel@tonic-gate if (len > ((ch->fdc_secptrack - sect + 1) * 32667c478bd9Sstevel@tonic-gate ch->fdc_sec_size)) 32677c478bd9Sstevel@tonic-gate tlen = (ch->fdc_secptrack - sect + 1) 32687c478bd9Sstevel@tonic-gate * ch->fdc_sec_size; 32697c478bd9Sstevel@tonic-gate } else { 32707c478bd9Sstevel@tonic-gate if (len > ((secpcyl - bincyl) 32717c478bd9Sstevel@tonic-gate * ch->fdc_sec_size)) 32727c478bd9Sstevel@tonic-gate tlen = (secpcyl - bincyl) 32737c478bd9Sstevel@tonic-gate * ch->fdc_sec_size; 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate else 32767c478bd9Sstevel@tonic-gate tlen = len; 32777c478bd9Sstevel@tonic-gate } 32787c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 32797c478bd9Sstevel@tonic-gate /* 32807c478bd9Sstevel@tonic-gate * To avoid underrun errors during IFB activity. 32817c478bd9Sstevel@tonic-gate */ 32827c478bd9Sstevel@tonic-gate if (tlen > max_fd_dma_len) 32837c478bd9Sstevel@tonic-gate tlen = max_fd_dma_len; 32847c478bd9Sstevel@tonic-gate } 32857c478bd9Sstevel@tonic-gate 32867c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRT, 32877c478bd9Sstevel@tonic-gate (C, " blk 0x%x, addr 0x%p, len 0x%x\n", 32887c478bd9Sstevel@tonic-gate blk, (void *)addr, len)); 32897c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRT, 32907c478bd9Sstevel@tonic-gate (C, "cyl:%x, head:%x, sec:%x\n", 32917c478bd9Sstevel@tonic-gate cyl, head, sect)); 32927c478bd9Sstevel@tonic-gate 32937c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRT, 32947c478bd9Sstevel@tonic-gate (C, " resid 0x%lx, tlen %d\n", 32957c478bd9Sstevel@tonic-gate bp->b_resid, tlen)); 32967c478bd9Sstevel@tonic-gate 32977c478bd9Sstevel@tonic-gate /* 32987c478bd9Sstevel@tonic-gate * Finish programming the command 32997c478bd9Sstevel@tonic-gate */ 33007c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = (head << 2) | unit; 33017c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) 33027c478bd9Sstevel@tonic-gate csb->csb_cmds[1] |= IPS; 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = cyl; /* C - cylinder address */ 33057c478bd9Sstevel@tonic-gate csb->csb_cmds[3] = head; /* H - head number */ 33067c478bd9Sstevel@tonic-gate csb->csb_cmds[4] = sect; /* R - sector number */ 33077c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_TCBUG) 33087c478bd9Sstevel@tonic-gate csb->csb_cmds[6] = sect + 33097c478bd9Sstevel@tonic-gate (tlen / ch->fdc_sec_size) - 1; 33107c478bd9Sstevel@tonic-gate 33117c478bd9Sstevel@tonic-gate csb->csb_len = tlen; 33127c478bd9Sstevel@tonic-gate if (partial_read) 33137c478bd9Sstevel@tonic-gate csb->csb_addr = temp_addr; 33147c478bd9Sstevel@tonic-gate else 33157c478bd9Sstevel@tonic-gate csb->csb_addr = addr; 33167c478bd9Sstevel@tonic-gate 33177c478bd9Sstevel@tonic-gate /* retry this many times max */ 33187c478bd9Sstevel@tonic-gate csb->csb_maxretry = rwretry; 33197c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 33207c478bd9Sstevel@tonic-gate 33217c478bd9Sstevel@tonic-gate /* If platform supports DMA, set up DMA resources */ 33227c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 33237c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_SB) && 332429df58e5Spc157239 (((uint32_t)(uintptr_t)addr & 0xFFFF0000) != 332529df58e5Spc157239 (((uint32_t)(uintptr_t)addr + tlen) & 332629df58e5Spc157239 0xFFFF0000))) { 33277c478bd9Sstevel@tonic-gate csb->csb_addr = fdc->dma_buf; 33287c478bd9Sstevel@tonic-gate sb_temp_buf_used = 1; 33297c478bd9Sstevel@tonic-gate if (csb->csb_read != CSB_READ) { 33307c478bd9Sstevel@tonic-gate bcopy(addr, fdc->dma_buf, tlen); 33317c478bd9Sstevel@tonic-gate } 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate if (fdstart_dma(fdc, csb->csb_addr, 33367c478bd9Sstevel@tonic-gate tlen) != 0) { 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate bp->b_flags |= B_ERROR; 33397c478bd9Sstevel@tonic-gate bp->b_error = EAGAIN; 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 33427c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRT, 33437c478bd9Sstevel@tonic-gate (C, "fdstart: no dma resources\n")); 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate break; 33467c478bd9Sstevel@tonic-gate } 33477c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 33487c478bd9Sstevel@tonic-gate 33497c478bd9Sstevel@tonic-gate } 33507c478bd9Sstevel@tonic-gate 33517c478bd9Sstevel@tonic-gate bp->b_error = fdexec(fdc, FDXC_SLEEP|FDXC_CHECKCHG); 33527c478bd9Sstevel@tonic-gate if (bp->b_error != 0) { 33537c478bd9Sstevel@tonic-gate /* 33547c478bd9Sstevel@tonic-gate * error in fdexec 33557c478bd9Sstevel@tonic-gate */ 33567c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRT, (C, 33577c478bd9Sstevel@tonic-gate "fdstart: bad exec of bp: 0x%p, err %d\n", 33587c478bd9Sstevel@tonic-gate (void *)bp, bp->b_error)); 33597c478bd9Sstevel@tonic-gate 33607c478bd9Sstevel@tonic-gate bp->b_flags |= B_ERROR; 33617c478bd9Sstevel@tonic-gate if (partial_read) { 33627c478bd9Sstevel@tonic-gate partial_read = 0; 33637c478bd9Sstevel@tonic-gate kmem_free(temp_addr, tlen); 33647c478bd9Sstevel@tonic-gate } 33657c478bd9Sstevel@tonic-gate break; 33667c478bd9Sstevel@tonic-gate } 33677c478bd9Sstevel@tonic-gate 33687c478bd9Sstevel@tonic-gate /* 33697c478bd9Sstevel@tonic-gate * If it was a partial read, copy the useful 33707c478bd9Sstevel@tonic-gate * portion of data to 'addr'. 33717c478bd9Sstevel@tonic-gate */ 33727c478bd9Sstevel@tonic-gate if (partial_read) { 33737c478bd9Sstevel@tonic-gate partial_read = 0; 33747c478bd9Sstevel@tonic-gate bcopy(temp_addr, addr, len); 33757c478bd9Sstevel@tonic-gate kmem_free(temp_addr, tlen); 33767c478bd9Sstevel@tonic-gate tlen = len; 33777c478bd9Sstevel@tonic-gate } 33787c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_SB) && 33797c478bd9Sstevel@tonic-gate (csb->csb_read == CSB_READ)) { 33807c478bd9Sstevel@tonic-gate if (sb_temp_buf_used) { 33817c478bd9Sstevel@tonic-gate bcopy(fdc->dma_buf, addr, tlen); 33827c478bd9Sstevel@tonic-gate sb_temp_buf_used = 0; 33837c478bd9Sstevel@tonic-gate } 33847c478bd9Sstevel@tonic-gate } 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate blk += tlen / ch->fdc_sec_size; 33877c478bd9Sstevel@tonic-gate len -= tlen; 33887c478bd9Sstevel@tonic-gate addr += tlen; 33897c478bd9Sstevel@tonic-gate bp->b_resid -= tlen; 33907c478bd9Sstevel@tonic-gate 33917c478bd9Sstevel@tonic-gate } 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRT, 33947c478bd9Sstevel@tonic-gate (C, "fdstart done: b_resid %lu, b_count %lu, csb_rlen %d\n", 33957c478bd9Sstevel@tonic-gate bp->b_resid, bp->b_bcount, fdc->c_csb.csb_rlen)); 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate fdc->c_current = 0; 33987c478bd9Sstevel@tonic-gate fdretcsb(fdc); 33997c478bd9Sstevel@tonic-gate if (un->un_iostat) { 34007c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 34017c478bd9Sstevel@tonic-gate KIOSP->reads++; 34027c478bd9Sstevel@tonic-gate KIOSP->nread += 34037c478bd9Sstevel@tonic-gate (bp->b_bcount - bp->b_resid); 34047c478bd9Sstevel@tonic-gate } else { 34057c478bd9Sstevel@tonic-gate KIOSP->writes++; 34067c478bd9Sstevel@tonic-gate KIOSP->nwritten += (bp->b_bcount - bp->b_resid); 34077c478bd9Sstevel@tonic-gate } 34087c478bd9Sstevel@tonic-gate kstat_runq_exit(KIOSP); 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate biodone(bp); 34117c478bd9Sstevel@tonic-gate 34127c478bd9Sstevel@tonic-gate /* 34137c478bd9Sstevel@tonic-gate * Look at the next buffer 34147c478bd9Sstevel@tonic-gate */ 34157c478bd9Sstevel@tonic-gate bp = fdc->c_actf; 34167c478bd9Sstevel@tonic-gate 34177c478bd9Sstevel@tonic-gate } 34187c478bd9Sstevel@tonic-gate } 34197c478bd9Sstevel@tonic-gate 34207c478bd9Sstevel@tonic-gate /* 34217c478bd9Sstevel@tonic-gate * Set up DMA resources 34227c478bd9Sstevel@tonic-gate * The DMA handle was initialized in fd_attach() 34237c478bd9Sstevel@tonic-gate * Assumes the handle has already been allocated by fd_attach() 34247c478bd9Sstevel@tonic-gate */ 34257c478bd9Sstevel@tonic-gate static int 34267c478bd9Sstevel@tonic-gate fdstart_dma(struct fdctlr *fdc, caddr_t addr, uint_t len) 34277c478bd9Sstevel@tonic-gate { 34287c478bd9Sstevel@tonic-gate int flags; /* flags for setting up resources */ 34297c478bd9Sstevel@tonic-gate int res; 34307c478bd9Sstevel@tonic-gate 34317c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: start\n")); 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate if (fdc->c_csb.csb_read == CSB_READ) { 34347c478bd9Sstevel@tonic-gate flags = DDI_DMA_READ; 34357c478bd9Sstevel@tonic-gate } else { 34367c478bd9Sstevel@tonic-gate flags = DDI_DMA_WRITE; 34377c478bd9Sstevel@tonic-gate } 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate 34407c478bd9Sstevel@tonic-gate /* allow partial mapping to maximize the portability of the driver */ 34417c478bd9Sstevel@tonic-gate flags = flags | DDI_DMA_PARTIAL; 34427c478bd9Sstevel@tonic-gate 34437c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: amt. asked for %d\n", 34447c478bd9Sstevel@tonic-gate len)); 34457c478bd9Sstevel@tonic-gate 34467c478bd9Sstevel@tonic-gate /* 34477c478bd9Sstevel@tonic-gate * Zero out the current cookie. This is done to ensure that 34487c478bd9Sstevel@tonic-gate * the previous transfers cookie information can in no way be 34497c478bd9Sstevel@tonic-gate * used. 34507c478bd9Sstevel@tonic-gate */ 34517c478bd9Sstevel@tonic-gate bzero((char *)&fdc->c_csb.csb_dmacookie, 34527c478bd9Sstevel@tonic-gate sizeof (fdc->c_csb.csb_dmacookie)); 34537c478bd9Sstevel@tonic-gate fdc->c_csb.csb_nwin = 0; 34547c478bd9Sstevel@tonic-gate fdc->c_csb.csb_windex = 0; 34557c478bd9Sstevel@tonic-gate fdc->c_csb.csb_ccount = 0; 34567c478bd9Sstevel@tonic-gate 34577c478bd9Sstevel@tonic-gate res = ddi_dma_addr_bind_handle(fdc->c_dmahandle, NULL, addr, len, 34587c478bd9Sstevel@tonic-gate flags, DDI_DMA_DONTWAIT, 0, &fdc->c_csb.csb_dmacookie, 34597c478bd9Sstevel@tonic-gate &fdc->c_csb.csb_ccount); 34607c478bd9Sstevel@tonic-gate 34617c478bd9Sstevel@tonic-gate switch (res) { 34627c478bd9Sstevel@tonic-gate case DDI_DMA_MAPPED: 34637c478bd9Sstevel@tonic-gate /* 34647c478bd9Sstevel@tonic-gate * There is one window. csb_windex is the index 34657c478bd9Sstevel@tonic-gate * into the array of windows. If there are n 34667c478bd9Sstevel@tonic-gate * windows then, (0 <= windex <= n-1). csb_windex 34677c478bd9Sstevel@tonic-gate * represents the index of the next window 34687c478bd9Sstevel@tonic-gate * to be processed. 34697c478bd9Sstevel@tonic-gate */ 34707c478bd9Sstevel@tonic-gate fdc->c_csb.csb_nwin = 1; 34717c478bd9Sstevel@tonic-gate fdc->c_csb.csb_windex = 1; 34727c478bd9Sstevel@tonic-gate 34737c478bd9Sstevel@tonic-gate 34747c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 34757c478bd9Sstevel@tonic-gate (C, "fdstart_dma: DDI_DMA_MAPPED\n")); 34767c478bd9Sstevel@tonic-gate 34777c478bd9Sstevel@tonic-gate break; 34787c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate /* 34817c478bd9Sstevel@tonic-gate * obtain the number of DMA windows 34827c478bd9Sstevel@tonic-gate */ 34837c478bd9Sstevel@tonic-gate if (ddi_dma_numwin(fdc->c_dmahandle, 34847c478bd9Sstevel@tonic-gate &fdc->c_csb.csb_nwin) != DDI_SUCCESS) { 34857c478bd9Sstevel@tonic-gate return (-1); 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate 34887c478bd9Sstevel@tonic-gate 34897c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 34907c478bd9Sstevel@tonic-gate (C, "fdstart_dma: partially mapped %d windows\n", 34917c478bd9Sstevel@tonic-gate fdc->c_csb.csb_nwin)); 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate /* 34947c478bd9Sstevel@tonic-gate * The DMA window currently in use is window number 34957c478bd9Sstevel@tonic-gate * one. 34967c478bd9Sstevel@tonic-gate */ 34977c478bd9Sstevel@tonic-gate fdc->c_csb.csb_windex = 1; 34987c478bd9Sstevel@tonic-gate 34997c478bd9Sstevel@tonic-gate break; 35007c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 35017c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 35027c478bd9Sstevel@tonic-gate (C, "fdstart_dma: no resources\n")); 35037c478bd9Sstevel@tonic-gate return (-1); 35047c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 35057c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 35067c478bd9Sstevel@tonic-gate (C, "fdstart_dma: no mapping\n")); 35077c478bd9Sstevel@tonic-gate return (-1); 35087c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 35097c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 35107c478bd9Sstevel@tonic-gate (C, "fdstart_dma: too big\n")); 35117c478bd9Sstevel@tonic-gate return (-1); 35127c478bd9Sstevel@tonic-gate 35137c478bd9Sstevel@tonic-gate case DDI_DMA_INUSE: 35147c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 35157c478bd9Sstevel@tonic-gate (C, "fdstart_dma: dma inuse\n")); 35167c478bd9Sstevel@tonic-gate return (-1); 35177c478bd9Sstevel@tonic-gate default: 35187c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 35197c478bd9Sstevel@tonic-gate (C, "fdstart_dma: result is 0x%x\n", res)); 35207c478bd9Sstevel@tonic-gate return (-1); 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate }; 35237c478bd9Sstevel@tonic-gate 35247c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, 35257c478bd9Sstevel@tonic-gate (C, "fdstart_dma: bound the handle\n")); 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate ASSERT(fdc->c_csb.csb_dmacookie.dmac_size); 35287c478bd9Sstevel@tonic-gate 35297c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: done\n")); 35307c478bd9Sstevel@tonic-gate return (0); 35317c478bd9Sstevel@tonic-gate } 35327c478bd9Sstevel@tonic-gate 35337c478bd9Sstevel@tonic-gate 35347c478bd9Sstevel@tonic-gate /* 35357c478bd9Sstevel@tonic-gate * fd_unbind_handle: unbind a dma handle if one exists 35367c478bd9Sstevel@tonic-gate * return EIO if unbind failes 35377c478bd9Sstevel@tonic-gate */ 35387c478bd9Sstevel@tonic-gate static int 35397c478bd9Sstevel@tonic-gate fd_unbind_handle(struct fdctlr *fdc) 35407c478bd9Sstevel@tonic-gate { 35417c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_DMA) && 35427c478bd9Sstevel@tonic-gate ((fdc->c_csb.csb_read == CSB_READ) || 35437c478bd9Sstevel@tonic-gate (fdc->c_csb.csb_read == CSB_WRITE))) { 35447c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 35457c478bd9Sstevel@tonic-gate 35467c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 35477c478bd9Sstevel@tonic-gate if (fdc->sb_dma_lock) { 35487c478bd9Sstevel@tonic-gate release_sb_dma(fdc); 35497c478bd9Sstevel@tonic-gate } 35507c478bd9Sstevel@tonic-gate } 35517c478bd9Sstevel@tonic-gate 35527c478bd9Sstevel@tonic-gate /* 35537c478bd9Sstevel@tonic-gate * If the byte count isn't zero, then the DMA engine is 35547c478bd9Sstevel@tonic-gate * still doing a transfer. If the byte count is nonzero, 35557c478bd9Sstevel@tonic-gate * reset the DMA engine to cause it to drain. 35567c478bd9Sstevel@tonic-gate */ 35577c478bd9Sstevel@tonic-gate 35587c478bd9Sstevel@tonic-gate if (get_data_count_register(fdc) != 0) { 35597c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, 35607c478bd9Sstevel@tonic-gate (C, "unbind & byte count isn't zero\n")); 35617c478bd9Sstevel@tonic-gate 35627c478bd9Sstevel@tonic-gate reset_dma_controller(fdc); 35637c478bd9Sstevel@tonic-gate set_dma_control_register(fdc, DCSR_INIT_BITS); 35647c478bd9Sstevel@tonic-gate } 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate if (ddi_dma_unbind_handle(fdc->c_dmahandle) != DDI_SUCCESS) { 35677c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, 35687c478bd9Sstevel@tonic-gate (C, "problem unbinding the handle\n")); 35697c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 35707c478bd9Sstevel@tonic-gate return (EIO); 35717c478bd9Sstevel@tonic-gate } 35727c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 35737c478bd9Sstevel@tonic-gate } 35747c478bd9Sstevel@tonic-gate return (0); 35757c478bd9Sstevel@tonic-gate } 35767c478bd9Sstevel@tonic-gate 35777c478bd9Sstevel@tonic-gate /* 35787c478bd9Sstevel@tonic-gate * fdexec 35797c478bd9Sstevel@tonic-gate * all commands go through here. Assumes the command block 35807c478bd9Sstevel@tonic-gate * fdctlr.c_csb is filled in. The bytes are sent to the 35817c478bd9Sstevel@tonic-gate * controller and then we do whatever else the csb says - 35827c478bd9Sstevel@tonic-gate * like wait for immediate results, etc. 35837c478bd9Sstevel@tonic-gate * 35847c478bd9Sstevel@tonic-gate * All waiting for operations done is in here - to allow retrys 35857c478bd9Sstevel@tonic-gate * and checking for disk changed - so we don't have to worry 35867c478bd9Sstevel@tonic-gate * about sleeping at interrupt level. 35877c478bd9Sstevel@tonic-gate * 35887c478bd9Sstevel@tonic-gate * RETURNS: 0 if all ok, 35897c478bd9Sstevel@tonic-gate * ENXIO - diskette not in drive 35907c478bd9Sstevel@tonic-gate * EBUSY - if chip is locked or busy 35917c478bd9Sstevel@tonic-gate * EIO - for timeout during sending cmds to chip 35927c478bd9Sstevel@tonic-gate * 35937c478bd9Sstevel@tonic-gate * to sleep: set FDXC_SLEEP, to check for disk 35947c478bd9Sstevel@tonic-gate * changed: set FDXC_CHECKCHG 35957c478bd9Sstevel@tonic-gate * 35967c478bd9Sstevel@tonic-gate * - called with the lock held 35977c478bd9Sstevel@tonic-gate */ 35987c478bd9Sstevel@tonic-gate static int 35997c478bd9Sstevel@tonic-gate fdexec(struct fdctlr *fdc, int flags) 36007c478bd9Sstevel@tonic-gate { 36017c478bd9Sstevel@tonic-gate struct fdcsb *csb; 36027c478bd9Sstevel@tonic-gate int i; 36037c478bd9Sstevel@tonic-gate int to, unit; 36047c478bd9Sstevel@tonic-gate uchar_t tmp; 36057c478bd9Sstevel@tonic-gate caddr_t a = (caddr_t)fdc; 36067c478bd9Sstevel@tonic-gate 36077c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: flags:%x\n", flags)); 36087c478bd9Sstevel@tonic-gate 36097c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&fdc->c_lolock)); 36107c478bd9Sstevel@tonic-gate 36117c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 36127c478bd9Sstevel@tonic-gate unit = csb->csb_unit; 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate 36157c478bd9Sstevel@tonic-gate ASSERT(unit == fdc->c_un->un_unit_no); 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate retry: 36187c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: cmd is %s\n", 36197c478bd9Sstevel@tonic-gate fdcmds[csb->csb_cmds[0] & 0x1f].cmdname)); 36207c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: transfer rate = %d\n", 36217c478bd9Sstevel@tonic-gate fdc->c_un->un_chars->fdc_transfer_rate)); 36227c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: sec size = %d\n", 36237c478bd9Sstevel@tonic-gate fdc->c_un->un_chars->fdc_sec_size)); 36247c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: nblocks (512) = %d\n", 36257c478bd9Sstevel@tonic-gate fdc->c_un->un_label.dkl_map[2].dkl_nblk)); 36267c478bd9Sstevel@tonic-gate 36277c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) { 36287c478bd9Sstevel@tonic-gate fdexec_turn_on_motor(fdc, flags, unit); 36297c478bd9Sstevel@tonic-gate } 36307c478bd9Sstevel@tonic-gate 36317c478bd9Sstevel@tonic-gate 36327c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 1); /* select drive */ 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate /* 36357c478bd9Sstevel@tonic-gate * select data rate for this unit/command 36367c478bd9Sstevel@tonic-gate */ 36377c478bd9Sstevel@tonic-gate switch (fdc->c_un->un_chars->fdc_transfer_rate) { 36387c478bd9Sstevel@tonic-gate case 500: 36397c478bd9Sstevel@tonic-gate Dsr(fdc, 0); 36407c478bd9Sstevel@tonic-gate break; 36417c478bd9Sstevel@tonic-gate case 300: 36427c478bd9Sstevel@tonic-gate Dsr(fdc, 1); 36437c478bd9Sstevel@tonic-gate break; 36447c478bd9Sstevel@tonic-gate case 250: 36457c478bd9Sstevel@tonic-gate Dsr(fdc, 2); 36467c478bd9Sstevel@tonic-gate break; 36477c478bd9Sstevel@tonic-gate } 36487c478bd9Sstevel@tonic-gate drv_usecwait(2); 36497c478bd9Sstevel@tonic-gate 36507c478bd9Sstevel@tonic-gate 36517c478bd9Sstevel@tonic-gate /* 36527c478bd9Sstevel@tonic-gate * If checking for changed is enabled (i.e., not seeking in checkdisk), 36537c478bd9Sstevel@tonic-gate * we sample the DSKCHG line to see if the diskette has wandered away. 36547c478bd9Sstevel@tonic-gate */ 36557c478bd9Sstevel@tonic-gate if ((flags & FDXC_CHECKCHG) && fdsense_chng(fdc, unit)) { 36567c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "diskette changed\n")); 36577c478bd9Sstevel@tonic-gate fdc->c_un->un_flags |= FDUNIT_CHANGED; 36587c478bd9Sstevel@tonic-gate 36597c478bd9Sstevel@tonic-gate if (fdcheckdisk(fdc, unit)) { 36607c478bd9Sstevel@tonic-gate 36617c478bd9Sstevel@tonic-gate (void) fd_unbind_handle(fdc); 36627c478bd9Sstevel@tonic-gate return (ENXIO); 36637c478bd9Sstevel@tonic-gate 36647c478bd9Sstevel@tonic-gate } 36657c478bd9Sstevel@tonic-gate } 36667c478bd9Sstevel@tonic-gate 36677c478bd9Sstevel@tonic-gate /* 36687c478bd9Sstevel@tonic-gate * gather some statistics 36697c478bd9Sstevel@tonic-gate */ 36707c478bd9Sstevel@tonic-gate switch (csb->csb_cmds[0] & 0x1f) { 36717c478bd9Sstevel@tonic-gate case FDRAW_RDCMD: 36727c478bd9Sstevel@tonic-gate fdc->fdstats.rd++; 36737c478bd9Sstevel@tonic-gate break; 36747c478bd9Sstevel@tonic-gate case FDRAW_WRCMD: 36757c478bd9Sstevel@tonic-gate fdc->fdstats.wr++; 36767c478bd9Sstevel@tonic-gate break; 36777c478bd9Sstevel@tonic-gate case FDRAW_REZERO: 36787c478bd9Sstevel@tonic-gate fdc->fdstats.recal++; 36797c478bd9Sstevel@tonic-gate break; 36807c478bd9Sstevel@tonic-gate case FDRAW_FORMAT: 36817c478bd9Sstevel@tonic-gate fdc->fdstats.form++; 36827c478bd9Sstevel@tonic-gate break; 36837c478bd9Sstevel@tonic-gate default: 36847c478bd9Sstevel@tonic-gate fdc->fdstats.other++; 36857c478bd9Sstevel@tonic-gate break; 36867c478bd9Sstevel@tonic-gate } 36877c478bd9Sstevel@tonic-gate 36887c478bd9Sstevel@tonic-gate /* 36897c478bd9Sstevel@tonic-gate * Always set the opmode *prior* to poking the chip. 36907c478bd9Sstevel@tonic-gate * This way we don't have to do any locking at high level. 36917c478bd9Sstevel@tonic-gate */ 36927c478bd9Sstevel@tonic-gate csb->csb_raddr = 0; 36937c478bd9Sstevel@tonic-gate csb->csb_rlen = 0; 36947c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFSEEKOPS) { 36957c478bd9Sstevel@tonic-gate csb->csb_opmode = 2; 36967c478bd9Sstevel@tonic-gate } else if (csb->csb_opflags & CSB_OFIMMEDIATE) { 36977c478bd9Sstevel@tonic-gate csb->csb_opmode = 0; 36987c478bd9Sstevel@tonic-gate } else { 36997c478bd9Sstevel@tonic-gate csb->csb_opmode = 1; /* normal data xfer commands */ 37007c478bd9Sstevel@tonic-gate csb->csb_raddr = csb->csb_addr; 37017c478bd9Sstevel@tonic-gate csb->csb_rlen = csb->csb_len; 37027c478bd9Sstevel@tonic-gate } 37037c478bd9Sstevel@tonic-gate 37047c478bd9Sstevel@tonic-gate bzero((caddr_t)csb->csb_rslt, 10); 37057c478bd9Sstevel@tonic-gate csb->csb_status = 0; 37067c478bd9Sstevel@tonic-gate csb->csb_cmdstat = 0; 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate 37097c478bd9Sstevel@tonic-gate /* 37107c478bd9Sstevel@tonic-gate * Program the DMA engine with the length and address of the transfer 37117c478bd9Sstevel@tonic-gate * (DMA is only used on a read or a write) 37127c478bd9Sstevel@tonic-gate */ 37137c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_DMA) && 37147c478bd9Sstevel@tonic-gate ((fdc->c_csb.csb_read == CSB_READ) || 37157c478bd9Sstevel@tonic-gate (fdc->c_csb.csb_read == CSB_WRITE))) { 37167c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 37177c478bd9Sstevel@tonic-gate 37187c478bd9Sstevel@tonic-gate /* Reset the dcsr to clear it of all errors */ 37197c478bd9Sstevel@tonic-gate 37207c478bd9Sstevel@tonic-gate reset_dma_controller(fdc); 37217c478bd9Sstevel@tonic-gate 37227c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie addr 0x%p\n", 37237c478bd9Sstevel@tonic-gate (void *)fdc->c_csb.csb_dmacookie.dmac_laddress)); 37247c478bd9Sstevel@tonic-gate 37257c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie length %ld\n", 37267c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_size)); 37277c478bd9Sstevel@tonic-gate ASSERT(fdc->c_csb.csb_dmacookie.dmac_size); 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate set_data_count_register(fdc, 37307c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_size); 37317c478bd9Sstevel@tonic-gate set_data_address_register(fdc, 37327c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_laddress); 37337c478bd9Sstevel@tonic-gate 37347c478bd9Sstevel@tonic-gate /* Program the DCSR */ 37357c478bd9Sstevel@tonic-gate 37367c478bd9Sstevel@tonic-gate if (fdc->c_csb.csb_read == CSB_READ) 37377c478bd9Sstevel@tonic-gate set_dma_mode(fdc, CSB_READ); 37387c478bd9Sstevel@tonic-gate else 37397c478bd9Sstevel@tonic-gate set_dma_mode(fdc, CSB_WRITE); 37407c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 37417c478bd9Sstevel@tonic-gate } 37427c478bd9Sstevel@tonic-gate 37437c478bd9Sstevel@tonic-gate /* 37447c478bd9Sstevel@tonic-gate * I saw this (chip unexpectedly busy) happen when i shoved the 37457c478bd9Sstevel@tonic-gate * floppy into the drive while 37467c478bd9Sstevel@tonic-gate * running a dd if= /dev/rfd0c. so it *is* possible for this to happen. 37477c478bd9Sstevel@tonic-gate * we need to do a ctlr reset ... 37487c478bd9Sstevel@tonic-gate */ 37497c478bd9Sstevel@tonic-gate 37507c478bd9Sstevel@tonic-gate if (Msr(fdc) & CB) { 37517c478bd9Sstevel@tonic-gate /* tried to give command to chip when it is busy! */ 37527c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_EXEC, 37537c478bd9Sstevel@tonic-gate (C, "fdc: unexpectedly busy-stat 0x%x\n", Msr(fdc))); 37547c478bd9Sstevel@tonic-gate csb->csb_cmdstat = 1; /* XXX TBD ERRS NYD for now */ 37557c478bd9Sstevel@tonic-gate 37567c478bd9Sstevel@tonic-gate (void) fd_unbind_handle(fdc); 37577c478bd9Sstevel@tonic-gate return (EBUSY); 37587c478bd9Sstevel@tonic-gate } 37597c478bd9Sstevel@tonic-gate 37607c478bd9Sstevel@tonic-gate /* Give command to the controller */ 37617c478bd9Sstevel@tonic-gate for (i = 0; i < (int)csb->csb_ncmds; i++) { 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate /* Test the readiness of the controller to receive the cmd */ 37647c478bd9Sstevel@tonic-gate for (to = FD_CRETRY; to; to--) { 37657c478bd9Sstevel@tonic-gate if ((Msr(fdc) & (DIO|RQM)) == RQM) 37667c478bd9Sstevel@tonic-gate break; 37677c478bd9Sstevel@tonic-gate } 37687c478bd9Sstevel@tonic-gate if (to == 0) { 37697c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_EXEC, 37707c478bd9Sstevel@tonic-gate (C, "fdc: no RQM - stat 0x%x\n", Msr(fdc))); 37717c478bd9Sstevel@tonic-gate csb->csb_cmdstat = 1; 37727c478bd9Sstevel@tonic-gate 37737c478bd9Sstevel@tonic-gate (void) fd_unbind_handle(fdc); 37747c478bd9Sstevel@tonic-gate return (EIO); 37757c478bd9Sstevel@tonic-gate } 37767c478bd9Sstevel@tonic-gate 37777c478bd9Sstevel@tonic-gate Set_Fifo(fdc, csb->csb_cmds[i]); 37787c478bd9Sstevel@tonic-gate 37797c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, 37807c478bd9Sstevel@tonic-gate (C, "fdexec: sent 0x%x, Msr 0x%x\n", csb->csb_cmds[i], 37817c478bd9Sstevel@tonic-gate Msr(fdc))); 37827c478bd9Sstevel@tonic-gate 37837c478bd9Sstevel@tonic-gate } 37847c478bd9Sstevel@tonic-gate 37857c478bd9Sstevel@tonic-gate 37867c478bd9Sstevel@tonic-gate /* 37877c478bd9Sstevel@tonic-gate * Start watchdog timer on data transfer type commands - required 37887c478bd9Sstevel@tonic-gate * in case a diskette is not present or is unformatted 37897c478bd9Sstevel@tonic-gate */ 37907c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFTIMEIT) { 37917c478bd9Sstevel@tonic-gate fdc->c_timeid = timeout(fdwatch, a, 37927c478bd9Sstevel@tonic-gate tosec * drv_usectohz(1000000)); 37937c478bd9Sstevel@tonic-gate } 37947c478bd9Sstevel@tonic-gate 37957c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, 37967c478bd9Sstevel@tonic-gate (C, "fdexec: cmd sent, Msr 0x%x\n", Msr(fdc))); 37977c478bd9Sstevel@tonic-gate 37987c478bd9Sstevel@tonic-gate /* If the operation has no results - then just return */ 37997c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFNORESULTS) { 38007c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_82077) { 38017c478bd9Sstevel@tonic-gate if (fdc->c_mtimeid == 0) { 38027c478bd9Sstevel@tonic-gate fdc->c_mtimeid = timeout(fdmotoff, a, 38037c478bd9Sstevel@tonic-gate Motoff_delay); 38047c478bd9Sstevel@tonic-gate } 38057c478bd9Sstevel@tonic-gate } 38067c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..\n")); 38077c478bd9Sstevel@tonic-gate 38087c478bd9Sstevel@tonic-gate /* 38097c478bd9Sstevel@tonic-gate * Make sure the last byte is received well by the 38107c478bd9Sstevel@tonic-gate * controller. On faster CPU, it may still be busy 38117c478bd9Sstevel@tonic-gate * by the time another command comes here. 38127c478bd9Sstevel@tonic-gate */ 38137c478bd9Sstevel@tonic-gate for (to = FD_CRETRY; to; to--) { 38147c478bd9Sstevel@tonic-gate if ((Msr(fdc) & (DIO|RQM)) == RQM) 38157c478bd9Sstevel@tonic-gate break; 38167c478bd9Sstevel@tonic-gate } 38177c478bd9Sstevel@tonic-gate if (to == 0) { 38187c478bd9Sstevel@tonic-gate csb->csb_cmdstat = 1; 38197c478bd9Sstevel@tonic-gate return (EIO); 38207c478bd9Sstevel@tonic-gate } 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate /* 38237c478bd9Sstevel@tonic-gate * An operation that has no results isn't doing DMA so, 38247c478bd9Sstevel@tonic-gate * there is no reason to try to unbind a handle 38257c478bd9Sstevel@tonic-gate */ 38267c478bd9Sstevel@tonic-gate return (0); 38277c478bd9Sstevel@tonic-gate } 38287c478bd9Sstevel@tonic-gate 38297c478bd9Sstevel@tonic-gate /* 38307c478bd9Sstevel@tonic-gate * If this operation has no interrupt AND an immediate result 38317c478bd9Sstevel@tonic-gate * then we just busy wait for the results and stuff them into 38327c478bd9Sstevel@tonic-gate * the csb 38337c478bd9Sstevel@tonic-gate */ 38347c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFIMMEDIATE) { 38357c478bd9Sstevel@tonic-gate to = FD_RRETRY; 38367c478bd9Sstevel@tonic-gate csb->csb_nrslts = 0; 38377c478bd9Sstevel@tonic-gate /* 38387c478bd9Sstevel@tonic-gate * Wait while this command is still going on. 38397c478bd9Sstevel@tonic-gate */ 38407c478bd9Sstevel@tonic-gate while ((tmp = Msr(fdc)) & CB) { 38417c478bd9Sstevel@tonic-gate /* 38427c478bd9Sstevel@tonic-gate * If RQM + DIO, then a result byte is at hand. 38437c478bd9Sstevel@tonic-gate */ 38447c478bd9Sstevel@tonic-gate if ((tmp & (RQM|DIO|CB)) == (RQM|DIO|CB)) { 38457c478bd9Sstevel@tonic-gate csb->csb_rslt[csb->csb_nrslts++] = 38467c478bd9Sstevel@tonic-gate Fifo(fdc); 38477c478bd9Sstevel@tonic-gate /* 38487c478bd9Sstevel@tonic-gate * FDERRPRINT(FDEP_L4, FDEM_EXEC, 38497c478bd9Sstevel@tonic-gate * (C, "fdexec: got result 0x%x\n", 38507c478bd9Sstevel@tonic-gate * csb->csb_nrslts)); 38517c478bd9Sstevel@tonic-gate */ 38527c478bd9Sstevel@tonic-gate } else if (--to == 0) { 38537c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L4, FDEM_EXEC, 38547c478bd9Sstevel@tonic-gate (C, "fdexec: timeout, Msr%x, nr%x\n", 38557c478bd9Sstevel@tonic-gate Msr(fdc), csb->csb_nrslts)); 38567c478bd9Sstevel@tonic-gate 38577c478bd9Sstevel@tonic-gate csb->csb_status = 2; 38587c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_82077) { 38597c478bd9Sstevel@tonic-gate if (fdc->c_mtimeid == 0) { 38607c478bd9Sstevel@tonic-gate fdc->c_mtimeid = timeout( 38617c478bd9Sstevel@tonic-gate fdmotoff, a, Motoff_delay); 38627c478bd9Sstevel@tonic-gate } 38637c478bd9Sstevel@tonic-gate } 38647c478bd9Sstevel@tonic-gate /* 38657c478bd9Sstevel@tonic-gate * There is no DMA happening. No need to 38667c478bd9Sstevel@tonic-gate * try freeing a handle. 38677c478bd9Sstevel@tonic-gate */ 38687c478bd9Sstevel@tonic-gate 38697c478bd9Sstevel@tonic-gate return (EIO); 38707c478bd9Sstevel@tonic-gate } 38717c478bd9Sstevel@tonic-gate } 38727c478bd9Sstevel@tonic-gate } 38737c478bd9Sstevel@tonic-gate 38747c478bd9Sstevel@tonic-gate /* 38757c478bd9Sstevel@tonic-gate * If told to sleep here, well then sleep! 38767c478bd9Sstevel@tonic-gate */ 38777c478bd9Sstevel@tonic-gate 38787c478bd9Sstevel@tonic-gate if (flags & FDXC_SLEEP) { 38797c478bd9Sstevel@tonic-gate fdc->c_flags |= FDCFLG_WAITING; 38807c478bd9Sstevel@tonic-gate while (fdc->c_flags & FDCFLG_WAITING) { 38817c478bd9Sstevel@tonic-gate cv_wait(&fdc->c_iocv, &fdc->c_lolock); 38827c478bd9Sstevel@tonic-gate } 38837c478bd9Sstevel@tonic-gate } 38847c478bd9Sstevel@tonic-gate 38857c478bd9Sstevel@tonic-gate /* 38867c478bd9Sstevel@tonic-gate * kludge for end-of-cylinder error which must be ignored!!! 38877c478bd9Sstevel@tonic-gate */ 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_TCBUG) && 38907c478bd9Sstevel@tonic-gate ((csb->csb_rslt[0] & IC_SR0) == 0x40) && 38917c478bd9Sstevel@tonic-gate (csb->csb_rslt[1] & EN_SR1)) 38927c478bd9Sstevel@tonic-gate csb->csb_rslt[0] &= ~IC_SR0; 38937c478bd9Sstevel@tonic-gate 38947c478bd9Sstevel@tonic-gate /* 38957c478bd9Sstevel@tonic-gate * See if there was an error detected, if so, fdrecover() 38967c478bd9Sstevel@tonic-gate * will check it out and say what to do. 38977c478bd9Sstevel@tonic-gate * 38987c478bd9Sstevel@tonic-gate * Don't do this, though, if this was the Sense Drive Status 38997c478bd9Sstevel@tonic-gate * or the Dump Registers command. 39007c478bd9Sstevel@tonic-gate */ 39017c478bd9Sstevel@tonic-gate if (((csb->csb_rslt[0] & IC_SR0) || (fdc->c_csb.csb_dcsr_rslt) || 39027c478bd9Sstevel@tonic-gate (csb->csb_status)) && 39037c478bd9Sstevel@tonic-gate ((csb->csb_cmds[0] != FDRAW_SENSE_DRV) && 39047c478bd9Sstevel@tonic-gate (csb->csb_cmds[0] != DUMPREG))) { 39057c478bd9Sstevel@tonic-gate /* if it can restarted OK, then do so, else return error */ 39067c478bd9Sstevel@tonic-gate if (fdrecover(fdc) != 0) { 39077c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_82077) { 39087c478bd9Sstevel@tonic-gate if (fdc->c_mtimeid == 0) { 39097c478bd9Sstevel@tonic-gate fdc->c_mtimeid = timeout(fdmotoff, 39107c478bd9Sstevel@tonic-gate a, Motoff_delay); 39117c478bd9Sstevel@tonic-gate } 39127c478bd9Sstevel@tonic-gate } 39137c478bd9Sstevel@tonic-gate 39147c478bd9Sstevel@tonic-gate /* 39157c478bd9Sstevel@tonic-gate * If this was a dma transfer, unbind the handle so 39167c478bd9Sstevel@tonic-gate * that other transfers may use it. 39177c478bd9Sstevel@tonic-gate */ 39187c478bd9Sstevel@tonic-gate 39197c478bd9Sstevel@tonic-gate (void) fd_unbind_handle(fdc); 39207c478bd9Sstevel@tonic-gate return (EIO); 39217c478bd9Sstevel@tonic-gate } else { 39227c478bd9Sstevel@tonic-gate /* ASSUMES that cmd is still intact in csb */ 39237c478bd9Sstevel@tonic-gate goto retry; 39247c478bd9Sstevel@tonic-gate } 39257c478bd9Sstevel@tonic-gate } 39267c478bd9Sstevel@tonic-gate 39277c478bd9Sstevel@tonic-gate /* things went ok */ 39287c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_82077) { 39297c478bd9Sstevel@tonic-gate if (fdc->c_mtimeid == 0) { 39307c478bd9Sstevel@tonic-gate fdc->c_mtimeid = timeout(fdmotoff, a, Motoff_delay); 39317c478bd9Sstevel@tonic-gate } 39327c478bd9Sstevel@tonic-gate } 39337c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..........\n")); 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate if (fd_unbind_handle(fdc)) 39367c478bd9Sstevel@tonic-gate return (EIO); 39377c478bd9Sstevel@tonic-gate 39387c478bd9Sstevel@tonic-gate return (0); 39397c478bd9Sstevel@tonic-gate } 39407c478bd9Sstevel@tonic-gate 39417c478bd9Sstevel@tonic-gate /* 39427c478bd9Sstevel@tonic-gate * Turn on the drive's motor 39437c478bd9Sstevel@tonic-gate * 39447c478bd9Sstevel@tonic-gate * - called with the low level lock held 39457c478bd9Sstevel@tonic-gate */ 39467c478bd9Sstevel@tonic-gate static void 39477c478bd9Sstevel@tonic-gate fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit) 39487c478bd9Sstevel@tonic-gate { 39497c478bd9Sstevel@tonic-gate clock_t local_lbolt; 39507c478bd9Sstevel@tonic-gate timeout_id_t timeid; 39517c478bd9Sstevel@tonic-gate 39527c478bd9Sstevel@tonic-gate /* 39537c478bd9Sstevel@tonic-gate * The low level mutex may not be held over the call to 39547c478bd9Sstevel@tonic-gate * untimeout(). See the manpage for details. 39557c478bd9Sstevel@tonic-gate */ 39567c478bd9Sstevel@tonic-gate timeid = fdc->c_mtimeid; 39577c478bd9Sstevel@tonic-gate fdc->c_mtimeid = 0; 39587c478bd9Sstevel@tonic-gate if (timeid) { 39597c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 39607c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 39617c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 39627c478bd9Sstevel@tonic-gate } 39637c478bd9Sstevel@tonic-gate 39647c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 39657c478bd9Sstevel@tonic-gate 39667c478bd9Sstevel@tonic-gate 39677c478bd9Sstevel@tonic-gate set_rotational_speed(fdc, unit); 39687c478bd9Sstevel@tonic-gate 39697c478bd9Sstevel@tonic-gate if (!(Dor(fdc) & (MOTEN(unit)))) { 39707c478bd9Sstevel@tonic-gate /* 39717c478bd9Sstevel@tonic-gate * Turn on the motor 39727c478bd9Sstevel@tonic-gate */ 39737c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, 39747c478bd9Sstevel@tonic-gate (C, "fdexec: turning on motor\n")); 39757c478bd9Sstevel@tonic-gate 39767c478bd9Sstevel@tonic-gate /* LINTED */ 39777c478bd9Sstevel@tonic-gate Set_dor(fdc, (MOTEN(unit)), 1); 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate if (flags & FDXC_SLEEP) { 39807c478bd9Sstevel@tonic-gate local_lbolt = ddi_get_lbolt(); 39817c478bd9Sstevel@tonic-gate (void) cv_timedwait(&fdc->c_motoncv, 39827c478bd9Sstevel@tonic-gate &fdc->c_lolock, local_lbolt + Moton_delay); 39837c478bd9Sstevel@tonic-gate } else { 39847c478bd9Sstevel@tonic-gate drv_usecwait(1000000); 39857c478bd9Sstevel@tonic-gate } 39867c478bd9Sstevel@tonic-gate } 39877c478bd9Sstevel@tonic-gate 39887c478bd9Sstevel@tonic-gate } 39897c478bd9Sstevel@tonic-gate 39907c478bd9Sstevel@tonic-gate /* 39917c478bd9Sstevel@tonic-gate * fdrecover 39927c478bd9Sstevel@tonic-gate * see if possible to retry an operation. 39937c478bd9Sstevel@tonic-gate * All we can do is restart the operation. If we are out of allowed 39947c478bd9Sstevel@tonic-gate * retries - return non-zero so that the higher levels will be notified. 39957c478bd9Sstevel@tonic-gate * 39967c478bd9Sstevel@tonic-gate * RETURNS: 0 if ok to restart, !0 if can't or out of retries 39977c478bd9Sstevel@tonic-gate * - called with the low level lock held 39987c478bd9Sstevel@tonic-gate */ 39997c478bd9Sstevel@tonic-gate static int 40007c478bd9Sstevel@tonic-gate fdrecover(struct fdctlr *fdc) 40017c478bd9Sstevel@tonic-gate { 40027c478bd9Sstevel@tonic-gate struct fdcsb *csb; 40037c478bd9Sstevel@tonic-gate 40047c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdrecover\n")); 40057c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 40067c478bd9Sstevel@tonic-gate 40077c478bd9Sstevel@tonic-gate if (fdc->c_flags & FDCFLG_TIMEDOUT) { 40087c478bd9Sstevel@tonic-gate struct fdcsb savecsb; 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate fdc->c_flags ^= FDCFLG_TIMEDOUT; 40117c478bd9Sstevel@tonic-gate csb->csb_rslt[1] |= TO_SR1; 40127c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RECO, 40137c478bd9Sstevel@tonic-gate (C, "fd%d: %s timed out\n", csb->csb_unit, 40147c478bd9Sstevel@tonic-gate fdcmds[csb->csb_cmds[0] & 0x1f].cmdname)); 40157c478bd9Sstevel@tonic-gate 40167c478bd9Sstevel@tonic-gate /* use private csb */ 40177c478bd9Sstevel@tonic-gate savecsb = fdc->c_csb; 40187c478bd9Sstevel@tonic-gate bzero(&fdc->c_csb, sizeof (struct fdcsb)); 40197c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdc: resetting\n")); 40207c478bd9Sstevel@tonic-gate 40217c478bd9Sstevel@tonic-gate (void) fdreset(fdc); 40227c478bd9Sstevel@tonic-gate 40237c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 40247c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 40257c478bd9Sstevel@tonic-gate /* Reset the DMA engine as well */ 40267c478bd9Sstevel@tonic-gate reset_dma_controller(fdc); 40277c478bd9Sstevel@tonic-gate set_dma_control_register(fdc, DCSR_INIT_BITS); 40287c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 40297c478bd9Sstevel@tonic-gate } 40307c478bd9Sstevel@tonic-gate 40317c478bd9Sstevel@tonic-gate 40327c478bd9Sstevel@tonic-gate /* check change first?? */ 40337c478bd9Sstevel@tonic-gate /* don't ckchg in fdexec, too convoluted */ 40347c478bd9Sstevel@tonic-gate (void) fdrecalseek(fdc, savecsb.csb_unit, -1, 0); 40357c478bd9Sstevel@tonic-gate fdc->c_csb = savecsb; /* restore original csb */ 40367c478bd9Sstevel@tonic-gate } 40377c478bd9Sstevel@tonic-gate 40387c478bd9Sstevel@tonic-gate /* 40397c478bd9Sstevel@tonic-gate * gather statistics on errors 40407c478bd9Sstevel@tonic-gate */ 40417c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & DE_SR1) { 40427c478bd9Sstevel@tonic-gate fdc->fdstats.de++; 40437c478bd9Sstevel@tonic-gate } 40447c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & OR_SR1) { 40457c478bd9Sstevel@tonic-gate fdc->fdstats.run++; 40467c478bd9Sstevel@tonic-gate } 40477c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) { 40487c478bd9Sstevel@tonic-gate fdc->fdstats.bfmt++; 40497c478bd9Sstevel@tonic-gate } 40507c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & TO_SR1) { 40517c478bd9Sstevel@tonic-gate fdc->fdstats.to++; 40527c478bd9Sstevel@tonic-gate } 40537c478bd9Sstevel@tonic-gate 40547c478bd9Sstevel@tonic-gate /* 40557c478bd9Sstevel@tonic-gate * If raw ioctl don't examine results just pass status 40567c478bd9Sstevel@tonic-gate * back via fdraw. Raw commands are timed too, so put this 40577c478bd9Sstevel@tonic-gate * after the above check. 40587c478bd9Sstevel@tonic-gate */ 40597c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFRAWIOCTL) { 40607c478bd9Sstevel@tonic-gate return (1); 40617c478bd9Sstevel@tonic-gate } 40627c478bd9Sstevel@tonic-gate 40637c478bd9Sstevel@tonic-gate 40647c478bd9Sstevel@tonic-gate /* 40657c478bd9Sstevel@tonic-gate * if there was a pci bus error, do not retry 40667c478bd9Sstevel@tonic-gate */ 40677c478bd9Sstevel@tonic-gate 40687c478bd9Sstevel@tonic-gate if (csb->csb_dcsr_rslt == 1) { 40697c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_RECO, 40707c478bd9Sstevel@tonic-gate (C, "fd%d: host bus error\n", 0)); 40717c478bd9Sstevel@tonic-gate return (1); 40727c478bd9Sstevel@tonic-gate } 40737c478bd9Sstevel@tonic-gate 40747c478bd9Sstevel@tonic-gate /* 40757c478bd9Sstevel@tonic-gate * If there was an error with the DMA functions, do not retry 40767c478bd9Sstevel@tonic-gate */ 40777c478bd9Sstevel@tonic-gate if (csb->csb_dma_rslt == 1) { 40787c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RECO, 40797c478bd9Sstevel@tonic-gate (C, "fd%d: DMA interface error\n", csb->csb_unit)); 40807c478bd9Sstevel@tonic-gate return (1); 40817c478bd9Sstevel@tonic-gate } 40827c478bd9Sstevel@tonic-gate 40837c478bd9Sstevel@tonic-gate 40847c478bd9Sstevel@tonic-gate /* 40857c478bd9Sstevel@tonic-gate * if we have run out of retries, return an error 40867c478bd9Sstevel@tonic-gate * XXX need better status interp 40877c478bd9Sstevel@tonic-gate */ 40887c478bd9Sstevel@tonic-gate 40897c478bd9Sstevel@tonic-gate csb->csb_retrys++; 40907c478bd9Sstevel@tonic-gate if (csb->csb_retrys > csb->csb_maxretry) { 40917c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_RECO, 40927c478bd9Sstevel@tonic-gate (C, "fd%d: %s failed (%x %x %x)\n", 40937c478bd9Sstevel@tonic-gate 0, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname, 40947c478bd9Sstevel@tonic-gate csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2])); 40957c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & NW_SR1) { 40967c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_RECO, 40977c478bd9Sstevel@tonic-gate (C, "fd%d: not writable\n", 0)); 40987c478bd9Sstevel@tonic-gate } 40997c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & DE_SR1) { 41007c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_RECO, 41017c478bd9Sstevel@tonic-gate (C, "fd%d: crc error blk %d\n", 0, 41027c478bd9Sstevel@tonic-gate (int)fdc->c_current->b_blkno)); 41037c478bd9Sstevel@tonic-gate } 41047c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & OR_SR1) { 41057c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 41067c478bd9Sstevel@tonic-gate /* 41077c478bd9Sstevel@tonic-gate * When using southbridge chip we need to 41087c478bd9Sstevel@tonic-gate * retry atleast 10 times to shake off the 41097c478bd9Sstevel@tonic-gate * underrun err. 41107c478bd9Sstevel@tonic-gate */ 41117c478bd9Sstevel@tonic-gate if (csb->csb_retrys <= rwretry) 41127c478bd9Sstevel@tonic-gate return (0); 41137c478bd9Sstevel@tonic-gate } 41147c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_RECO, 41157c478bd9Sstevel@tonic-gate (C, "fd%d: over/underrun\n", 0)); 41167c478bd9Sstevel@tonic-gate } 41177c478bd9Sstevel@tonic-gate 41187c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) { 41197c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_RECO, 41207c478bd9Sstevel@tonic-gate (C, "fd%d: bad format\n", 0)); 41217c478bd9Sstevel@tonic-gate } 41227c478bd9Sstevel@tonic-gate 41237c478bd9Sstevel@tonic-gate if (csb->csb_rslt[1] & TO_SR1) { 41247c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_RECO, 41257c478bd9Sstevel@tonic-gate (C, "fd%d: timeout\n", 0)); 41267c478bd9Sstevel@tonic-gate } 41277c478bd9Sstevel@tonic-gate 41287c478bd9Sstevel@tonic-gate csb->csb_cmdstat = 1; /* failed - give up */ 41297c478bd9Sstevel@tonic-gate return (1); 41307c478bd9Sstevel@tonic-gate } 41317c478bd9Sstevel@tonic-gate 41327c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFSEEKOPS) { 41337c478bd9Sstevel@tonic-gate /* seek, recal type commands - just look at st0 */ 41347c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_RECO, 41357c478bd9Sstevel@tonic-gate (C, "fd%d: %s error : st0 0x%x\n", csb->csb_unit, 41367c478bd9Sstevel@tonic-gate fdcmds[csb->csb_cmds[0] & 0x1f].cmdname, 41377c478bd9Sstevel@tonic-gate csb->csb_rslt[0])); 41387c478bd9Sstevel@tonic-gate } 41397c478bd9Sstevel@tonic-gate if (csb->csb_opflags & CSB_OFXFEROPS) { 41407c478bd9Sstevel@tonic-gate /* rd, wr, fmt type commands - look at st0, st1, st2 */ 41417c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_RECO, 41427c478bd9Sstevel@tonic-gate (C, "fd%d: %s error : st0=0x%x st1=0x%x st2=0x%x\n", 41437c478bd9Sstevel@tonic-gate csb->csb_unit, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname, 41447c478bd9Sstevel@tonic-gate csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2])); 41457c478bd9Sstevel@tonic-gate } 41467c478bd9Sstevel@tonic-gate 41477c478bd9Sstevel@tonic-gate return (0); /* tell fdexec to retry */ 41487c478bd9Sstevel@tonic-gate } 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate /* 41517c478bd9Sstevel@tonic-gate * Interrupt handle for DMA 41527c478bd9Sstevel@tonic-gate */ 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate static uint_t 41557c478bd9Sstevel@tonic-gate fdintr_dma() 41567c478bd9Sstevel@tonic-gate { 41577c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 41587c478bd9Sstevel@tonic-gate off_t off; 41597c478bd9Sstevel@tonic-gate size_t len; 41607c478bd9Sstevel@tonic-gate uint_t ccount; 41617c478bd9Sstevel@tonic-gate uint_t windex; 41627c478bd9Sstevel@tonic-gate uint_t done = 0; 41637c478bd9Sstevel@tonic-gate int tmp_dcsr; 41647c478bd9Sstevel@tonic-gate int to; 41657c478bd9Sstevel@tonic-gate uchar_t tmp; 41667c478bd9Sstevel@tonic-gate int i = 0; 41677c478bd9Sstevel@tonic-gate int res = DDI_INTR_UNCLAIMED; 41687c478bd9Sstevel@tonic-gate int not_cheerio = 1; 41697c478bd9Sstevel@tonic-gate 41707c478bd9Sstevel@tonic-gate /* search for a controller that's expecting an interrupt */ 41717c478bd9Sstevel@tonic-gate fdc = fdctlrs; 41727c478bd9Sstevel@tonic-gate 41737c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 41747c478bd9Sstevel@tonic-gate tmp_dcsr = get_dma_control_register(fdc); 41757c478bd9Sstevel@tonic-gate if (!(tmp_dcsr & DCSR_INT_PEND) && !(DCSR_ERR_PEND & tmp_dcsr)) 41767c478bd9Sstevel@tonic-gate return (res); 41777c478bd9Sstevel@tonic-gate not_cheerio = 0; 41787c478bd9Sstevel@tonic-gate } 41797c478bd9Sstevel@tonic-gate 41807c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 41817c478bd9Sstevel@tonic-gate 41827c478bd9Sstevel@tonic-gate if (fdc->c_csb.csb_opmode == 0x0) { 41837c478bd9Sstevel@tonic-gate fdc->c_csb.csb_opmode = 2; 41847c478bd9Sstevel@tonic-gate } 41857c478bd9Sstevel@tonic-gate if (fdc->sb_dma_lock) { 41867c478bd9Sstevel@tonic-gate release_sb_dma(fdc); 41877c478bd9Sstevel@tonic-gate } 41887c478bd9Sstevel@tonic-gate 41897c478bd9Sstevel@tonic-gate /* 41907c478bd9Sstevel@tonic-gate * An interrupt can come from either the floppy controller or 41917c478bd9Sstevel@tonic-gate * or the DMA engine. The DMA engine will only issue an 41927c478bd9Sstevel@tonic-gate * interrupt if there was an error. 41937c478bd9Sstevel@tonic-gate */ 41947c478bd9Sstevel@tonic-gate 41957c478bd9Sstevel@tonic-gate switch (fdc->c_csb.csb_opmode) { 41967c478bd9Sstevel@tonic-gate case 0x1: 41977c478bd9Sstevel@tonic-gate /* read/write/format data-xfer case */ 41987c478bd9Sstevel@tonic-gate 41997c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 42007c478bd9Sstevel@tonic-gate (C, "fdintr_dma: opmode 1\n")); 42017c478bd9Sstevel@tonic-gate 42027c478bd9Sstevel@tonic-gate /* 42037c478bd9Sstevel@tonic-gate * See if the interrupt is from the floppy 42047c478bd9Sstevel@tonic-gate * controller. If there is, take out the status bytes. 42057c478bd9Sstevel@tonic-gate */ 42067c478bd9Sstevel@tonic-gate 42077c478bd9Sstevel@tonic-gate if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) { 42087c478bd9Sstevel@tonic-gate 42097c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 42107c478bd9Sstevel@tonic-gate (C, "fdintr_dma: INT_PEND \n")); 42117c478bd9Sstevel@tonic-gate 42127c478bd9Sstevel@tonic-gate res = DDI_INTR_CLAIMED; 42137c478bd9Sstevel@tonic-gate 42147c478bd9Sstevel@tonic-gate to = FD_RRETRY; 42157c478bd9Sstevel@tonic-gate fdc->c_csb.csb_nrslts = 0; 42167c478bd9Sstevel@tonic-gate 42177c478bd9Sstevel@tonic-gate /* check status */ 42187c478bd9Sstevel@tonic-gate i = 0; 42197c478bd9Sstevel@tonic-gate 42207c478bd9Sstevel@tonic-gate /* 42217c478bd9Sstevel@tonic-gate * CB turns off once all the result bytes are 42227c478bd9Sstevel@tonic-gate * read. 42237c478bd9Sstevel@tonic-gate * 42247c478bd9Sstevel@tonic-gate * NOTE: the counters are there so that the 42257c478bd9Sstevel@tonic-gate * handler will never get stuck in a loop. 42267c478bd9Sstevel@tonic-gate * If the counters do reach their maximum 42277c478bd9Sstevel@tonic-gate * values, then a catastrophic error has 42287c478bd9Sstevel@tonic-gate * occurred. This should never be the case. 42297c478bd9Sstevel@tonic-gate * The counters only came into play during 42307c478bd9Sstevel@tonic-gate * development. 42317c478bd9Sstevel@tonic-gate */ 42327c478bd9Sstevel@tonic-gate while (((tmp = Msr(fdc)) & CB) && 42337c478bd9Sstevel@tonic-gate (i < 1000001)) { 42347c478bd9Sstevel@tonic-gate 42357c478bd9Sstevel@tonic-gate /* 42367c478bd9Sstevel@tonic-gate * If RQM + DIO, then a result byte 42377c478bd9Sstevel@tonic-gate * is at hand. 42387c478bd9Sstevel@tonic-gate */ 42397c478bd9Sstevel@tonic-gate if ((tmp & (RQM|DIO|CB)) == 42407c478bd9Sstevel@tonic-gate (RQM|DIO|CB)) { 42417c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt 42427c478bd9Sstevel@tonic-gate [fdc->c_csb.csb_nrslts++] 42437c478bd9Sstevel@tonic-gate = Fifo(fdc); 42447c478bd9Sstevel@tonic-gate 42457c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 424619397407SSherry Moore (C, 424719397407SSherry Moore "fdintr_dma: res 0x%x\n", 42487c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt 42497c478bd9Sstevel@tonic-gate [fdc->c_csb.csb_nrslts 42507c478bd9Sstevel@tonic-gate - 1])); 42517c478bd9Sstevel@tonic-gate 42527c478bd9Sstevel@tonic-gate } else if (--to == 0) { 42537c478bd9Sstevel@tonic-gate /* 42547c478bd9Sstevel@tonic-gate * controller was never 42557c478bd9Sstevel@tonic-gate * ready to give results 42567c478bd9Sstevel@tonic-gate */ 42577c478bd9Sstevel@tonic-gate fdc->c_csb.csb_status = 2; 42587c478bd9Sstevel@tonic-gate break; 42597c478bd9Sstevel@tonic-gate } 42607c478bd9Sstevel@tonic-gate i++; 42617c478bd9Sstevel@tonic-gate } 42627c478bd9Sstevel@tonic-gate if (i == 10000) { 42637c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 42647c478bd9Sstevel@tonic-gate (C, "First loop overran\n")); 42657c478bd9Sstevel@tonic-gate } 42667c478bd9Sstevel@tonic-gate } 42677c478bd9Sstevel@tonic-gate 42687c478bd9Sstevel@tonic-gate /* 42697c478bd9Sstevel@tonic-gate * See if the interrupt is from the DMA engine, 42707c478bd9Sstevel@tonic-gate * which will only interrupt on an error 42717c478bd9Sstevel@tonic-gate */ 42727c478bd9Sstevel@tonic-gate if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) { 42737c478bd9Sstevel@tonic-gate 42747c478bd9Sstevel@tonic-gate res = DDI_INTR_CLAIMED; 42757c478bd9Sstevel@tonic-gate 42767c478bd9Sstevel@tonic-gate done = 1; 42777c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dcsr_rslt = 1; 42787c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 42797c478bd9Sstevel@tonic-gate (C, "fdintr_dma: Error pending\n")); 42807c478bd9Sstevel@tonic-gate reset_dma_controller(fdc); 42817c478bd9Sstevel@tonic-gate set_dma_control_register(fdc, DCSR_INIT_BITS); 42827c478bd9Sstevel@tonic-gate break; 42837c478bd9Sstevel@tonic-gate } 42847c478bd9Sstevel@tonic-gate 42857c478bd9Sstevel@tonic-gate /* TCBUG kludge */ 42867c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_TCBUG) && 42877c478bd9Sstevel@tonic-gate ((fdc->c_csb.csb_rslt[0] & IC_SR0) == 0x40) && 42887c478bd9Sstevel@tonic-gate (fdc->c_csb.csb_rslt[1] & EN_SR1)) { 42897c478bd9Sstevel@tonic-gate 42907c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt[0] &= ~IC_SR0; 42917c478bd9Sstevel@tonic-gate 42927c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt[1] &= ~EN_SR1; 42937c478bd9Sstevel@tonic-gate 42947c478bd9Sstevel@tonic-gate 42957c478bd9Sstevel@tonic-gate } 42967c478bd9Sstevel@tonic-gate 42977c478bd9Sstevel@tonic-gate 42987c478bd9Sstevel@tonic-gate /* Exit if there were errors in the DMA */ 42997c478bd9Sstevel@tonic-gate if (((fdc->c_csb.csb_rslt[0] & IC_SR0) != 0) || 43007c478bd9Sstevel@tonic-gate (fdc->c_csb.csb_rslt[1] != 0) || 43017c478bd9Sstevel@tonic-gate (fdc->c_csb.csb_rslt[2] != 0)) { 43027c478bd9Sstevel@tonic-gate done = 1; 43037c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43047c478bd9Sstevel@tonic-gate (C, "fdintr_dma: errors in command\n")); 43057c478bd9Sstevel@tonic-gate 43067c478bd9Sstevel@tonic-gate 43077c478bd9Sstevel@tonic-gate break; 43087c478bd9Sstevel@tonic-gate } 43097c478bd9Sstevel@tonic-gate 43107c478bd9Sstevel@tonic-gate 43117c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43127c478bd9Sstevel@tonic-gate (C, "fdintr_dma: dbcr 0x%x\n", 43137c478bd9Sstevel@tonic-gate get_data_count_register(fdc))); 43147c478bd9Sstevel@tonic-gate /* 43157c478bd9Sstevel@tonic-gate * The csb_ccount is the number of cookies that still 43167c478bd9Sstevel@tonic-gate * need to be processed. A cookie was just processed 43177c478bd9Sstevel@tonic-gate * so decrement the cookie counter. 43187c478bd9Sstevel@tonic-gate */ 43197c478bd9Sstevel@tonic-gate if (fdc->c_csb.csb_ccount == 0) { 43207c478bd9Sstevel@tonic-gate done = 1; 43217c478bd9Sstevel@tonic-gate break; 43227c478bd9Sstevel@tonic-gate } 43237c478bd9Sstevel@tonic-gate fdc->c_csb.csb_ccount--; 43247c478bd9Sstevel@tonic-gate ccount = fdc->c_csb.csb_ccount; 43257c478bd9Sstevel@tonic-gate 43267c478bd9Sstevel@tonic-gate windex = fdc->c_csb.csb_windex; 43277c478bd9Sstevel@tonic-gate 43287c478bd9Sstevel@tonic-gate /* 43297c478bd9Sstevel@tonic-gate * If there are no more cookies and all the windows 43307c478bd9Sstevel@tonic-gate * have been DMA'd, then DMA is done. 43317c478bd9Sstevel@tonic-gate * 43327c478bd9Sstevel@tonic-gate */ 43337c478bd9Sstevel@tonic-gate if ((ccount == 0) && (windex == fdc->c_csb.csb_nwin)) { 43347c478bd9Sstevel@tonic-gate 43357c478bd9Sstevel@tonic-gate done = 1; 43367c478bd9Sstevel@tonic-gate 43377c478bd9Sstevel@tonic-gate /* 43387c478bd9Sstevel@tonic-gate * The handle is unbound in fdexec 43397c478bd9Sstevel@tonic-gate */ 43407c478bd9Sstevel@tonic-gate 43417c478bd9Sstevel@tonic-gate break; 43427c478bd9Sstevel@tonic-gate } 43437c478bd9Sstevel@tonic-gate 43447c478bd9Sstevel@tonic-gate if (ccount != 0) { 43457c478bd9Sstevel@tonic-gate /* process the next cookie */ 43467c478bd9Sstevel@tonic-gate ddi_dma_nextcookie(fdc->c_dmahandle, 43477c478bd9Sstevel@tonic-gate &fdc->c_csb.csb_dmacookie); 43487c478bd9Sstevel@tonic-gate 43497c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43507c478bd9Sstevel@tonic-gate (C, "cookie addr 0x%" PRIx64 "\n", 43517c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_laddress)); 43527c478bd9Sstevel@tonic-gate 43537c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43547c478bd9Sstevel@tonic-gate (C, "cookie length %lu\n", 43557c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_size)); 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate } else { 43587c478bd9Sstevel@tonic-gate 43597c478bd9Sstevel@tonic-gate (void) ddi_dma_getwin(fdc->c_dmahandle, 43607c478bd9Sstevel@tonic-gate fdc->c_csb.csb_windex, 43617c478bd9Sstevel@tonic-gate &off, &len, 43627c478bd9Sstevel@tonic-gate &fdc->c_csb.csb_dmacookie, 43637c478bd9Sstevel@tonic-gate &fdc->c_csb.csb_ccount); 43647c478bd9Sstevel@tonic-gate fdc->c_csb.csb_windex++; 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43677c478bd9Sstevel@tonic-gate (C, "fdintr_dma: process %d window\n", 43687c478bd9Sstevel@tonic-gate fdc->c_csb.csb_windex)); 43697c478bd9Sstevel@tonic-gate 43707c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43717c478bd9Sstevel@tonic-gate (C, "fdintr_dma: process no. cookies %d\n", 43727c478bd9Sstevel@tonic-gate fdc->c_csb.csb_ccount)); 43737c478bd9Sstevel@tonic-gate 43747c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43757c478bd9Sstevel@tonic-gate (C, "cookie addr 0x%" PRIx64 "\n", 43767c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_laddress)); 43777c478bd9Sstevel@tonic-gate 43787c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 43797c478bd9Sstevel@tonic-gate (C, "cookie length %lu\n", 43807c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_size)); 43817c478bd9Sstevel@tonic-gate } 43827c478bd9Sstevel@tonic-gate 43837c478bd9Sstevel@tonic-gate /* 43847c478bd9Sstevel@tonic-gate * Program the DMA engine with the length and 43857c478bd9Sstevel@tonic-gate * the address of the transfer 43867c478bd9Sstevel@tonic-gate */ 43877c478bd9Sstevel@tonic-gate 43887c478bd9Sstevel@tonic-gate ASSERT(fdc->c_csb.csb_dmacookie.dmac_size); 43897c478bd9Sstevel@tonic-gate 43907c478bd9Sstevel@tonic-gate set_data_count_register(fdc, 43917c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_size); 43927c478bd9Sstevel@tonic-gate set_data_address_register(fdc, 43937c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_laddress); 43947c478bd9Sstevel@tonic-gate 43957c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, (C, 43967c478bd9Sstevel@tonic-gate "fdintr_dma: size 0x%lx\n", 43977c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dmacookie.dmac_size)); 43987c478bd9Sstevel@tonic-gate 43997c478bd9Sstevel@tonic-gate 44007c478bd9Sstevel@tonic-gate /* reprogram the controller */ 44017c478bd9Sstevel@tonic-gate fdc->c_csb.csb_cmds[2] = fdc->c_csb.csb_rslt[3]; 44027c478bd9Sstevel@tonic-gate fdc->c_csb.csb_cmds[3] = fdc->c_csb.csb_rslt[4]; 44037c478bd9Sstevel@tonic-gate fdc->c_csb.csb_cmds[4] = fdc->c_csb.csb_rslt[5]; 44047c478bd9Sstevel@tonic-gate fdc->c_csb.csb_cmds[1] = (fdc->c_csb.csb_cmds[1] 44057c478bd9Sstevel@tonic-gate & ~0x04) | (fdc->c_csb.csb_rslt[4] << 2); 44067c478bd9Sstevel@tonic-gate 44077c478bd9Sstevel@tonic-gate for (i = 0; i < (int)fdc->c_csb.csb_ncmds; i++) { 44087c478bd9Sstevel@tonic-gate 44097c478bd9Sstevel@tonic-gate /* 44107c478bd9Sstevel@tonic-gate * Test the readiness of the controller 44117c478bd9Sstevel@tonic-gate * to receive the cmd 44127c478bd9Sstevel@tonic-gate */ 44137c478bd9Sstevel@tonic-gate for (to = FD_CRETRY; to; to--) { 44147c478bd9Sstevel@tonic-gate if ((Msr(fdc) & (DIO|RQM)) == RQM) 44157c478bd9Sstevel@tonic-gate break; 44167c478bd9Sstevel@tonic-gate } 44177c478bd9Sstevel@tonic-gate if (to == 0) { 44187c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_EXEC, 44197c478bd9Sstevel@tonic-gate (C, 442019397407SSherry Moore "fdc: no RQM - stat 0x%x\n", 442119397407SSherry Moore Msr(fdc))); 44227c478bd9Sstevel@tonic-gate /* stop the DMA from happening */ 44237c478bd9Sstevel@tonic-gate fdc->c_csb.csb_status = 2; 44247c478bd9Sstevel@tonic-gate done = 1; 44257c478bd9Sstevel@tonic-gate break; 44267c478bd9Sstevel@tonic-gate } 44277c478bd9Sstevel@tonic-gate 44287c478bd9Sstevel@tonic-gate Set_Fifo(fdc, fdc->c_csb.csb_cmds[i]); 44297c478bd9Sstevel@tonic-gate 44307c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 44317c478bd9Sstevel@tonic-gate (C, 44327c478bd9Sstevel@tonic-gate "fdintr_dma: sent 0x%x, Msr 0x%x\n", 44337c478bd9Sstevel@tonic-gate fdc->c_csb.csb_cmds[i], Msr(fdc))); 44347c478bd9Sstevel@tonic-gate } 44357c478bd9Sstevel@tonic-gate 44367c478bd9Sstevel@tonic-gate /* reenable DMA */ 44377c478bd9Sstevel@tonic-gate if ((!not_cheerio) && (!done)) 44387c478bd9Sstevel@tonic-gate set_dma_control_register(fdc, tmp_dcsr | 44397c478bd9Sstevel@tonic-gate DCSR_EN_DMA); 44407c478bd9Sstevel@tonic-gate break; 44417c478bd9Sstevel@tonic-gate 44427c478bd9Sstevel@tonic-gate case 0x2: 44437c478bd9Sstevel@tonic-gate /* seek/recal type cmd */ 44447c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 44457c478bd9Sstevel@tonic-gate (C, "fintr_dma: opmode 2\n")); 44467c478bd9Sstevel@tonic-gate 44477c478bd9Sstevel@tonic-gate /* 44487c478bd9Sstevel@tonic-gate * See if the interrupt is from the DMA engine, 44497c478bd9Sstevel@tonic-gate * which will only interrupt if there was an error. 44507c478bd9Sstevel@tonic-gate */ 44517c478bd9Sstevel@tonic-gate if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) { 44527c478bd9Sstevel@tonic-gate res = DDI_INTR_CLAIMED; 44537c478bd9Sstevel@tonic-gate done = 1; 44547c478bd9Sstevel@tonic-gate fdc->c_csb.csb_dcsr_rslt = 1; 44557c478bd9Sstevel@tonic-gate reset_dma_controller(fdc); 44567c478bd9Sstevel@tonic-gate set_dma_control_register(fdc, DCSR_INIT_BITS); 44577c478bd9Sstevel@tonic-gate 44587c478bd9Sstevel@tonic-gate break; 44597c478bd9Sstevel@tonic-gate } 44607c478bd9Sstevel@tonic-gate 44617c478bd9Sstevel@tonic-gate 44627c478bd9Sstevel@tonic-gate /* See if the interrupt is from the floppy controller */ 44637c478bd9Sstevel@tonic-gate if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) { 44647c478bd9Sstevel@tonic-gate 44657c478bd9Sstevel@tonic-gate res = DDI_INTR_CLAIMED; 44667c478bd9Sstevel@tonic-gate 44677c478bd9Sstevel@tonic-gate 44687c478bd9Sstevel@tonic-gate /* 44697c478bd9Sstevel@tonic-gate * Wait until there's no longer a command 44707c478bd9Sstevel@tonic-gate * in progress 44717c478bd9Sstevel@tonic-gate */ 44727c478bd9Sstevel@tonic-gate 44737c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 44747c478bd9Sstevel@tonic-gate (C, "fdintr_dma: interrupt pending\n")); 44757c478bd9Sstevel@tonic-gate i = 0; 44767c478bd9Sstevel@tonic-gate while (((Msr(fdc) & CB)) && (i < 10000)) { 44777c478bd9Sstevel@tonic-gate i++; 44787c478bd9Sstevel@tonic-gate } 44797c478bd9Sstevel@tonic-gate 44807c478bd9Sstevel@tonic-gate if (i == 10000) 44817c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 44827c478bd9Sstevel@tonic-gate (C, "2nd loop overran !!!\n")); 44837c478bd9Sstevel@tonic-gate 44847c478bd9Sstevel@tonic-gate /* 44857c478bd9Sstevel@tonic-gate * Check the RQM bit to see if the controller is 44867c478bd9Sstevel@tonic-gate * ready to transfer status of the command. 44877c478bd9Sstevel@tonic-gate */ 44887c478bd9Sstevel@tonic-gate i = 0; 44897c478bd9Sstevel@tonic-gate while ((!(Msr(fdc) & RQM)) && (i < 10000)) { 44907c478bd9Sstevel@tonic-gate i++; 44917c478bd9Sstevel@tonic-gate } 44927c478bd9Sstevel@tonic-gate 44937c478bd9Sstevel@tonic-gate if (i == 10000) 44947c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 44957c478bd9Sstevel@tonic-gate (C, "3rd loop overran !!!\n")); 44967c478bd9Sstevel@tonic-gate 44977c478bd9Sstevel@tonic-gate /* 44987c478bd9Sstevel@tonic-gate * Issue the Sense Interrupt Status Command 44997c478bd9Sstevel@tonic-gate */ 45007c478bd9Sstevel@tonic-gate Set_Fifo(fdc, SNSISTAT); 45017c478bd9Sstevel@tonic-gate 45027c478bd9Sstevel@tonic-gate i = 0; 45037c478bd9Sstevel@tonic-gate while ((!(Msr(fdc) & RQM)) && (i < 10000)) { 45047c478bd9Sstevel@tonic-gate i++; 45057c478bd9Sstevel@tonic-gate } 45067c478bd9Sstevel@tonic-gate if (i == 10000) 45077c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 45087c478bd9Sstevel@tonic-gate (C, "4th loop overran !!!\n")); 45097c478bd9Sstevel@tonic-gate 45107c478bd9Sstevel@tonic-gate /* Store the first result byte */ 45117c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt[0] = Fifo(fdc); 45127c478bd9Sstevel@tonic-gate 45137c478bd9Sstevel@tonic-gate i = 0; 45147c478bd9Sstevel@tonic-gate while ((!(Msr(fdc) & RQM)) && (i < 10000)) { 45157c478bd9Sstevel@tonic-gate i++; 45167c478bd9Sstevel@tonic-gate } 45177c478bd9Sstevel@tonic-gate if (i == 10000) 45187c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 45197c478bd9Sstevel@tonic-gate (C, "5th loop overran !!!\n")); 45207c478bd9Sstevel@tonic-gate 45217c478bd9Sstevel@tonic-gate /* Store the second result byte */ 45227c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt[1] = Fifo(fdc); 45237c478bd9Sstevel@tonic-gate 45247c478bd9Sstevel@tonic-gate done = 1; 45257c478bd9Sstevel@tonic-gate } 45267c478bd9Sstevel@tonic-gate 45277c478bd9Sstevel@tonic-gate } 45287c478bd9Sstevel@tonic-gate 45297c478bd9Sstevel@tonic-gate /* 45307c478bd9Sstevel@tonic-gate * We are done with the actual interrupt handling here. 45317c478bd9Sstevel@tonic-gate * The portion below should be actually be done by fd_lointr(). 45327c478bd9Sstevel@tonic-gate * We should be triggering the fd_lointr here and exiting. 45337c478bd9Sstevel@tonic-gate * However for want of time this will be done in the next FIX. 45347c478bd9Sstevel@tonic-gate * 45357c478bd9Sstevel@tonic-gate * Hence for now we will release hilock only and keep the remaining 45367c478bd9Sstevel@tonic-gate * code as it is. 45377c478bd9Sstevel@tonic-gate * Releasing of hilock ensures that we don't hold on to the 45387c478bd9Sstevel@tonic-gate * lolock and hilock at the same time. 45397c478bd9Sstevel@tonic-gate * hilock is acquired each time dma related registers are accessed. 45407c478bd9Sstevel@tonic-gate */ 45417c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 45427c478bd9Sstevel@tonic-gate /* Make signal and get out of interrupt handler */ 45437c478bd9Sstevel@tonic-gate if (done) { 45447c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 45457c478bd9Sstevel@tonic-gate 45467c478bd9Sstevel@tonic-gate fdc->c_csb.csb_opmode = 0; 45477c478bd9Sstevel@tonic-gate 45487c478bd9Sstevel@tonic-gate /* reset watchdog timer if armed and not already triggered */ 45497c478bd9Sstevel@tonic-gate 45507c478bd9Sstevel@tonic-gate 45517c478bd9Sstevel@tonic-gate if (fdc->c_timeid) { 45527c478bd9Sstevel@tonic-gate timeout_id_t timeid = fdc->c_timeid; 45537c478bd9Sstevel@tonic-gate fdc->c_timeid = 0; 45547c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 45557c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 45567c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 45577c478bd9Sstevel@tonic-gate } 45587c478bd9Sstevel@tonic-gate 45597c478bd9Sstevel@tonic-gate 45607c478bd9Sstevel@tonic-gate if (fdc->c_flags & FDCFLG_WAITING) { 45617c478bd9Sstevel@tonic-gate /* 45627c478bd9Sstevel@tonic-gate * somebody's waiting on finish of fdctlr/csb, 45637c478bd9Sstevel@tonic-gate * wake them 45647c478bd9Sstevel@tonic-gate */ 45657c478bd9Sstevel@tonic-gate 45667c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 45677c478bd9Sstevel@tonic-gate (C, "fdintr_dma: signal the waiter\n")); 45687c478bd9Sstevel@tonic-gate 45697c478bd9Sstevel@tonic-gate fdc->c_flags ^= FDCFLG_WAITING; 45707c478bd9Sstevel@tonic-gate cv_signal(&fdc->c_iocv); 45717c478bd9Sstevel@tonic-gate 45727c478bd9Sstevel@tonic-gate /* 45737c478bd9Sstevel@tonic-gate * FDCFLG_BUSY is NOT cleared, NOR is the csb given 45747c478bd9Sstevel@tonic-gate * back; the operation just finished can look at the csb 45757c478bd9Sstevel@tonic-gate */ 45767c478bd9Sstevel@tonic-gate } else { 45777c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, 45787c478bd9Sstevel@tonic-gate (C, "fdintr_dma: nobody sleeping (%x %x %x)\n", 45797c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt[0], fdc->c_csb.csb_rslt[1], 45807c478bd9Sstevel@tonic-gate fdc->c_csb.csb_rslt[2])); 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 45837c478bd9Sstevel@tonic-gate } 45847c478bd9Sstevel@tonic-gate /* update high level interrupt counter */ 45857c478bd9Sstevel@tonic-gate if (fdc->c_intrstat) 45867c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 45877c478bd9Sstevel@tonic-gate 45887c478bd9Sstevel@tonic-gate 45897c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr_dma: done\n")); 45907c478bd9Sstevel@tonic-gate return (res); 45917c478bd9Sstevel@tonic-gate } 45927c478bd9Sstevel@tonic-gate 45937c478bd9Sstevel@tonic-gate /* 45947c478bd9Sstevel@tonic-gate * fd_lointr 45957c478bd9Sstevel@tonic-gate * This is the low level SW interrupt handler triggered by the high 45967c478bd9Sstevel@tonic-gate * level interrupt handler (or by fdwatch). 45977c478bd9Sstevel@tonic-gate */ 45987c478bd9Sstevel@tonic-gate static uint_t 45997c478bd9Sstevel@tonic-gate fd_lointr(caddr_t arg) 46007c478bd9Sstevel@tonic-gate { 46017c478bd9Sstevel@tonic-gate struct fdctlr *fdc = (struct fdctlr *)arg; 46027c478bd9Sstevel@tonic-gate struct fdcsb *csb; 46037c478bd9Sstevel@tonic-gate 46047c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 46057c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr: opmode %d\n", 46067c478bd9Sstevel@tonic-gate csb->csb_opmode)); 46077c478bd9Sstevel@tonic-gate /* 46087c478bd9Sstevel@tonic-gate * Check that lowlevel interrupt really meant to trigger us. 46097c478bd9Sstevel@tonic-gate */ 46107c478bd9Sstevel@tonic-gate if (csb->csb_opmode != 4) { 46117c478bd9Sstevel@tonic-gate /* 46127c478bd9Sstevel@tonic-gate * This should probably be protected, but, what the 46137c478bd9Sstevel@tonic-gate * heck...the cost isn't worth the accuracy for this 46147c478bd9Sstevel@tonic-gate * statistic. 46157c478bd9Sstevel@tonic-gate */ 46167c478bd9Sstevel@tonic-gate if (fdc->c_intrstat) 46177c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 46187c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 46197c478bd9Sstevel@tonic-gate } 46207c478bd9Sstevel@tonic-gate 46217c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 46227c478bd9Sstevel@tonic-gate csb->csb_opmode = 0; 46237c478bd9Sstevel@tonic-gate 46247c478bd9Sstevel@tonic-gate /* reset watchdog timer if armed and not already triggered */ 46257c478bd9Sstevel@tonic-gate if (fdc->c_timeid) { 46267c478bd9Sstevel@tonic-gate timeout_id_t timeid = fdc->c_timeid; 46277c478bd9Sstevel@tonic-gate fdc->c_timeid = 0; 46287c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 46297c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 46307c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 46317c478bd9Sstevel@tonic-gate 46327c478bd9Sstevel@tonic-gate } 46337c478bd9Sstevel@tonic-gate 46347c478bd9Sstevel@tonic-gate if (fdc->c_flags & FDCFLG_WAITING) { 46357c478bd9Sstevel@tonic-gate /* 46367c478bd9Sstevel@tonic-gate * somebody's waiting on finish of fdctlr/csb, wake them 46377c478bd9Sstevel@tonic-gate */ 46387c478bd9Sstevel@tonic-gate fdc->c_flags ^= FDCFLG_WAITING; 46397c478bd9Sstevel@tonic-gate cv_signal(&fdc->c_iocv); 46407c478bd9Sstevel@tonic-gate 46417c478bd9Sstevel@tonic-gate /* 46427c478bd9Sstevel@tonic-gate * FDCFLG_BUSY is NOT cleared, NOR is the csb given back; so 46437c478bd9Sstevel@tonic-gate * the operation just finished can look at the csb 46447c478bd9Sstevel@tonic-gate */ 46457c478bd9Sstevel@tonic-gate } else { 46467c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_INTR, 46477c478bd9Sstevel@tonic-gate (C, "fdintr: nobody sleeping (%x %x %x)\n", 46487c478bd9Sstevel@tonic-gate csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2])); 46497c478bd9Sstevel@tonic-gate } 46507c478bd9Sstevel@tonic-gate if (fdc->c_intrstat) 46517c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SOFT]++; 46527c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 46537c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 46547c478bd9Sstevel@tonic-gate } 46557c478bd9Sstevel@tonic-gate 46567c478bd9Sstevel@tonic-gate /* 46577c478bd9Sstevel@tonic-gate * fdwatch 46587c478bd9Sstevel@tonic-gate * is called from timein() when a floppy operation has expired. 46597c478bd9Sstevel@tonic-gate */ 46607c478bd9Sstevel@tonic-gate static void 46617c478bd9Sstevel@tonic-gate fdwatch(void *arg) 46627c478bd9Sstevel@tonic-gate { 46637c478bd9Sstevel@tonic-gate struct fdctlr *fdc = arg; 46647c478bd9Sstevel@tonic-gate int old_opmode; 46657c478bd9Sstevel@tonic-gate struct fdcsb *csb; 46667c478bd9Sstevel@tonic-gate 46677c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch\n")); 46687c478bd9Sstevel@tonic-gate 46697c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 46707c478bd9Sstevel@tonic-gate if (fdc->c_timeid == 0) { 46717c478bd9Sstevel@tonic-gate /* 46727c478bd9Sstevel@tonic-gate * fdintr got here first, ergo, no timeout condition.. 46737c478bd9Sstevel@tonic-gate */ 46747c478bd9Sstevel@tonic-gate 46757c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_WATC, 46767c478bd9Sstevel@tonic-gate (C, "fdwatch: no timeout\n")); 46777c478bd9Sstevel@tonic-gate 46787c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 46797c478bd9Sstevel@tonic-gate return; 46807c478bd9Sstevel@tonic-gate } 46817c478bd9Sstevel@tonic-gate fdc->c_timeid = 0; 46827c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 46837c478bd9Sstevel@tonic-gate 46847c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 46857c478bd9Sstevel@tonic-gate /* 46867c478bd9Sstevel@tonic-gate * XXXX: We should probably reset the bloody chip 46877c478bd9Sstevel@tonic-gate */ 46887c478bd9Sstevel@tonic-gate old_opmode = csb->csb_opmode; 46897c478bd9Sstevel@tonic-gate 46907c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_WATC, 46917c478bd9Sstevel@tonic-gate (C, "fd%d: timeout, opmode:%d\n", csb->csb_unit, old_opmode)); 46927c478bd9Sstevel@tonic-gate 46937c478bd9Sstevel@tonic-gate csb->csb_opmode = 4; 46947c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 46957c478bd9Sstevel@tonic-gate 46967c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch: cmd %s timed out\n", 46977c478bd9Sstevel@tonic-gate fdcmds[csb->csb_cmds[0] & 0x1f].cmdname)); 46987c478bd9Sstevel@tonic-gate fdc->c_flags |= FDCFLG_TIMEDOUT; 46997c478bd9Sstevel@tonic-gate csb->csb_status = CSB_CMDTO; 47007c478bd9Sstevel@tonic-gate 47017c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_DMA) == 0) { 47027c478bd9Sstevel@tonic-gate ddi_trigger_softintr(fdc->c_softid); 47037c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_WATCHDOG]++; 47047c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 47057c478bd9Sstevel@tonic-gate } else { 47067c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 47077c478bd9Sstevel@tonic-gate (void) fd_lointr((caddr_t)fdctlrs); 47087c478bd9Sstevel@tonic-gate } 47097c478bd9Sstevel@tonic-gate } 47107c478bd9Sstevel@tonic-gate 47117c478bd9Sstevel@tonic-gate /* 47127c478bd9Sstevel@tonic-gate * fdgetcsb 47137c478bd9Sstevel@tonic-gate * wait until the csb is free 47147c478bd9Sstevel@tonic-gate */ 47157c478bd9Sstevel@tonic-gate static void 47167c478bd9Sstevel@tonic-gate fdgetcsb(struct fdctlr *fdc) 47177c478bd9Sstevel@tonic-gate { 47187c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETC, (C, "fdgetcsb\n")); 47197c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&fdc->c_lolock)); 47207c478bd9Sstevel@tonic-gate while (fdc->c_flags & FDCFLG_BUSY) { 47217c478bd9Sstevel@tonic-gate fdc->c_flags |= FDCFLG_WANT; 47227c478bd9Sstevel@tonic-gate cv_wait(&fdc->c_csbcv, &fdc->c_lolock); 47237c478bd9Sstevel@tonic-gate } 47247c478bd9Sstevel@tonic-gate fdc->c_flags |= FDCFLG_BUSY; /* got it! */ 47257c478bd9Sstevel@tonic-gate } 47267c478bd9Sstevel@tonic-gate 47277c478bd9Sstevel@tonic-gate /* 47287c478bd9Sstevel@tonic-gate * fdretcsb 47297c478bd9Sstevel@tonic-gate * return csb 47307c478bd9Sstevel@tonic-gate */ 47317c478bd9Sstevel@tonic-gate static void 47327c478bd9Sstevel@tonic-gate fdretcsb(struct fdctlr *fdc) 47337c478bd9Sstevel@tonic-gate { 47347c478bd9Sstevel@tonic-gate 47357c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&fdc->c_lolock)); 47367c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RETC, (C, "fdretcsb\n")); 47377c478bd9Sstevel@tonic-gate fdc->c_flags &= ~FDCFLG_BUSY; /* let go */ 47387c478bd9Sstevel@tonic-gate 47397c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = 0; 47407c478bd9Sstevel@tonic-gate 47417c478bd9Sstevel@tonic-gate if (fdc->c_flags & FDCFLG_WANT) { 47427c478bd9Sstevel@tonic-gate fdc->c_flags ^= FDCFLG_WANT; 47437c478bd9Sstevel@tonic-gate /* 47447c478bd9Sstevel@tonic-gate * broadcast the signal. One thread will wake up and 47457c478bd9Sstevel@tonic-gate * set the flags to FDCFLG_BUSY. If more than one thread is 47467c478bd9Sstevel@tonic-gate * waiting then each thread will wake up in turn. The first 47477c478bd9Sstevel@tonic-gate * thread to wake-up will set the FDCFLG_BUSY flag and the 47487c478bd9Sstevel@tonic-gate * subsequent threads will will wake-up, but reset the 47497c478bd9Sstevel@tonic-gate * flag to FDCFLG_WANT because the FDCFLG_BUSY bit is set. 47507c478bd9Sstevel@tonic-gate */ 47517c478bd9Sstevel@tonic-gate cv_broadcast(&fdc->c_csbcv); 47527c478bd9Sstevel@tonic-gate } 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate 47557c478bd9Sstevel@tonic-gate 47567c478bd9Sstevel@tonic-gate /* 47577c478bd9Sstevel@tonic-gate * fdreset 47587c478bd9Sstevel@tonic-gate * reset THE controller, and configure it to be 47597c478bd9Sstevel@tonic-gate * the way it ought to be 47607c478bd9Sstevel@tonic-gate * ASSUMES: that it already owns the csb/fdctlr! 47617c478bd9Sstevel@tonic-gate * 47627c478bd9Sstevel@tonic-gate * - called with the low level lock held 47637c478bd9Sstevel@tonic-gate */ 47647c478bd9Sstevel@tonic-gate static int 47657c478bd9Sstevel@tonic-gate fdreset(struct fdctlr *fdc) 47667c478bd9Sstevel@tonic-gate { 47677c478bd9Sstevel@tonic-gate struct fdcsb *csb; 47687c478bd9Sstevel@tonic-gate clock_t local_lbolt = 0; 47697c478bd9Sstevel@tonic-gate timeout_id_t timeid; 47707c478bd9Sstevel@tonic-gate 47717c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset\n")); 47727c478bd9Sstevel@tonic-gate 47737c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&fdc->c_lolock)); 47747c478bd9Sstevel@tonic-gate 47757c478bd9Sstevel@tonic-gate /* count resets */ 47767c478bd9Sstevel@tonic-gate fdc->fdstats.reset++; 47777c478bd9Sstevel@tonic-gate 47787c478bd9Sstevel@tonic-gate /* 47797c478bd9Sstevel@tonic-gate * On the 82077, the DSR will clear itself after a reset. Upon exiting 47807c478bd9Sstevel@tonic-gate * the reset, a polling interrupt will be generated. If the floppy 47817c478bd9Sstevel@tonic-gate * interrupt is enabled, it's possible for cv_signal() to be called 47827c478bd9Sstevel@tonic-gate * before cv_wait(). This will cause the system to hang. Turn off 47837c478bd9Sstevel@tonic-gate * the floppy interrupt to avoid this race condition 47847c478bd9Sstevel@tonic-gate */ 47857c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) { 47867c478bd9Sstevel@tonic-gate /* 47877c478bd9Sstevel@tonic-gate * We need to perform any timeouts before we Reset the 47887c478bd9Sstevel@tonic-gate * controller. We cannot afford to drop the c_lolock mutex after 47897c478bd9Sstevel@tonic-gate * Resetting the controller. The reason is that we get a spate 47907c478bd9Sstevel@tonic-gate * of interrupts until we take the controller out of reset. 47917c478bd9Sstevel@tonic-gate * The way we avoid this spate of continuous interrupts is by 47927c478bd9Sstevel@tonic-gate * holding on to the c_lolock and forcing the fdintr_dma routine 47937c478bd9Sstevel@tonic-gate * to go to sleep waiting for this mutex. 47947c478bd9Sstevel@tonic-gate */ 47957c478bd9Sstevel@tonic-gate /* Do not hold the mutex across the untimeout call */ 47967c478bd9Sstevel@tonic-gate timeid = fdc->c_mtimeid; 47977c478bd9Sstevel@tonic-gate fdc->c_mtimeid = 0; 47987c478bd9Sstevel@tonic-gate if (timeid) { 47997c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 48007c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 48017c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 48027c478bd9Sstevel@tonic-gate } 48037c478bd9Sstevel@tonic-gate /* LINTED */ 48047c478bd9Sstevel@tonic-gate Set_dor(fdc, DMAGATE, 0); 48057c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset: set dor\n")); 48067c478bd9Sstevel@tonic-gate } 48077c478bd9Sstevel@tonic-gate 48087c478bd9Sstevel@tonic-gate /* toggle software reset */ 48097c478bd9Sstevel@tonic-gate Dsr(fdc, SWR); 48107c478bd9Sstevel@tonic-gate 48117c478bd9Sstevel@tonic-gate drv_usecwait(5); 48127c478bd9Sstevel@tonic-gate 48137c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RESE, 48147c478bd9Sstevel@tonic-gate (C, "fdreset: toggled software reset\n")); 48157c478bd9Sstevel@tonic-gate 48167c478bd9Sstevel@tonic-gate /* 48177c478bd9Sstevel@tonic-gate * This sets the data rate to 500Kbps (for high density) 48187c478bd9Sstevel@tonic-gate * XXX should use current characteristics instead XXX 48197c478bd9Sstevel@tonic-gate */ 48207c478bd9Sstevel@tonic-gate Dsr(fdc, 0); 48217c478bd9Sstevel@tonic-gate drv_usecwait(5); 48227c478bd9Sstevel@tonic-gate switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) { 48237c478bd9Sstevel@tonic-gate case FDCTYPE_82077: 48247c478bd9Sstevel@tonic-gate /* 48257c478bd9Sstevel@tonic-gate * when we bring the controller out of reset it will generate 48267c478bd9Sstevel@tonic-gate * a polling interrupt. fdintr() will field it and schedule 48277c478bd9Sstevel@tonic-gate * fd_lointr(). There will be no one sleeping but we are 48287c478bd9Sstevel@tonic-gate * expecting an interrupt so.... 48297c478bd9Sstevel@tonic-gate */ 48307c478bd9Sstevel@tonic-gate fdc->c_flags |= FDCFLG_WAITING; 48317c478bd9Sstevel@tonic-gate 48327c478bd9Sstevel@tonic-gate /* 48337c478bd9Sstevel@tonic-gate * The reset bit must be cleared to take the 077 out of 48347c478bd9Sstevel@tonic-gate * reset state and the DMAGATE bit must be high to enable 48357c478bd9Sstevel@tonic-gate * interrupts. 48367c478bd9Sstevel@tonic-gate */ 48377c478bd9Sstevel@tonic-gate /* LINTED */ 48387c478bd9Sstevel@tonic-gate Set_dor(fdc, DMAGATE|RESET, 1); 48397c478bd9Sstevel@tonic-gate 48407c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 48417c478bd9Sstevel@tonic-gate (C, "fdattach: Dor 0x%x\n", Dor(fdc))); 48427c478bd9Sstevel@tonic-gate 48437c478bd9Sstevel@tonic-gate local_lbolt = ddi_get_lbolt(); 48447c478bd9Sstevel@tonic-gate if (cv_timedwait(&fdc->c_iocv, &fdc->c_lolock, 48457c478bd9Sstevel@tonic-gate local_lbolt + drv_usectohz(1000000)) == -1) { 48467c478bd9Sstevel@tonic-gate return (-1); 48477c478bd9Sstevel@tonic-gate } 48487c478bd9Sstevel@tonic-gate break; 48497c478bd9Sstevel@tonic-gate 48507c478bd9Sstevel@tonic-gate default: 48517c478bd9Sstevel@tonic-gate fdc->c_flags |= FDCFLG_WAITING; 48527c478bd9Sstevel@tonic-gate 48537c478bd9Sstevel@tonic-gate /* 48547c478bd9Sstevel@tonic-gate * A timed wait is not used because it's possible for the timer 48557c478bd9Sstevel@tonic-gate * to go off before the controller has a chance to interrupt. 48567c478bd9Sstevel@tonic-gate */ 48577c478bd9Sstevel@tonic-gate cv_wait(&fdc->c_iocv, &fdc->c_lolock); 48587c478bd9Sstevel@tonic-gate break; 48597c478bd9Sstevel@tonic-gate } 48607c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 48617c478bd9Sstevel@tonic-gate 48627c478bd9Sstevel@tonic-gate /* setup common things in csb */ 48637c478bd9Sstevel@tonic-gate csb->csb_unit = fdc->c_un->un_unit_no; 48647c478bd9Sstevel@tonic-gate csb->csb_nrslts = 0; 48657c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFNORESULTS; 48667c478bd9Sstevel@tonic-gate csb->csb_maxretry = 0; 48677c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 48687c478bd9Sstevel@tonic-gate 48697c478bd9Sstevel@tonic-gate csb->csb_read = CSB_NULL; 48707c478bd9Sstevel@tonic-gate 48717c478bd9Sstevel@tonic-gate /* send SPECIFY command to fdc */ 48727c478bd9Sstevel@tonic-gate /* csb->unit is don't care */ 48737c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = FDRAW_SPECIFY; 48747c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = fdspec[0]; /* step rate, head unload time */ 48757c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) 48767c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = SPEC_DMA_MODE; 48777c478bd9Sstevel@tonic-gate else 48787c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = fdspec[1]; /* head load time, DMA mode */ 48797c478bd9Sstevel@tonic-gate 48807c478bd9Sstevel@tonic-gate csb->csb_ncmds = 3; 48817c478bd9Sstevel@tonic-gate 48827c478bd9Sstevel@tonic-gate /* XXX for now ignore errors, they "CAN'T HAPPEN" */ 48837c478bd9Sstevel@tonic-gate (void) fdexec(fdc, 0); /* no FDXC_CHECKCHG, ... */ 48847c478bd9Sstevel@tonic-gate /* no results */ 48857c478bd9Sstevel@tonic-gate 48867c478bd9Sstevel@tonic-gate /* send CONFIGURE command to fdc */ 48877c478bd9Sstevel@tonic-gate /* csb->unit is don't care */ 48887c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = CONFIGURE; 48897c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = fdconf[0]; /* motor info, motor delays */ 48907c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = fdconf[1]; /* enaimplsk, disapoll, fifothru */ 48917c478bd9Sstevel@tonic-gate csb->csb_cmds[3] = fdconf[2]; /* track precomp */ 48927c478bd9Sstevel@tonic-gate csb->csb_ncmds = 4; 48937c478bd9Sstevel@tonic-gate 48947c478bd9Sstevel@tonic-gate csb->csb_read = CSB_NULL; 48957c478bd9Sstevel@tonic-gate 48967c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 48977c478bd9Sstevel@tonic-gate 48987c478bd9Sstevel@tonic-gate /* XXX for now ignore errors, they "CAN'T HAPPEN" */ 48997c478bd9Sstevel@tonic-gate (void) fdexec(fdc, 0); /* no FDXC_CHECKCHG, ... */ 49007c478bd9Sstevel@tonic-gate return (0); 49017c478bd9Sstevel@tonic-gate } 49027c478bd9Sstevel@tonic-gate 49037c478bd9Sstevel@tonic-gate /* 49047c478bd9Sstevel@tonic-gate * fdrecalseek 49057c478bd9Sstevel@tonic-gate * performs recalibrates or seeks if the "arg" is -1 does a 49067c478bd9Sstevel@tonic-gate * recalibrate on a drive, else it seeks to the cylinder of 49077c478bd9Sstevel@tonic-gate * the drive. The recalibrate is also used to find a drive, 49087c478bd9Sstevel@tonic-gate * ie if the drive is not there, the controller says "error" 49097c478bd9Sstevel@tonic-gate * on the operation 49107c478bd9Sstevel@tonic-gate * NOTE: that there is special handling of this operation in the hardware 49117c478bd9Sstevel@tonic-gate * interrupt routine - it causes the operation to appear to have results; 49127c478bd9Sstevel@tonic-gate * ie the results of the SENSE INTERRUPT STATUS that the hardware interrupt 49137c478bd9Sstevel@tonic-gate * function did for us. 49147c478bd9Sstevel@tonic-gate * NOTE: because it uses sleep/wakeup it must be protected in a critical 49157c478bd9Sstevel@tonic-gate * section so create one before calling it! 49167c478bd9Sstevel@tonic-gate * 49177c478bd9Sstevel@tonic-gate * RETURNS: 0 for ok, 49187c478bd9Sstevel@tonic-gate * else errno from fdexec, 49197c478bd9Sstevel@tonic-gate * or ENODEV if error (infers hardware type error) 49207c478bd9Sstevel@tonic-gate * 49217c478bd9Sstevel@tonic-gate * - called with the low level lock held 49227c478bd9Sstevel@tonic-gate */ 49237c478bd9Sstevel@tonic-gate static int 49247c478bd9Sstevel@tonic-gate fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg) 49257c478bd9Sstevel@tonic-gate { 49267c478bd9Sstevel@tonic-gate struct fdcsb *csb; 49277c478bd9Sstevel@tonic-gate int result; 49287c478bd9Sstevel@tonic-gate 49297c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 49307c478bd9Sstevel@tonic-gate 49317c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RECA, (C, "fdrecalseek to %d\n", arg)); 49327c478bd9Sstevel@tonic-gate 49337c478bd9Sstevel@tonic-gate /* XXX TODO: check see argument for <= num cyls OR < 256 */ 49347c478bd9Sstevel@tonic-gate 49357c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 49367c478bd9Sstevel@tonic-gate csb->csb_unit = (uchar_t)unit; 49377c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = unit & 0x03; 49387c478bd9Sstevel@tonic-gate 49397c478bd9Sstevel@tonic-gate if (arg == -1) { /* is recal... */ 49407c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = FDRAW_REZERO; 49417c478bd9Sstevel@tonic-gate csb->csb_ncmds = 2; 49427c478bd9Sstevel@tonic-gate } else { 49437c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = FDRAW_SEEK; 49447c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = (uchar_t)arg; 49457c478bd9Sstevel@tonic-gate csb->csb_ncmds = 3; 49467c478bd9Sstevel@tonic-gate } 49477c478bd9Sstevel@tonic-gate csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */ 49487c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFSEEKOPS | CSB_OFTIMEIT; 49497c478bd9Sstevel@tonic-gate /* 49507c478bd9Sstevel@tonic-gate * MAYBE NYD need to set retries to different values? - depending on 49517c478bd9Sstevel@tonic-gate * drive characteristics - if we get to high capacity drives 49527c478bd9Sstevel@tonic-gate */ 49537c478bd9Sstevel@tonic-gate csb->csb_maxretry = skretry; 49547c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 49557c478bd9Sstevel@tonic-gate 49567c478bd9Sstevel@tonic-gate /* send cmd off to fdexec */ 49577c478bd9Sstevel@tonic-gate if (result = fdexec(fdc, FDXC_SLEEP | execflg)) { 49587c478bd9Sstevel@tonic-gate goto out; 49597c478bd9Sstevel@tonic-gate } 49607c478bd9Sstevel@tonic-gate 49617c478bd9Sstevel@tonic-gate /* 49627c478bd9Sstevel@tonic-gate * if recal, test for equipment check error 49637c478bd9Sstevel@tonic-gate * ASSUMES result = 0 from above call 49647c478bd9Sstevel@tonic-gate */ 49657c478bd9Sstevel@tonic-gate if (arg == -1) { 49667c478bd9Sstevel@tonic-gate result = 0; 49677c478bd9Sstevel@tonic-gate } else { 49687c478bd9Sstevel@tonic-gate /* for seeks, any old error will do */ 49697c478bd9Sstevel@tonic-gate if ((csb->csb_rslt[0] & IC_SR0) || csb->csb_cmdstat) 49707c478bd9Sstevel@tonic-gate result = ENODEV; 49717c478bd9Sstevel@tonic-gate } 49727c478bd9Sstevel@tonic-gate 49737c478bd9Sstevel@tonic-gate out: 49747c478bd9Sstevel@tonic-gate return (result); 49757c478bd9Sstevel@tonic-gate } 49767c478bd9Sstevel@tonic-gate 49777c478bd9Sstevel@tonic-gate /* 49787c478bd9Sstevel@tonic-gate * fdsensedrv 49797c478bd9Sstevel@tonic-gate * do a sense_drive command. used by fdopen and fdcheckdisk. 49807c478bd9Sstevel@tonic-gate * 49817c478bd9Sstevel@tonic-gate * - called with the lock held 49827c478bd9Sstevel@tonic-gate */ 49837c478bd9Sstevel@tonic-gate static int 49847c478bd9Sstevel@tonic-gate fdsensedrv(struct fdctlr *fdc, int unit) 49857c478bd9Sstevel@tonic-gate { 49867c478bd9Sstevel@tonic-gate struct fdcsb *csb; 49877c478bd9Sstevel@tonic-gate 49887c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 49897c478bd9Sstevel@tonic-gate 49907c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 49917c478bd9Sstevel@tonic-gate 49927c478bd9Sstevel@tonic-gate /* setup common things in csb */ 49937c478bd9Sstevel@tonic-gate csb->csb_unit = (uchar_t)unit; 49947c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFIMMEDIATE; 49957c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = FDRAW_SENSE_DRV; 49967c478bd9Sstevel@tonic-gate /* MOT bit set means don't delay */ 49977c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = MOT | (unit & 0x03); 49987c478bd9Sstevel@tonic-gate csb->csb_ncmds = 2; 49997c478bd9Sstevel@tonic-gate csb->csb_nrslts = 1; 50007c478bd9Sstevel@tonic-gate csb->csb_maxretry = skretry; 50017c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 50027c478bd9Sstevel@tonic-gate 50037c478bd9Sstevel@tonic-gate /* XXX for now ignore errors, they "CAN'T HAPPEN" */ 50047c478bd9Sstevel@tonic-gate (void) fdexec(fdc, 0); /* DON't check changed!, no sleep */ 50057c478bd9Sstevel@tonic-gate 50067c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_CHEK, 50077c478bd9Sstevel@tonic-gate (C, "fdsensedrv: result 0x%x", csb->csb_rslt[0])); 50087c478bd9Sstevel@tonic-gate 50097c478bd9Sstevel@tonic-gate return (csb->csb_rslt[0]); /* return status byte 3 */ 50107c478bd9Sstevel@tonic-gate } 50117c478bd9Sstevel@tonic-gate 50127c478bd9Sstevel@tonic-gate /* 50137c478bd9Sstevel@tonic-gate * fdcheckdisk 50147c478bd9Sstevel@tonic-gate * check to see if the disk is still there - do a recalibrate, 50157c478bd9Sstevel@tonic-gate * then see if DSKCHG line went away, if so, diskette is in; else 50167c478bd9Sstevel@tonic-gate * it's (still) out. 50177c478bd9Sstevel@tonic-gate */ 50187c478bd9Sstevel@tonic-gate 50197c478bd9Sstevel@tonic-gate static int 50207c478bd9Sstevel@tonic-gate fdcheckdisk(struct fdctlr *fdc, int unit) 50217c478bd9Sstevel@tonic-gate { 50227c478bd9Sstevel@tonic-gate auto struct fdcsb savecsb; 50237c478bd9Sstevel@tonic-gate struct fdcsb *csb; 50247c478bd9Sstevel@tonic-gate int err, st3; 50257c478bd9Sstevel@tonic-gate int seekto; /* where to seek for reset of DSKCHG */ 50267c478bd9Sstevel@tonic-gate 50277c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_CHEK, 50287c478bd9Sstevel@tonic-gate (C, "fdcheckdisk, unit %d\n", unit)); 50297c478bd9Sstevel@tonic-gate 50307c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 50317c478bd9Sstevel@tonic-gate 50327c478bd9Sstevel@tonic-gate /* 50337c478bd9Sstevel@tonic-gate * save old csb 50347c478bd9Sstevel@tonic-gate */ 50357c478bd9Sstevel@tonic-gate 50367c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 50377c478bd9Sstevel@tonic-gate savecsb = fdc->c_csb; 50387c478bd9Sstevel@tonic-gate bzero((caddr_t)csb, sizeof (*csb)); 50397c478bd9Sstevel@tonic-gate 50407c478bd9Sstevel@tonic-gate /* 50417c478bd9Sstevel@tonic-gate * Read drive status to see if at TRK0, if so, seek to cyl 1, 50427c478bd9Sstevel@tonic-gate * else seek to cyl 0. We do this because the controller is 50437c478bd9Sstevel@tonic-gate * "smart" enough to not send any step pulses (which are how 50447c478bd9Sstevel@tonic-gate * the DSKCHG line gets reset) if it sees TRK0 'cause it 50457c478bd9Sstevel@tonic-gate * knows the drive is already recalibrated. 50467c478bd9Sstevel@tonic-gate */ 50477c478bd9Sstevel@tonic-gate st3 = fdsensedrv(fdc, unit); 50487c478bd9Sstevel@tonic-gate 50497c478bd9Sstevel@tonic-gate /* check TRK0 bit in status */ 50507c478bd9Sstevel@tonic-gate if (st3 & T0_SR3) 50517c478bd9Sstevel@tonic-gate seekto = 1; /* at TRK0, seek out */ 50527c478bd9Sstevel@tonic-gate else 50537c478bd9Sstevel@tonic-gate seekto = 0; 50547c478bd9Sstevel@tonic-gate 50557c478bd9Sstevel@tonic-gate /* 50567c478bd9Sstevel@tonic-gate * DON'T recurse check changed 50577c478bd9Sstevel@tonic-gate */ 50587c478bd9Sstevel@tonic-gate err = fdrecalseek(fdc, unit, seekto, 0); 50597c478bd9Sstevel@tonic-gate 50607c478bd9Sstevel@tonic-gate /* "restore" old csb, check change state */ 50617c478bd9Sstevel@tonic-gate fdc->c_csb = savecsb; 50627c478bd9Sstevel@tonic-gate 50637c478bd9Sstevel@tonic-gate /* any recal/seek errors are too serious to attend to */ 50647c478bd9Sstevel@tonic-gate if (err) { 50657c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_CHEK, 50667c478bd9Sstevel@tonic-gate (C, "fdcheckdisk err %d\n", err)); 50677c478bd9Sstevel@tonic-gate return (err); 50687c478bd9Sstevel@tonic-gate } 50697c478bd9Sstevel@tonic-gate 50707c478bd9Sstevel@tonic-gate /* 50717c478bd9Sstevel@tonic-gate * if disk change still asserted, no diskette in drive! 50727c478bd9Sstevel@tonic-gate */ 50737c478bd9Sstevel@tonic-gate if (fdsense_chng(fdc, csb->csb_unit)) { 50747c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_CHEK, 50757c478bd9Sstevel@tonic-gate (C, "fdcheckdisk no disk\n")); 50767c478bd9Sstevel@tonic-gate return (1); 50777c478bd9Sstevel@tonic-gate } 50787c478bd9Sstevel@tonic-gate return (0); 50797c478bd9Sstevel@tonic-gate } 50807c478bd9Sstevel@tonic-gate 50817c478bd9Sstevel@tonic-gate /* 50827c478bd9Sstevel@tonic-gate * fdselect() - select drive, needed for external to chip select logic 50837c478bd9Sstevel@tonic-gate * fdeject() - ejects drive, must be previously selected 50847c478bd9Sstevel@tonic-gate * fdsense_chng() - sense disk changed line from previously selected drive 50857c478bd9Sstevel@tonic-gate * return s 1 is signal asserted, else 0 50867c478bd9Sstevel@tonic-gate */ 50877c478bd9Sstevel@tonic-gate /* ARGSUSED */ 50887c478bd9Sstevel@tonic-gate static void 50897c478bd9Sstevel@tonic-gate fdselect(struct fdctlr *fdc, int unit, int on) 50907c478bd9Sstevel@tonic-gate { 50917c478bd9Sstevel@tonic-gate 50927c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 50937c478bd9Sstevel@tonic-gate 50947c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_DSEL, 50957c478bd9Sstevel@tonic-gate (C, "fdselect, unit %d, on = %d\n", unit, on)); 50967c478bd9Sstevel@tonic-gate 50977c478bd9Sstevel@tonic-gate switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) { 50987c478bd9Sstevel@tonic-gate case FDCTYPE_MACHIO: 50997c478bd9Sstevel@tonic-gate set_auxioreg(AUX_DRVSELECT, on); 51007c478bd9Sstevel@tonic-gate break; 51017c478bd9Sstevel@tonic-gate 51027c478bd9Sstevel@tonic-gate case FDCTYPE_SLAVIO: 51037c478bd9Sstevel@tonic-gate case FDCTYPE_CHEERIO: 51047c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 51057c478bd9Sstevel@tonic-gate (C, "fdselect: (before) Dor 0x%x\n", Dor(fdc))); 51067c478bd9Sstevel@tonic-gate 51077c478bd9Sstevel@tonic-gate if (unit == 0) { 51087c478bd9Sstevel@tonic-gate Set_dor(fdc, DRVSEL, !on); 51097c478bd9Sstevel@tonic-gate } else { 51107c478bd9Sstevel@tonic-gate Set_dor(fdc, DRVSEL, on); 51117c478bd9Sstevel@tonic-gate } 51127c478bd9Sstevel@tonic-gate 51137c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_ATTA, 51147c478bd9Sstevel@tonic-gate (C, "fdselect: Dor 0x%x\n", Dor(fdc))); 51157c478bd9Sstevel@tonic-gate 51167c478bd9Sstevel@tonic-gate break; 51177c478bd9Sstevel@tonic-gate 51187c478bd9Sstevel@tonic-gate default: 51197c478bd9Sstevel@tonic-gate break; 51207c478bd9Sstevel@tonic-gate } 51217c478bd9Sstevel@tonic-gate } 51227c478bd9Sstevel@tonic-gate 51237c478bd9Sstevel@tonic-gate /* ARGSUSED */ 51247c478bd9Sstevel@tonic-gate static void 51257c478bd9Sstevel@tonic-gate fdeject(struct fdctlr *fdc, int unit) 51267c478bd9Sstevel@tonic-gate { 51277c478bd9Sstevel@tonic-gate struct fdunit *un; 51287c478bd9Sstevel@tonic-gate 51297c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 51307c478bd9Sstevel@tonic-gate 51317c478bd9Sstevel@tonic-gate un = fdc->c_un; 51327c478bd9Sstevel@tonic-gate 51337c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EJEC, (C, "fdeject\n")); 51347c478bd9Sstevel@tonic-gate /* 51357c478bd9Sstevel@tonic-gate * assume delay of function calling sufficient settling time 51367c478bd9Sstevel@tonic-gate * eject line is NOT driven by inverter so it is true low 51377c478bd9Sstevel@tonic-gate */ 51387c478bd9Sstevel@tonic-gate switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) { 51397c478bd9Sstevel@tonic-gate case FDCTYPE_MACHIO: 51407c478bd9Sstevel@tonic-gate set_auxioreg(AUX_EJECT, 0); 51417c478bd9Sstevel@tonic-gate drv_usecwait(2); 51427c478bd9Sstevel@tonic-gate set_auxioreg(AUX_EJECT, 1); 51437c478bd9Sstevel@tonic-gate break; 51447c478bd9Sstevel@tonic-gate 51457c478bd9Sstevel@tonic-gate case FDCTYPE_SLAVIO: 51467c478bd9Sstevel@tonic-gate if (!(Dor(fdc) & MOTEN(unit))) { 51477c478bd9Sstevel@tonic-gate /* LINTED */ 51487c478bd9Sstevel@tonic-gate Set_dor(fdc, MOTEN(unit), 1); 51497c478bd9Sstevel@tonic-gate } 51507c478bd9Sstevel@tonic-gate drv_usecwait(2); /* just to settle */ 51517c478bd9Sstevel@tonic-gate /* LINTED */ 51527c478bd9Sstevel@tonic-gate Set_dor(fdc, EJECT, 1); 51537c478bd9Sstevel@tonic-gate drv_usecwait(2); 51547c478bd9Sstevel@tonic-gate /* LINTED */ 51557c478bd9Sstevel@tonic-gate Set_dor(fdc, EJECT, 0); 51567c478bd9Sstevel@tonic-gate break; 51577c478bd9Sstevel@tonic-gate case FDCTYPE_CHEERIO: 51587c478bd9Sstevel@tonic-gate if (!(Dor(fdc) & MOTEN(unit))) { 51597c478bd9Sstevel@tonic-gate /* LINTED */ 51607c478bd9Sstevel@tonic-gate Set_dor(fdc, MOTEN(unit), 1); 51617c478bd9Sstevel@tonic-gate } 51627c478bd9Sstevel@tonic-gate drv_usecwait(2); /* just to settle */ 51637c478bd9Sstevel@tonic-gate /* LINTED */ 51647c478bd9Sstevel@tonic-gate Set_dor(fdc, EJECT_DMA, 1); 51657c478bd9Sstevel@tonic-gate drv_usecwait(2); 51667c478bd9Sstevel@tonic-gate /* LINTED */ 51677c478bd9Sstevel@tonic-gate Set_dor(fdc, EJECT_DMA, 0); 51687c478bd9Sstevel@tonic-gate break; 51697c478bd9Sstevel@tonic-gate } 51707c478bd9Sstevel@tonic-gate /* 51717c478bd9Sstevel@tonic-gate * XXX set ejected state? 51727c478bd9Sstevel@tonic-gate */ 51737c478bd9Sstevel@tonic-gate un->un_ejected = 1; 51747c478bd9Sstevel@tonic-gate } 51757c478bd9Sstevel@tonic-gate 51767c478bd9Sstevel@tonic-gate /* ARGSUSED */ 51777c478bd9Sstevel@tonic-gate static int 51787c478bd9Sstevel@tonic-gate fdsense_chng(struct fdctlr *fdc, int unit) 51797c478bd9Sstevel@tonic-gate { 51807c478bd9Sstevel@tonic-gate int changed = 0; 51817c478bd9Sstevel@tonic-gate 51827c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:start\n")); 51837c478bd9Sstevel@tonic-gate 51847c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 51857c478bd9Sstevel@tonic-gate 51867c478bd9Sstevel@tonic-gate /* 51877c478bd9Sstevel@tonic-gate * Do not turn on the motor of a pollable drive 51887c478bd9Sstevel@tonic-gate */ 51897c478bd9Sstevel@tonic-gate if (fd_pollable) { 51907c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "pollable: don't turn on motor\n")); 51917c478bd9Sstevel@tonic-gate /* 51927c478bd9Sstevel@tonic-gate * Invert the sense of the DSKCHG for pollable drives 51937c478bd9Sstevel@tonic-gate */ 51947c478bd9Sstevel@tonic-gate if (Dir(fdc) & DSKCHG) 51957c478bd9Sstevel@tonic-gate changed = 0; 51967c478bd9Sstevel@tonic-gate else 51977c478bd9Sstevel@tonic-gate changed = 1; 51987c478bd9Sstevel@tonic-gate 51997c478bd9Sstevel@tonic-gate return (changed); 52007c478bd9Sstevel@tonic-gate } 52017c478bd9Sstevel@tonic-gate 52027c478bd9Sstevel@tonic-gate switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) { 52037c478bd9Sstevel@tonic-gate case FDCTYPE_MACHIO: 52047c478bd9Sstevel@tonic-gate if (*fdc->c_auxiova & AUX_DISKCHG) 52057c478bd9Sstevel@tonic-gate changed = 1; 52067c478bd9Sstevel@tonic-gate break; 52077c478bd9Sstevel@tonic-gate 52087c478bd9Sstevel@tonic-gate case FDCTYPE_SB: 52097c478bd9Sstevel@tonic-gate case FDCTYPE_SLAVIO: 52107c478bd9Sstevel@tonic-gate case FDCTYPE_CHEERIO: 52117c478bd9Sstevel@tonic-gate if (!(Dor(fdc) & MOTEN(unit))) { 52127c478bd9Sstevel@tonic-gate /* LINTED */ 52137c478bd9Sstevel@tonic-gate Set_dor(fdc, MOTEN(unit), 1); 52147c478bd9Sstevel@tonic-gate } 52157c478bd9Sstevel@tonic-gate drv_usecwait(2); /* just to settle */ 52167c478bd9Sstevel@tonic-gate if (Dir(fdc) & DSKCHG) 52177c478bd9Sstevel@tonic-gate changed = 1; 52187c478bd9Sstevel@tonic-gate break; 52197c478bd9Sstevel@tonic-gate } 52207c478bd9Sstevel@tonic-gate 52217c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:end\n")); 52227c478bd9Sstevel@tonic-gate 52237c478bd9Sstevel@tonic-gate return (changed); 52247c478bd9Sstevel@tonic-gate } 52257c478bd9Sstevel@tonic-gate 52267c478bd9Sstevel@tonic-gate /* 52277c478bd9Sstevel@tonic-gate * if it can read a valid label it does so, else it will use a 52287c478bd9Sstevel@tonic-gate * default. If it can`t read the diskette - that is an error. 52297c478bd9Sstevel@tonic-gate * 52307c478bd9Sstevel@tonic-gate * RETURNS: 0 for ok - meaning that it could at least read the device, 52317c478bd9Sstevel@tonic-gate * !0 for error XXX TBD NYD error codes 52327c478bd9Sstevel@tonic-gate * 52337c478bd9Sstevel@tonic-gate * - called with the low level lock held 52347c478bd9Sstevel@tonic-gate */ 52357c478bd9Sstevel@tonic-gate static int 52367c478bd9Sstevel@tonic-gate fdgetlabel(struct fdctlr *fdc, int unit) 52377c478bd9Sstevel@tonic-gate { 52387c478bd9Sstevel@tonic-gate struct dk_label *label = NULL; 52397c478bd9Sstevel@tonic-gate struct fdunit *un; 52407c478bd9Sstevel@tonic-gate short *sp; 52417c478bd9Sstevel@tonic-gate short count; 52427c478bd9Sstevel@tonic-gate short xsum; /* checksum */ 52437c478bd9Sstevel@tonic-gate int i, tries; 52447c478bd9Sstevel@tonic-gate int err = 0; 52457c478bd9Sstevel@tonic-gate short oldlvl; 52467c478bd9Sstevel@tonic-gate 52477c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 52487c478bd9Sstevel@tonic-gate (C, "fdgetlabel: unit %d\n", unit)); 52497c478bd9Sstevel@tonic-gate 52507c478bd9Sstevel@tonic-gate un = fdc->c_un; 52517c478bd9Sstevel@tonic-gate un->un_flags &= ~(FDUNIT_UNLABELED); 52527c478bd9Sstevel@tonic-gate 52537c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 52547c478bd9Sstevel@tonic-gate 52557c478bd9Sstevel@tonic-gate /* Do not print errors since this is a private cmd */ 52567c478bd9Sstevel@tonic-gate 52577c478bd9Sstevel@tonic-gate oldlvl = fderrlevel; 52587c478bd9Sstevel@tonic-gate 52597c478bd9Sstevel@tonic-gate 52607c478bd9Sstevel@tonic-gate fderrlevel = FDEP_L4; 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate label = (struct dk_label *) 52637c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 52647c478bd9Sstevel@tonic-gate 52657c478bd9Sstevel@tonic-gate /* 52667c478bd9Sstevel@tonic-gate * try different characteristics (ie densities) by attempting to read 52677c478bd9Sstevel@tonic-gate * from the diskette. The diskette may not be present or 52687c478bd9Sstevel@tonic-gate * is unformatted. 52697c478bd9Sstevel@tonic-gate * 52707c478bd9Sstevel@tonic-gate * First, the last sector of the first track is read. If this 52717c478bd9Sstevel@tonic-gate * passes, attempt to read the last sector + 1 of the first track. 52727c478bd9Sstevel@tonic-gate * For example, for a high density diskette, sector 18 is read. If 52737c478bd9Sstevel@tonic-gate * the diskette is high density, this will pass. Next, try to 52747c478bd9Sstevel@tonic-gate * read sector 19 of the first track. This should fail. If it 52757c478bd9Sstevel@tonic-gate * passes, this is not a high density diskette. Finally, read 52767c478bd9Sstevel@tonic-gate * the first sector which should contain a label. 52777c478bd9Sstevel@tonic-gate * 52787c478bd9Sstevel@tonic-gate * if un->un_curfdtype is -1 then the current characteristics 52797c478bd9Sstevel@tonic-gate * were set by FDIOSCHAR and need to try it as well as everything 52807c478bd9Sstevel@tonic-gate * in the table 52817c478bd9Sstevel@tonic-gate */ 52827c478bd9Sstevel@tonic-gate if (un->un_curfdtype == -1) { 52837c478bd9Sstevel@tonic-gate tries = nfdtypes+1; 52847c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 52857c478bd9Sstevel@tonic-gate (C, "fdgetl: un_curfdtype is -1\n")); 52867c478bd9Sstevel@tonic-gate 52877c478bd9Sstevel@tonic-gate } else { 52887c478bd9Sstevel@tonic-gate tries = nfdtypes; 52897c478bd9Sstevel@tonic-gate 52907c478bd9Sstevel@tonic-gate /* Always start with the highest density (1.7MB) */ 52917c478bd9Sstevel@tonic-gate un->un_curfdtype = 0; 52927c478bd9Sstevel@tonic-gate *(un->un_chars) = fdtypes[un->un_curfdtype]; 52937c478bd9Sstevel@tonic-gate } 52947c478bd9Sstevel@tonic-gate 52957c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 52967c478bd9Sstevel@tonic-gate (C, "fdgetl: no. of tries %d\n", tries)); 52977c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 52987c478bd9Sstevel@tonic-gate (C, "fdgetl: no. of curfdtype %d\n", un->un_curfdtype)); 52997c478bd9Sstevel@tonic-gate 53007c478bd9Sstevel@tonic-gate for (i = 0; i < tries; i++) { 53017c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 53027c478bd9Sstevel@tonic-gate (C, "fdgetl: trying %d\n", i)); 53037c478bd9Sstevel@tonic-gate 53047c478bd9Sstevel@tonic-gate if (!(err = fdrw(fdc, unit, FDREAD, 0, 0, 53057c478bd9Sstevel@tonic-gate un->un_chars->fdc_secptrack, (caddr_t)label, 53067c478bd9Sstevel@tonic-gate sizeof (struct dk_label))) && 53077c478bd9Sstevel@tonic-gate 53087c478bd9Sstevel@tonic-gate fdrw(fdc, unit, FDREAD, 0, 0, 53097c478bd9Sstevel@tonic-gate un->un_chars->fdc_secptrack + 1, 53107c478bd9Sstevel@tonic-gate (caddr_t)label, sizeof (struct dk_label)) && 53117c478bd9Sstevel@tonic-gate 53127c478bd9Sstevel@tonic-gate !(err = fdrw(fdc, unit, FDREAD, 0, 0, 1, (caddr_t)label, 53137c478bd9Sstevel@tonic-gate sizeof (struct dk_label)))) { 53147c478bd9Sstevel@tonic-gate 53157c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 53167c478bd9Sstevel@tonic-gate (C, "fdgetl: succeeded\n")); 53177c478bd9Sstevel@tonic-gate 53187c478bd9Sstevel@tonic-gate break; 53197c478bd9Sstevel@tonic-gate } 53207c478bd9Sstevel@tonic-gate 53217c478bd9Sstevel@tonic-gate /* 53227c478bd9Sstevel@tonic-gate * try the next entry in the characteristics tbl 53237c478bd9Sstevel@tonic-gate * If curfdtype is -1, the nxt entry in tbl is 0 (the first). 53247c478bd9Sstevel@tonic-gate */ 53257c478bd9Sstevel@tonic-gate 53267c478bd9Sstevel@tonic-gate un->un_curfdtype = (un->un_curfdtype + 1) % nfdtypes; 53277c478bd9Sstevel@tonic-gate *(un->un_chars) = fdtypes[un->un_curfdtype]; 53287c478bd9Sstevel@tonic-gate 53297c478bd9Sstevel@tonic-gate 53307c478bd9Sstevel@tonic-gate } 53317c478bd9Sstevel@tonic-gate 53327c478bd9Sstevel@tonic-gate /* print errors again */ 53337c478bd9Sstevel@tonic-gate fderrlevel = oldlvl; 53347c478bd9Sstevel@tonic-gate 53357c478bd9Sstevel@tonic-gate /* Couldn't read anything */ 53367c478bd9Sstevel@tonic-gate if (err) { 53377c478bd9Sstevel@tonic-gate 53387c478bd9Sstevel@tonic-gate /* The default characteristics are high density (1.4MB) */ 53397c478bd9Sstevel@tonic-gate un->un_curfdtype = 1; 53407c478bd9Sstevel@tonic-gate *(un->un_chars) = fdtypes[un->un_curfdtype]; 53417c478bd9Sstevel@tonic-gate 53427c478bd9Sstevel@tonic-gate fdunpacklabel(&fdlbl_high_80, &un->un_label); 53437c478bd9Sstevel@tonic-gate 53447c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 53457c478bd9Sstevel@tonic-gate (C, "fdgetl: Can't autosense diskette\n")); 53467c478bd9Sstevel@tonic-gate 53477c478bd9Sstevel@tonic-gate goto out; 53487c478bd9Sstevel@tonic-gate } 53497c478bd9Sstevel@tonic-gate 53507c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 53517c478bd9Sstevel@tonic-gate (C, "fdgetl: fdtype=%d !!!\n", un->un_curfdtype)); 53527c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 53537c478bd9Sstevel@tonic-gate (C, "fdgetl: rate=%d ssize=%d !!!\n", 53547c478bd9Sstevel@tonic-gate un->un_chars->fdc_transfer_rate, un->un_chars->fdc_sec_size)); 53557c478bd9Sstevel@tonic-gate 53567c478bd9Sstevel@tonic-gate /* 53577c478bd9Sstevel@tonic-gate * _something_ was read - look for unixtype label 53587c478bd9Sstevel@tonic-gate */ 53597c478bd9Sstevel@tonic-gate if (label->dkl_magic != DKL_MAGIC) { 53607c478bd9Sstevel@tonic-gate 53617c478bd9Sstevel@tonic-gate /* 53627c478bd9Sstevel@tonic-gate * The label isn't a unix label. However, the diskette 53637c478bd9Sstevel@tonic-gate * is formatted because we were able to read the first 53647c478bd9Sstevel@tonic-gate * cylinder. 53657c478bd9Sstevel@tonic-gate */ 53667c478bd9Sstevel@tonic-gate 53677c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 53687c478bd9Sstevel@tonic-gate (C, "fdgetl: not unix label\n")); 53697c478bd9Sstevel@tonic-gate 53707c478bd9Sstevel@tonic-gate goto nolabel; 53717c478bd9Sstevel@tonic-gate } 53727c478bd9Sstevel@tonic-gate 53737c478bd9Sstevel@tonic-gate /* 53747c478bd9Sstevel@tonic-gate * Checksum the label 53757c478bd9Sstevel@tonic-gate */ 53767c478bd9Sstevel@tonic-gate count = sizeof (struct dk_label)/sizeof (short); 53777c478bd9Sstevel@tonic-gate sp = (short *)label; 53787c478bd9Sstevel@tonic-gate xsum = 0; 53797c478bd9Sstevel@tonic-gate while (count--) 53807c478bd9Sstevel@tonic-gate xsum ^= *sp++; /* should add up to 0 */ 53817c478bd9Sstevel@tonic-gate if (xsum) { 53827c478bd9Sstevel@tonic-gate 53837c478bd9Sstevel@tonic-gate /* 53847c478bd9Sstevel@tonic-gate * The checksum fails. However, the diskette is formatted 53857c478bd9Sstevel@tonic-gate * because we were able to read the first cylinder 53867c478bd9Sstevel@tonic-gate */ 53877c478bd9Sstevel@tonic-gate 53887c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 53897c478bd9Sstevel@tonic-gate (C, "fdgetl: bad cksum\n")); 53907c478bd9Sstevel@tonic-gate 53917c478bd9Sstevel@tonic-gate goto nolabel; 53927c478bd9Sstevel@tonic-gate } 53937c478bd9Sstevel@tonic-gate 53947c478bd9Sstevel@tonic-gate /* 53957c478bd9Sstevel@tonic-gate * The diskette has a unix label with a correct checksum. 53967c478bd9Sstevel@tonic-gate * Copy the label into the unit structure 53977c478bd9Sstevel@tonic-gate */ 53987c478bd9Sstevel@tonic-gate un->un_label = *label; 53997c478bd9Sstevel@tonic-gate 54007c478bd9Sstevel@tonic-gate goto out; 54017c478bd9Sstevel@tonic-gate 54027c478bd9Sstevel@tonic-gate nolabel: 54037c478bd9Sstevel@tonic-gate /* 54047c478bd9Sstevel@tonic-gate * The diskette doesn't have a correct unix label, but it is formatted. 54057c478bd9Sstevel@tonic-gate * Use a default label according to the diskette's density 54067c478bd9Sstevel@tonic-gate * (mark default used) 54077c478bd9Sstevel@tonic-gate */ 54087c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_GETL, 54097c478bd9Sstevel@tonic-gate (C, "fdgetlabel: unit %d\n", unit)); 54107c478bd9Sstevel@tonic-gate un->un_flags |= FDUNIT_UNLABELED; 54117c478bd9Sstevel@tonic-gate switch (un->un_chars->fdc_secptrack) { 54127c478bd9Sstevel@tonic-gate case 9: 54137c478bd9Sstevel@tonic-gate fdunpacklabel(&fdlbl_low_80, &un->un_label); 54147c478bd9Sstevel@tonic-gate break; 54157c478bd9Sstevel@tonic-gate case 8: 54167c478bd9Sstevel@tonic-gate fdunpacklabel(&fdlbl_medium_80, &un->un_label); 54177c478bd9Sstevel@tonic-gate break; 54187c478bd9Sstevel@tonic-gate case 18: 54197c478bd9Sstevel@tonic-gate fdunpacklabel(&fdlbl_high_80, &un->un_label); 54207c478bd9Sstevel@tonic-gate break; 54217c478bd9Sstevel@tonic-gate case 21: 54227c478bd9Sstevel@tonic-gate fdunpacklabel(&fdlbl_high_21, &un->un_label); 54237c478bd9Sstevel@tonic-gate break; 54247c478bd9Sstevel@tonic-gate default: 54257c478bd9Sstevel@tonic-gate fdunpacklabel(&fdlbl_high_80, &un->un_label); 54267c478bd9Sstevel@tonic-gate break; 54277c478bd9Sstevel@tonic-gate } 54287c478bd9Sstevel@tonic-gate 54297c478bd9Sstevel@tonic-gate out: 54307c478bd9Sstevel@tonic-gate if (label != NULL) 54317c478bd9Sstevel@tonic-gate kmem_free((caddr_t)label, sizeof (struct dk_label)); 54327c478bd9Sstevel@tonic-gate return (err); 54337c478bd9Sstevel@tonic-gate } 54347c478bd9Sstevel@tonic-gate 54357c478bd9Sstevel@tonic-gate /* 54367c478bd9Sstevel@tonic-gate * fdrw- used only for reading labels and for DKIOCSVTOC ioctl 54377c478bd9Sstevel@tonic-gate * which reads the 1 sector. 54387c478bd9Sstevel@tonic-gate */ 54397c478bd9Sstevel@tonic-gate static int 54407c478bd9Sstevel@tonic-gate fdrw(struct fdctlr *fdc, int unit, int rw, int cyl, int head, 54417c478bd9Sstevel@tonic-gate int sector, caddr_t bufp, uint_t len) 54427c478bd9Sstevel@tonic-gate { 54437c478bd9Sstevel@tonic-gate struct fdcsb *csb; 54447c478bd9Sstevel@tonic-gate struct fd_char *ch; 54457c478bd9Sstevel@tonic-gate int cmdresult = 0; 54467c478bd9Sstevel@tonic-gate caddr_t dma_addr; 54477c478bd9Sstevel@tonic-gate size_t real_length; 54487c478bd9Sstevel@tonic-gate int res; 54497c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 54507c478bd9Sstevel@tonic-gate ddi_acc_handle_t mem_handle = NULL; 54517c478bd9Sstevel@tonic-gate 54527c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw\n")); 54537c478bd9Sstevel@tonic-gate 54547c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 54557c478bd9Sstevel@tonic-gate 54567c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 54577c478bd9Sstevel@tonic-gate 54587c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 54597c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 54607c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON)) 54617c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 54627c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \ 54637c478bd9Sstevel@tonic-gate failed. \n")); 54647c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 54657c478bd9Sstevel@tonic-gate return (EIO); 54667c478bd9Sstevel@tonic-gate } 54677c478bd9Sstevel@tonic-gate 54687c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 54697c478bd9Sstevel@tonic-gate } 54707c478bd9Sstevel@tonic-gate 54717c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 54727c478bd9Sstevel@tonic-gate csb = &fdc->c_csb; 54737c478bd9Sstevel@tonic-gate ch = fdc->c_un->un_chars; 54747c478bd9Sstevel@tonic-gate if (rw == FDREAD) { 54757c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_TCBUG) { 54767c478bd9Sstevel@tonic-gate /* 54777c478bd9Sstevel@tonic-gate * kludge for lack of Multitrack functionality 54787c478bd9Sstevel@tonic-gate */ 54797c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = SK + FDRAW_RDCMD; 54807c478bd9Sstevel@tonic-gate } else 54817c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = MT + SK + FDRAW_RDCMD; 54827c478bd9Sstevel@tonic-gate } else { /* write */ 54837c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_TCBUG) { 54847c478bd9Sstevel@tonic-gate /* 54857c478bd9Sstevel@tonic-gate * kludge for lack of Multitrack functionality 54867c478bd9Sstevel@tonic-gate */ 54877c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = FDRAW_WRCMD; 54887c478bd9Sstevel@tonic-gate } else 54897c478bd9Sstevel@tonic-gate csb->csb_cmds[0] = MT + FDRAW_WRCMD; 54907c478bd9Sstevel@tonic-gate } 54917c478bd9Sstevel@tonic-gate 54927c478bd9Sstevel@tonic-gate if (rw == FDREAD) 54937c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_READ; 54947c478bd9Sstevel@tonic-gate else 54957c478bd9Sstevel@tonic-gate fdc->c_csb.csb_read = CSB_WRITE; 54967c478bd9Sstevel@tonic-gate 54977c478bd9Sstevel@tonic-gate /* always or in MFM bit */ 54987c478bd9Sstevel@tonic-gate csb->csb_cmds[0] |= MFM; 54997c478bd9Sstevel@tonic-gate csb->csb_cmds[1] = (uchar_t)(unit | ((head & 0x1) << 2)); 55007c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) 55017c478bd9Sstevel@tonic-gate csb->csb_cmds[1] |= IPS; 55027c478bd9Sstevel@tonic-gate csb->csb_cmds[2] = (uchar_t)cyl; 55037c478bd9Sstevel@tonic-gate csb->csb_cmds[3] = (uchar_t)head; 55047c478bd9Sstevel@tonic-gate csb->csb_cmds[4] = (uchar_t)sector; 55057c478bd9Sstevel@tonic-gate csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size code */ 55067c478bd9Sstevel@tonic-gate /* 55077c478bd9Sstevel@tonic-gate * kludge for end-of-cylinder error. 55087c478bd9Sstevel@tonic-gate */ 55097c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_TCBUG) 55107c478bd9Sstevel@tonic-gate csb->csb_cmds[6] = sector + (len / ch->fdc_sec_size) - 1; 55117c478bd9Sstevel@tonic-gate else 55127c478bd9Sstevel@tonic-gate csb->csb_cmds[6] = 55137c478bd9Sstevel@tonic-gate (uchar_t)max(fdc->c_un->un_chars->fdc_secptrack, sector); 55147c478bd9Sstevel@tonic-gate csb->csb_len = len; 55157c478bd9Sstevel@tonic-gate csb->csb_cmds[7] = GPLN; 55167c478bd9Sstevel@tonic-gate csb->csb_cmds[8] = SSSDTL; 55177c478bd9Sstevel@tonic-gate csb->csb_ncmds = NCBRW; 55187c478bd9Sstevel@tonic-gate csb->csb_len = len; 55197c478bd9Sstevel@tonic-gate csb->csb_maxretry = 2; 55207c478bd9Sstevel@tonic-gate csb->csb_retrys = 0; 55217c478bd9Sstevel@tonic-gate bzero(csb->csb_rslt, NRBRW); 55227c478bd9Sstevel@tonic-gate csb->csb_nrslts = NRBRW; 55237c478bd9Sstevel@tonic-gate csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT; 55247c478bd9Sstevel@tonic-gate 55257c478bd9Sstevel@tonic-gate /* If platform supports DMA, set up DMA resources */ 55267c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 55277c478bd9Sstevel@tonic-gate 55287c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 55297c478bd9Sstevel@tonic-gate 55307c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 55317c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 55327c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 55337c478bd9Sstevel@tonic-gate 55347c478bd9Sstevel@tonic-gate res = ddi_dma_mem_alloc(fdc->c_dmahandle, len, 55357c478bd9Sstevel@tonic-gate &attr, DDI_DMA_STREAMING, 55367c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, 0, &dma_addr, &real_length, 55377c478bd9Sstevel@tonic-gate &mem_handle); 55387c478bd9Sstevel@tonic-gate 55397c478bd9Sstevel@tonic-gate if (res != DDI_SUCCESS) { 55407c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RW, 55417c478bd9Sstevel@tonic-gate (C, "fdrw: dma mem alloc failed\n")); 55427c478bd9Sstevel@tonic-gate 55437c478bd9Sstevel@tonic-gate fdretcsb(fdc); 55447c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 55457c478bd9Sstevel@tonic-gate return (EIO); 55467c478bd9Sstevel@tonic-gate } 55477c478bd9Sstevel@tonic-gate 55487c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: allocated memory")); 55497c478bd9Sstevel@tonic-gate 55507c478bd9Sstevel@tonic-gate if (fdstart_dma(fdc, dma_addr, len) != 0) { 55517c478bd9Sstevel@tonic-gate fdretcsb(fdc); 55527c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 55537c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 55547c478bd9Sstevel@tonic-gate return (-1); 55557c478bd9Sstevel@tonic-gate 55567c478bd9Sstevel@tonic-gate } 55577c478bd9Sstevel@tonic-gate 55587c478bd9Sstevel@tonic-gate /* 55597c478bd9Sstevel@tonic-gate * If the command is a write, copy the data to be written to 55607c478bd9Sstevel@tonic-gate * dma_addr. 55617c478bd9Sstevel@tonic-gate */ 55627c478bd9Sstevel@tonic-gate 55637c478bd9Sstevel@tonic-gate if (fdc->c_csb.csb_read == CSB_WRITE) { 55647c478bd9Sstevel@tonic-gate bcopy((char *)bufp, (char *)dma_addr, len); 55657c478bd9Sstevel@tonic-gate } 55667c478bd9Sstevel@tonic-gate 55677c478bd9Sstevel@tonic-gate csb->csb_addr = dma_addr; 55687c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 55697c478bd9Sstevel@tonic-gate } else { 55707c478bd9Sstevel@tonic-gate csb->csb_addr = bufp; 55717c478bd9Sstevel@tonic-gate } 55727c478bd9Sstevel@tonic-gate 55737c478bd9Sstevel@tonic-gate 55747c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: call fdexec\n")); 55757c478bd9Sstevel@tonic-gate 55767c478bd9Sstevel@tonic-gate if (fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG) != 0) { 55777c478bd9Sstevel@tonic-gate fdretcsb(fdc); 55787c478bd9Sstevel@tonic-gate 55797c478bd9Sstevel@tonic-gate if (mem_handle) 55807c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 55817c478bd9Sstevel@tonic-gate 55827c478bd9Sstevel@tonic-gate return (EIO); 55837c478bd9Sstevel@tonic-gate 55847c478bd9Sstevel@tonic-gate } 55857c478bd9Sstevel@tonic-gate 55867c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: fdexec returned\n")); 55877c478bd9Sstevel@tonic-gate 55887c478bd9Sstevel@tonic-gate /* 55897c478bd9Sstevel@tonic-gate * if DMA was used and the command was a read 55907c478bd9Sstevel@tonic-gate * copy the results into bufp 55917c478bd9Sstevel@tonic-gate */ 55927c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 55937c478bd9Sstevel@tonic-gate if (fdc->c_csb.csb_read == CSB_READ) { 55947c478bd9Sstevel@tonic-gate bcopy((char *)dma_addr, (char *)bufp, len); 55957c478bd9Sstevel@tonic-gate } 55967c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&mem_handle); 55977c478bd9Sstevel@tonic-gate } 55987c478bd9Sstevel@tonic-gate 55997c478bd9Sstevel@tonic-gate if (csb->csb_cmdstat) 56007c478bd9Sstevel@tonic-gate cmdresult = EIO; /* XXX TBD NYD for now */ 56017c478bd9Sstevel@tonic-gate 56027c478bd9Sstevel@tonic-gate fdretcsb(fdc); 56037c478bd9Sstevel@tonic-gate return (cmdresult); 56047c478bd9Sstevel@tonic-gate } 56057c478bd9Sstevel@tonic-gate 56067c478bd9Sstevel@tonic-gate /* 56077c478bd9Sstevel@tonic-gate * fdunpacklabel 56087c478bd9Sstevel@tonic-gate * this unpacks a (packed) struct dk_label into a standard dk_label. 56097c478bd9Sstevel@tonic-gate */ 56107c478bd9Sstevel@tonic-gate static void 56117c478bd9Sstevel@tonic-gate fdunpacklabel(struct packed_label *from, struct dk_label *to) 56127c478bd9Sstevel@tonic-gate { 56137c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PACK, (C, "fdpacklabel\n")); 56147c478bd9Sstevel@tonic-gate bzero((caddr_t)to, sizeof (*to)); 56157c478bd9Sstevel@tonic-gate bcopy((caddr_t)&from->dkl_vname, (caddr_t)to->dkl_asciilabel, 56167c478bd9Sstevel@tonic-gate sizeof (to->dkl_asciilabel)); 56177c478bd9Sstevel@tonic-gate to->dkl_rpm = from->dkl_rpm; /* rotations per minute */ 56187c478bd9Sstevel@tonic-gate to->dkl_pcyl = from->dkl_pcyl; /* # physical cylinders */ 56197c478bd9Sstevel@tonic-gate to->dkl_apc = from->dkl_apc; /* alternates per cylinder */ 56207c478bd9Sstevel@tonic-gate to->dkl_intrlv = from->dkl_intrlv; /* interleave factor */ 56217c478bd9Sstevel@tonic-gate to->dkl_ncyl = from->dkl_ncyl; /* # of data cylinders */ 56227c478bd9Sstevel@tonic-gate to->dkl_acyl = from->dkl_acyl; /* # of alternate cylinders */ 56237c478bd9Sstevel@tonic-gate to->dkl_nhead = from->dkl_nhead; /* # of heads in this partition */ 56247c478bd9Sstevel@tonic-gate to->dkl_nsect = from->dkl_nsect; /* # of 512 byte sectors per track */ 56257c478bd9Sstevel@tonic-gate /* logical partitions */ 56267c478bd9Sstevel@tonic-gate bcopy((caddr_t)from->dkl_map, (caddr_t)to->dkl_map, 56277c478bd9Sstevel@tonic-gate sizeof (struct dk_map32) * NDKMAP); 56287c478bd9Sstevel@tonic-gate to->dkl_vtoc = from->dkl_vtoc; 56297c478bd9Sstevel@tonic-gate } 56307c478bd9Sstevel@tonic-gate 56317c478bd9Sstevel@tonic-gate static struct fdctlr * 56327c478bd9Sstevel@tonic-gate fd_getctlr(dev_t dev) 56337c478bd9Sstevel@tonic-gate { 56347c478bd9Sstevel@tonic-gate 56357c478bd9Sstevel@tonic-gate struct fdctlr *fdc = fdctlrs; 56367c478bd9Sstevel@tonic-gate int ctlr = FDCTLR(dev); 56377c478bd9Sstevel@tonic-gate 56387c478bd9Sstevel@tonic-gate while (fdc) { 56397c478bd9Sstevel@tonic-gate if (ddi_get_instance(fdc->c_dip) == ctlr) 56407c478bd9Sstevel@tonic-gate return (fdc); 56417c478bd9Sstevel@tonic-gate fdc = fdc->c_next; 56427c478bd9Sstevel@tonic-gate } 56437c478bd9Sstevel@tonic-gate return (fdc); 56447c478bd9Sstevel@tonic-gate } 56457c478bd9Sstevel@tonic-gate 56467c478bd9Sstevel@tonic-gate static int 56477c478bd9Sstevel@tonic-gate fd_unit_is_open(struct fdunit *un) 56487c478bd9Sstevel@tonic-gate { 56497c478bd9Sstevel@tonic-gate int i; 56507c478bd9Sstevel@tonic-gate for (i = 0; i < NDKMAP; i++) 56517c478bd9Sstevel@tonic-gate if (un->un_lyropen[i]) 56527c478bd9Sstevel@tonic-gate return (1); 56537c478bd9Sstevel@tonic-gate for (i = 0; i < OTYPCNT - 1; i++) 56547c478bd9Sstevel@tonic-gate if (un->un_regopen[i]) 56557c478bd9Sstevel@tonic-gate return (1); 56567c478bd9Sstevel@tonic-gate return (0); 56577c478bd9Sstevel@tonic-gate } 56587c478bd9Sstevel@tonic-gate 56597c478bd9Sstevel@tonic-gate /* 56607c478bd9Sstevel@tonic-gate * Return the a vtoc structure in *vtoc. 56617c478bd9Sstevel@tonic-gate * The vtoc is built from information in 56627c478bd9Sstevel@tonic-gate * the diskette's label. 56637c478bd9Sstevel@tonic-gate */ 56647c478bd9Sstevel@tonic-gate static void 56657c478bd9Sstevel@tonic-gate fd_build_user_vtoc(struct fdunit *un, struct vtoc *vtoc) 56667c478bd9Sstevel@tonic-gate { 56677c478bd9Sstevel@tonic-gate int i; 56687c478bd9Sstevel@tonic-gate int nblks; /* DEV_BSIZE sectors per cylinder */ 56697c478bd9Sstevel@tonic-gate struct dk_map2 *lpart; 56707c478bd9Sstevel@tonic-gate struct dk_map32 *lmap; 56717c478bd9Sstevel@tonic-gate struct partition *vpart; 56727c478bd9Sstevel@tonic-gate 56737c478bd9Sstevel@tonic-gate bzero(vtoc, sizeof (struct vtoc)); 56747c478bd9Sstevel@tonic-gate 56757c478bd9Sstevel@tonic-gate /* Initialize info. needed by mboot. (unsupported) */ 56767c478bd9Sstevel@tonic-gate vtoc->v_bootinfo[0] = un->un_label.dkl_vtoc.v_bootinfo[0]; 56777c478bd9Sstevel@tonic-gate vtoc->v_bootinfo[1] = un->un_label.dkl_vtoc.v_bootinfo[1]; 56787c478bd9Sstevel@tonic-gate vtoc->v_bootinfo[2] = un->un_label.dkl_vtoc.v_bootinfo[2]; 56797c478bd9Sstevel@tonic-gate 56807c478bd9Sstevel@tonic-gate /* Fill in vtoc sanity and version information */ 56817c478bd9Sstevel@tonic-gate vtoc->v_sanity = un->un_label.dkl_vtoc.v_sanity; 56827c478bd9Sstevel@tonic-gate vtoc->v_version = un->un_label.dkl_vtoc.v_version; 56837c478bd9Sstevel@tonic-gate 56847c478bd9Sstevel@tonic-gate /* Copy the volume name */ 56857c478bd9Sstevel@tonic-gate bcopy(un->un_label.dkl_vtoc.v_volume, 56867c478bd9Sstevel@tonic-gate vtoc->v_volume, LEN_DKL_VVOL); 56877c478bd9Sstevel@tonic-gate 56887c478bd9Sstevel@tonic-gate /* 56897c478bd9Sstevel@tonic-gate * The dk_map32 structure is based on DEV_BSIZE byte blocks. 56907c478bd9Sstevel@tonic-gate * However, medium density diskettes have 1024 byte blocks. 56917c478bd9Sstevel@tonic-gate * The number of sectors per partition listed in the dk_map32 structure 56927c478bd9Sstevel@tonic-gate * accounts for this by multiplying the number of 1024 byte 56937c478bd9Sstevel@tonic-gate * blocks by 2. (See the packed_label initializations.) The 56947c478bd9Sstevel@tonic-gate * 1024 byte block size can not be listed for medium density 56957c478bd9Sstevel@tonic-gate * diskettes because the kernel is hard coded for DEV_BSIZE 56967c478bd9Sstevel@tonic-gate * blocks. 56977c478bd9Sstevel@tonic-gate */ 56987c478bd9Sstevel@tonic-gate vtoc->v_sectorsz = DEV_BSIZE; 56997c478bd9Sstevel@tonic-gate vtoc->v_nparts = un->un_label.dkl_vtoc.v_nparts; 57007c478bd9Sstevel@tonic-gate 57017c478bd9Sstevel@tonic-gate /* Copy the reserved space */ 57027c478bd9Sstevel@tonic-gate bcopy(un->un_label.dkl_vtoc.v_reserved, 57037c478bd9Sstevel@tonic-gate vtoc->v_reserved, sizeof (un->un_label.dkl_vtoc.v_reserved)); 57047c478bd9Sstevel@tonic-gate /* 57057c478bd9Sstevel@tonic-gate * Convert partitioning information. 57067c478bd9Sstevel@tonic-gate * 57077c478bd9Sstevel@tonic-gate * Note the conversion from starting cylinder number 57087c478bd9Sstevel@tonic-gate * to starting sector number. 57097c478bd9Sstevel@tonic-gate */ 57107c478bd9Sstevel@tonic-gate lmap = un->un_label.dkl_map; 57117c478bd9Sstevel@tonic-gate lpart = un->un_label.dkl_vtoc.v_part; 57127c478bd9Sstevel@tonic-gate vpart = vtoc->v_part; 57137c478bd9Sstevel@tonic-gate 57147c478bd9Sstevel@tonic-gate nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack * 57157c478bd9Sstevel@tonic-gate un->un_chars->fdc_sec_size) / DEV_BSIZE; 57167c478bd9Sstevel@tonic-gate 57177c478bd9Sstevel@tonic-gate for (i = 0; i < V_NUMPAR; i++) { 57187c478bd9Sstevel@tonic-gate vpart->p_tag = lpart->p_tag; 57197c478bd9Sstevel@tonic-gate vpart->p_flag = lpart->p_flag; 57207c478bd9Sstevel@tonic-gate vpart->p_start = lmap->dkl_cylno * nblks; 57217c478bd9Sstevel@tonic-gate vpart->p_size = lmap->dkl_nblk; 57227c478bd9Sstevel@tonic-gate 57237c478bd9Sstevel@tonic-gate lmap++; 57247c478bd9Sstevel@tonic-gate lpart++; 57257c478bd9Sstevel@tonic-gate vpart++; 57267c478bd9Sstevel@tonic-gate } 57277c478bd9Sstevel@tonic-gate 57287c478bd9Sstevel@tonic-gate /* Initialize timestamp and label */ 57297c478bd9Sstevel@tonic-gate bcopy(un->un_label.dkl_vtoc.v_timestamp, 57307c478bd9Sstevel@tonic-gate vtoc->timestamp, sizeof (vtoc->timestamp)); 57317c478bd9Sstevel@tonic-gate 57327c478bd9Sstevel@tonic-gate bcopy(un->un_label.dkl_asciilabel, 57337c478bd9Sstevel@tonic-gate vtoc->v_asciilabel, LEN_DKL_ASCII); 57347c478bd9Sstevel@tonic-gate } 57357c478bd9Sstevel@tonic-gate 57367c478bd9Sstevel@tonic-gate /* 57377c478bd9Sstevel@tonic-gate * Build a label out of a vtoc structure. 57387c478bd9Sstevel@tonic-gate */ 57397c478bd9Sstevel@tonic-gate static int 57407c478bd9Sstevel@tonic-gate fd_build_label_vtoc(struct fdunit *un, struct vtoc *vtoc) 57417c478bd9Sstevel@tonic-gate { 57427c478bd9Sstevel@tonic-gate struct dk_map32 *lmap; 57437c478bd9Sstevel@tonic-gate struct dk_map2 *lpart; 57447c478bd9Sstevel@tonic-gate struct partition *vpart; 57457c478bd9Sstevel@tonic-gate int nblks; /* no. blocks per cylinder */ 57467c478bd9Sstevel@tonic-gate int ncyl; 57477c478bd9Sstevel@tonic-gate int i; 57487c478bd9Sstevel@tonic-gate short sum, *sp; 57497c478bd9Sstevel@tonic-gate 57507c478bd9Sstevel@tonic-gate /* Sanity-check the vtoc */ 57517c478bd9Sstevel@tonic-gate if ((vtoc->v_sanity != VTOC_SANE) || 57527c478bd9Sstevel@tonic-gate (vtoc->v_nparts > NDKMAP) || (vtoc->v_nparts <= 0)) { 57537c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_IOCT, 57547c478bd9Sstevel@tonic-gate (C, "fd_build_label: sanity check on vtoc failed\n")); 57557c478bd9Sstevel@tonic-gate return (EINVAL); 57567c478bd9Sstevel@tonic-gate } 57577c478bd9Sstevel@tonic-gate 57587c478bd9Sstevel@tonic-gate nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack * 57597c478bd9Sstevel@tonic-gate un->un_chars->fdc_sec_size) / DEV_BSIZE; 57607c478bd9Sstevel@tonic-gate 57617c478bd9Sstevel@tonic-gate vpart = vtoc->v_part; 57627c478bd9Sstevel@tonic-gate 57637c478bd9Sstevel@tonic-gate /* 57647c478bd9Sstevel@tonic-gate * Check the partition information in the vtoc. The starting sectors 57657c478bd9Sstevel@tonic-gate * must lie along partition boundaries. (NDKMAP entries are checked 57667c478bd9Sstevel@tonic-gate * to ensure that the unused entries are set to 0 if vtoc->v_nparts 57677c478bd9Sstevel@tonic-gate * is less than NDKMAP) 57687c478bd9Sstevel@tonic-gate */ 57697c478bd9Sstevel@tonic-gate 57707c478bd9Sstevel@tonic-gate for (i = 0; i < NDKMAP; i++) { 57717c478bd9Sstevel@tonic-gate if ((vpart->p_start % nblks) != 0) { 57727c478bd9Sstevel@tonic-gate return (EINVAL); 57737c478bd9Sstevel@tonic-gate } 57747c478bd9Sstevel@tonic-gate ncyl = vpart->p_start % nblks; 57757c478bd9Sstevel@tonic-gate ncyl += vpart->p_size % nblks; 57767c478bd9Sstevel@tonic-gate if ((vpart->p_size % nblks) != 0) 57777c478bd9Sstevel@tonic-gate ncyl++; 57787c478bd9Sstevel@tonic-gate if (ncyl > un->un_chars->fdc_ncyl) { 57797c478bd9Sstevel@tonic-gate return (EINVAL); 57807c478bd9Sstevel@tonic-gate } 57817c478bd9Sstevel@tonic-gate vpart++; 57827c478bd9Sstevel@tonic-gate } 57837c478bd9Sstevel@tonic-gate 57847c478bd9Sstevel@tonic-gate /* 57857c478bd9Sstevel@tonic-gate * reinitialize the existing label 57867c478bd9Sstevel@tonic-gate */ 57877c478bd9Sstevel@tonic-gate bzero(&un->un_label, sizeof (un->un_label)); 57887c478bd9Sstevel@tonic-gate 57897c478bd9Sstevel@tonic-gate /* Put appropriate vtoc structure fields into the disk label */ 57907c478bd9Sstevel@tonic-gate un->un_label.dkl_vtoc.v_bootinfo[0] = (uint32_t)vtoc->v_bootinfo[0]; 57917c478bd9Sstevel@tonic-gate un->un_label.dkl_vtoc.v_bootinfo[1] = (uint32_t)vtoc->v_bootinfo[1]; 57927c478bd9Sstevel@tonic-gate un->un_label.dkl_vtoc.v_bootinfo[2] = (uint32_t)vtoc->v_bootinfo[2]; 57937c478bd9Sstevel@tonic-gate 57947c478bd9Sstevel@tonic-gate un->un_label.dkl_vtoc.v_sanity = vtoc->v_sanity; 57957c478bd9Sstevel@tonic-gate un->un_label.dkl_vtoc.v_version = vtoc->v_version; 57967c478bd9Sstevel@tonic-gate 57977c478bd9Sstevel@tonic-gate bcopy(vtoc->v_volume, un->un_label.dkl_vtoc.v_volume, LEN_DKL_VVOL); 57987c478bd9Sstevel@tonic-gate 57997c478bd9Sstevel@tonic-gate un->un_label.dkl_vtoc.v_nparts = vtoc->v_nparts; 58007c478bd9Sstevel@tonic-gate 58017c478bd9Sstevel@tonic-gate bcopy(vtoc->v_reserved, un->un_label.dkl_vtoc.v_reserved, 58027c478bd9Sstevel@tonic-gate sizeof (un->un_label.dkl_vtoc.v_reserved)); 58037c478bd9Sstevel@tonic-gate 58047c478bd9Sstevel@tonic-gate /* 58057c478bd9Sstevel@tonic-gate * Initialize cylinder information in the label. 58067c478bd9Sstevel@tonic-gate * Note the conversion from starting sector number 58077c478bd9Sstevel@tonic-gate * to starting cylinder number. 58087c478bd9Sstevel@tonic-gate * Return error if division results in a remainder. 58097c478bd9Sstevel@tonic-gate */ 58107c478bd9Sstevel@tonic-gate lmap = un->un_label.dkl_map; 58117c478bd9Sstevel@tonic-gate lpart = un->un_label.dkl_vtoc.v_part; 58127c478bd9Sstevel@tonic-gate vpart = vtoc->v_part; 58137c478bd9Sstevel@tonic-gate 58147c478bd9Sstevel@tonic-gate for (i = 0; i < (int)vtoc->v_nparts; i++) { 58157c478bd9Sstevel@tonic-gate lpart->p_tag = vtoc->v_part[i].p_tag; 58167c478bd9Sstevel@tonic-gate lpart->p_flag = vtoc->v_part[i].p_flag; 58177c478bd9Sstevel@tonic-gate lmap->dkl_cylno = vpart->p_start / nblks; 58187c478bd9Sstevel@tonic-gate lmap->dkl_nblk = vpart->p_size; 58197c478bd9Sstevel@tonic-gate 58207c478bd9Sstevel@tonic-gate lmap++; 58217c478bd9Sstevel@tonic-gate lpart++; 58227c478bd9Sstevel@tonic-gate vpart++; 58237c478bd9Sstevel@tonic-gate } 58247c478bd9Sstevel@tonic-gate 58257c478bd9Sstevel@tonic-gate /* Copy the timestamp and ascii label */ 58267c478bd9Sstevel@tonic-gate for (i = 0; i < NDKMAP; i++) { 58277c478bd9Sstevel@tonic-gate un->un_label.dkl_vtoc.v_timestamp[i] = vtoc->timestamp[i]; 58287c478bd9Sstevel@tonic-gate } 58297c478bd9Sstevel@tonic-gate 58307c478bd9Sstevel@tonic-gate 58317c478bd9Sstevel@tonic-gate bcopy(vtoc->v_asciilabel, un->un_label.dkl_asciilabel, LEN_DKL_ASCII); 58327c478bd9Sstevel@tonic-gate 58337c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_IOCT, 58347c478bd9Sstevel@tonic-gate (C, "fd_build_label: asciilabel %s\n", 58357c478bd9Sstevel@tonic-gate un->un_label.dkl_asciilabel)); 58367c478bd9Sstevel@tonic-gate 58377c478bd9Sstevel@tonic-gate /* Initialize the magic number */ 58387c478bd9Sstevel@tonic-gate un->un_label.dkl_magic = DKL_MAGIC; 58397c478bd9Sstevel@tonic-gate 58407c478bd9Sstevel@tonic-gate un->un_label.dkl_pcyl = un->un_chars->fdc_ncyl; 58417c478bd9Sstevel@tonic-gate 58427c478bd9Sstevel@tonic-gate /* 58437c478bd9Sstevel@tonic-gate * The fdc_secptrack filed of the fd_char structure is the number 58447c478bd9Sstevel@tonic-gate * of sectors per track where the sectors are fdc_sec_size. The 58457c478bd9Sstevel@tonic-gate * dkl_nsect field of the dk_label structure is the number of 58467c478bd9Sstevel@tonic-gate * 512 (DEVBSIZE) byte sectors per track. 58477c478bd9Sstevel@tonic-gate */ 58487c478bd9Sstevel@tonic-gate un->un_label.dkl_nsect = (un->un_chars->fdc_secptrack * 58497c478bd9Sstevel@tonic-gate un->un_chars->fdc_sec_size) / DEV_BSIZE; 58507c478bd9Sstevel@tonic-gate 58517c478bd9Sstevel@tonic-gate 58527c478bd9Sstevel@tonic-gate un->un_label.dkl_ncyl = un->un_label.dkl_pcyl; 58537c478bd9Sstevel@tonic-gate un->un_label.dkl_nhead = un->un_chars->fdc_nhead; 58547c478bd9Sstevel@tonic-gate un->un_label.dkl_rpm = un->un_chars->fdc_medium ? 360 : 300; 58557c478bd9Sstevel@tonic-gate un->un_label.dkl_intrlv = 1; 58567c478bd9Sstevel@tonic-gate 58577c478bd9Sstevel@tonic-gate /* Create the checksum */ 58587c478bd9Sstevel@tonic-gate sum = 0; 58597c478bd9Sstevel@tonic-gate un->un_label.dkl_cksum = 0; 58607c478bd9Sstevel@tonic-gate sp = (short *)&un->un_label; 58617c478bd9Sstevel@tonic-gate i = sizeof (struct dk_label)/sizeof (short); 58627c478bd9Sstevel@tonic-gate while (i--) { 58637c478bd9Sstevel@tonic-gate sum ^= *sp++; 58647c478bd9Sstevel@tonic-gate } 58657c478bd9Sstevel@tonic-gate un->un_label.dkl_cksum = sum; 58667c478bd9Sstevel@tonic-gate 58677c478bd9Sstevel@tonic-gate return (0); 58687c478bd9Sstevel@tonic-gate } 58697c478bd9Sstevel@tonic-gate 58707c478bd9Sstevel@tonic-gate /* 58717c478bd9Sstevel@tonic-gate * Check for auxio register node 58727c478bd9Sstevel@tonic-gate */ 58737c478bd9Sstevel@tonic-gate 58747c478bd9Sstevel@tonic-gate int 58757c478bd9Sstevel@tonic-gate fd_isauxiodip(dev_info_t *dip) 58767c478bd9Sstevel@tonic-gate { 58777c478bd9Sstevel@tonic-gate if (strcmp(ddi_get_name(dip), "auxio") == 0 || 58787c478bd9Sstevel@tonic-gate strcmp(ddi_get_name(dip), "auxiliary-io") == 0) { 58797c478bd9Sstevel@tonic-gate return (1); 58807c478bd9Sstevel@tonic-gate } 58817c478bd9Sstevel@tonic-gate return (0); 58827c478bd9Sstevel@tonic-gate } 58837c478bd9Sstevel@tonic-gate 58847c478bd9Sstevel@tonic-gate /* 58857c478bd9Sstevel@tonic-gate * Search for auxio register node, then for address property 58867c478bd9Sstevel@tonic-gate */ 58877c478bd9Sstevel@tonic-gate 58887c478bd9Sstevel@tonic-gate caddr_t 58897c478bd9Sstevel@tonic-gate fd_getauxiova(dev_info_t *dip) 58907c478bd9Sstevel@tonic-gate { 58917c478bd9Sstevel@tonic-gate dev_info_t *auxdip; 58927c478bd9Sstevel@tonic-gate caddr_t addr; 58937c478bd9Sstevel@tonic-gate 58947c478bd9Sstevel@tonic-gate /* 58957c478bd9Sstevel@tonic-gate * Search sibling list, which happens to be safe inside attach 58967c478bd9Sstevel@tonic-gate */ 58977c478bd9Sstevel@tonic-gate auxdip = ddi_get_child(ddi_get_parent(dip)); 58987c478bd9Sstevel@tonic-gate while (auxdip) { 58997c478bd9Sstevel@tonic-gate if (fd_isauxiodip(auxdip)) 59007c478bd9Sstevel@tonic-gate break; 59017c478bd9Sstevel@tonic-gate auxdip = ddi_get_next_sibling(auxdip); 59027c478bd9Sstevel@tonic-gate } 59037c478bd9Sstevel@tonic-gate 59047c478bd9Sstevel@tonic-gate if (auxdip == NULL) 59057c478bd9Sstevel@tonic-gate return (NULL); 59067c478bd9Sstevel@tonic-gate 590729df58e5Spc157239 addr = (caddr_t)(uintptr_t)(caddr32_t)ddi_getprop(DDI_DEV_T_ANY, 59087c478bd9Sstevel@tonic-gate auxdip, DDI_PROP_DONTPASS, "address", 0); 59097c478bd9Sstevel@tonic-gate 59107c478bd9Sstevel@tonic-gate return (addr); 59117c478bd9Sstevel@tonic-gate } 59127c478bd9Sstevel@tonic-gate 59137c478bd9Sstevel@tonic-gate 59147c478bd9Sstevel@tonic-gate /* 59157c478bd9Sstevel@tonic-gate * set_rotational speed 59167c478bd9Sstevel@tonic-gate * 300 rpm for high and low density. 59177c478bd9Sstevel@tonic-gate * 360 rpm for medium density. 59187c478bd9Sstevel@tonic-gate * for now, we assume that 3rd density is supported only for Sun4M, 59197c478bd9Sstevel@tonic-gate * not for Clones. (else we would have to check for 82077, and do 59207c478bd9Sstevel@tonic-gate * specific things for the MEDIUM_DENSITY BIT for clones. 59217c478bd9Sstevel@tonic-gate * this code should not break CLONES. 59227c478bd9Sstevel@tonic-gate * 59237c478bd9Sstevel@tonic-gate * REMARK: there is a SOny requirement, to deselect the drive then 59247c478bd9Sstevel@tonic-gate * select it again after the medium density change, since the 59257c478bd9Sstevel@tonic-gate * leading edge of the select line latches the rotational Speed. 59267c478bd9Sstevel@tonic-gate * then after that, we have to wait 500 ms for the rotation to 59277c478bd9Sstevel@tonic-gate * stabilize. 59287c478bd9Sstevel@tonic-gate * 59297c478bd9Sstevel@tonic-gate */ 59307c478bd9Sstevel@tonic-gate static void 59317c478bd9Sstevel@tonic-gate set_rotational_speed(struct fdctlr *fdc, int unit) 59327c478bd9Sstevel@tonic-gate { 59337c478bd9Sstevel@tonic-gate int check; 59347c478bd9Sstevel@tonic-gate int is_medium; 59357c478bd9Sstevel@tonic-gate 59367c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 59377c478bd9Sstevel@tonic-gate 59387c478bd9Sstevel@tonic-gate /* 59397c478bd9Sstevel@tonic-gate * if we do not have a Sun4m, medium density is not supported. 59407c478bd9Sstevel@tonic-gate */ 59417c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_MACHIO) 59427c478bd9Sstevel@tonic-gate return; 59437c478bd9Sstevel@tonic-gate 59447c478bd9Sstevel@tonic-gate /* 59457c478bd9Sstevel@tonic-gate * if FDUNIT_SET_SPEED is set, set the speed. 59467c478bd9Sstevel@tonic-gate * else, 59477c478bd9Sstevel@tonic-gate * if there is a change, do it, if not leave it alone. 59487c478bd9Sstevel@tonic-gate * there is a change if un->un_chars->fdc_medium does not match 59497c478bd9Sstevel@tonic-gate * un->un_flags & FDUNIT_MEDIUM 59507c478bd9Sstevel@tonic-gate * un->un_flags & FDUNIT_MEDIUM specifies the last setting. 59517c478bd9Sstevel@tonic-gate * un->un_chars->fdc_medium specifies next setting. 59527c478bd9Sstevel@tonic-gate * if there is a change, wait 500ms according to Sony spec. 59537c478bd9Sstevel@tonic-gate */ 59547c478bd9Sstevel@tonic-gate 59557c478bd9Sstevel@tonic-gate is_medium = fdc->c_un->un_chars->fdc_medium; 59567c478bd9Sstevel@tonic-gate 59577c478bd9Sstevel@tonic-gate if (fdc->c_un->un_flags & FDUNIT_SET_SPEED) { 59587c478bd9Sstevel@tonic-gate check = 1; 59597c478bd9Sstevel@tonic-gate } else { 59607c478bd9Sstevel@tonic-gate check = is_medium ^ 59617c478bd9Sstevel@tonic-gate ((fdc->c_un->un_flags & FDUNIT_MEDIUM) ? 1 : 0); 59627c478bd9Sstevel@tonic-gate 59637c478bd9Sstevel@tonic-gate /* Set the un_flags if necessary */ 59647c478bd9Sstevel@tonic-gate 59657c478bd9Sstevel@tonic-gate if (check) 59667c478bd9Sstevel@tonic-gate fdc->c_un->un_flags ^= FDUNIT_MEDIUM; 59677c478bd9Sstevel@tonic-gate } 59687c478bd9Sstevel@tonic-gate 59697c478bd9Sstevel@tonic-gate fdc->c_un->un_flags &= ~FDUNIT_SET_SPEED; 59707c478bd9Sstevel@tonic-gate 59717c478bd9Sstevel@tonic-gate 59727c478bd9Sstevel@tonic-gate if (check) { 59737c478bd9Sstevel@tonic-gate 59747c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 0); 59757c478bd9Sstevel@tonic-gate drv_usecwait(5); 59767c478bd9Sstevel@tonic-gate 59777c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_SLAVIO) { 59787c478bd9Sstevel@tonic-gate Set_dor(fdc, MEDIUM_DENSITY, is_medium); 59797c478bd9Sstevel@tonic-gate } 59807c478bd9Sstevel@tonic-gate 59817c478bd9Sstevel@tonic-gate if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_CHEERIO) { 59827c478bd9Sstevel@tonic-gate if (is_medium) { 59837c478bd9Sstevel@tonic-gate Set_auxio(fdc, AUX_MEDIUM_DENSITY); 59847c478bd9Sstevel@tonic-gate } else { 59857c478bd9Sstevel@tonic-gate Set_auxio(fdc, AUX_HIGH_DENSITY); 59867c478bd9Sstevel@tonic-gate } 59877c478bd9Sstevel@tonic-gate 59887c478bd9Sstevel@tonic-gate } 59897c478bd9Sstevel@tonic-gate 59907c478bd9Sstevel@tonic-gate if (is_medium) { 59917c478bd9Sstevel@tonic-gate drv_usecwait(5); 59927c478bd9Sstevel@tonic-gate } 59937c478bd9Sstevel@tonic-gate 59947c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 1); /* Sony requirement */ 59957c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "rotation:medium\n")); 59967c478bd9Sstevel@tonic-gate drv_usecwait(500000); 59977c478bd9Sstevel@tonic-gate } 59987c478bd9Sstevel@tonic-gate } 59997c478bd9Sstevel@tonic-gate 60007c478bd9Sstevel@tonic-gate static void 60017c478bd9Sstevel@tonic-gate fd_media_watch(void *arg) 60027c478bd9Sstevel@tonic-gate { 60037c478bd9Sstevel@tonic-gate dev_t dev; 60047c478bd9Sstevel@tonic-gate struct fdunit *un; 60057c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 60067c478bd9Sstevel@tonic-gate int unit; 60077c478bd9Sstevel@tonic-gate 60087c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 60097c478bd9Sstevel@tonic-gate fdc = fd_getctlr(dev); 60107c478bd9Sstevel@tonic-gate unit = fdc->c_un->un_unit_no; 60117c478bd9Sstevel@tonic-gate un = fdc->c_un; 60127c478bd9Sstevel@tonic-gate 60137c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 60147c478bd9Sstevel@tonic-gate 60157c478bd9Sstevel@tonic-gate if (un->un_media_timeout_id == 0) { 60167c478bd9Sstevel@tonic-gate /* 60177c478bd9Sstevel@tonic-gate * Untimeout is about to be called. 60187c478bd9Sstevel@tonic-gate * Don't call fd_get_media_state again 60197c478bd9Sstevel@tonic-gate */ 60207c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 60217c478bd9Sstevel@tonic-gate return; 60227c478bd9Sstevel@tonic-gate } 60237c478bd9Sstevel@tonic-gate 60247c478bd9Sstevel@tonic-gate 60257c478bd9Sstevel@tonic-gate un->un_media_state = fd_get_media_state(fdc, unit); 60267c478bd9Sstevel@tonic-gate cv_broadcast(&fdc->c_statecv); 60277c478bd9Sstevel@tonic-gate 60287c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 60297c478bd9Sstevel@tonic-gate 60307c478bd9Sstevel@tonic-gate if (un->un_media_timeout) { 60317c478bd9Sstevel@tonic-gate un->un_media_timeout_id = timeout(fd_media_watch, 60327c478bd9Sstevel@tonic-gate (void *)(ulong_t)dev, un->un_media_timeout); 60337c478bd9Sstevel@tonic-gate } 60347c478bd9Sstevel@tonic-gate } 60357c478bd9Sstevel@tonic-gate 60367c478bd9Sstevel@tonic-gate enum dkio_state 60377c478bd9Sstevel@tonic-gate fd_get_media_state(struct fdctlr *fdc, int unit) 60387c478bd9Sstevel@tonic-gate { 60397c478bd9Sstevel@tonic-gate enum dkio_state state; 60407c478bd9Sstevel@tonic-gate 60417c478bd9Sstevel@tonic-gate ASSERT(fdc->c_un->un_unit_no == unit); 60427c478bd9Sstevel@tonic-gate 60437c478bd9Sstevel@tonic-gate if (fdsense_chng(fdc, unit)) { 60447c478bd9Sstevel@tonic-gate /* check disk only if DSKCHG "high" */ 60457c478bd9Sstevel@tonic-gate if (fdcheckdisk(fdc, unit)) { 60467c478bd9Sstevel@tonic-gate state = DKIO_EJECTED; 60477c478bd9Sstevel@tonic-gate } else { 60487c478bd9Sstevel@tonic-gate state = DKIO_INSERTED; 60497c478bd9Sstevel@tonic-gate } 60507c478bd9Sstevel@tonic-gate } else { 60517c478bd9Sstevel@tonic-gate state = DKIO_INSERTED; 60527c478bd9Sstevel@tonic-gate } 60537c478bd9Sstevel@tonic-gate return (state); 60547c478bd9Sstevel@tonic-gate } 60557c478bd9Sstevel@tonic-gate 60567c478bd9Sstevel@tonic-gate static int 60577c478bd9Sstevel@tonic-gate fd_check_media(dev_t dev, enum dkio_state state) 60587c478bd9Sstevel@tonic-gate { 60597c478bd9Sstevel@tonic-gate struct fdunit *un; 60607c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 60617c478bd9Sstevel@tonic-gate int unit; 60627c478bd9Sstevel@tonic-gate 60637c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: start\n")); 60647c478bd9Sstevel@tonic-gate 60657c478bd9Sstevel@tonic-gate fdc = fd_getctlr(dev); 60667c478bd9Sstevel@tonic-gate unit = fdc->c_un->un_unit_no; 60677c478bd9Sstevel@tonic-gate un = fdc->c_un; 60687c478bd9Sstevel@tonic-gate 60697c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 60707c478bd9Sstevel@tonic-gate 60717c478bd9Sstevel@tonic-gate CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc); 60727c478bd9Sstevel@tonic-gate 60737c478bd9Sstevel@tonic-gate if (fdc->c_un->un_state == FD_STATE_STOPPED) { 60747c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 60757c478bd9Sstevel@tonic-gate if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON)) 60767c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 60777c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \ 60787c478bd9Sstevel@tonic-gate failed. \n")); 60797c478bd9Sstevel@tonic-gate 60807c478bd9Sstevel@tonic-gate (void) pm_idle_component(fdc->c_dip, 0); 60817c478bd9Sstevel@tonic-gate return (EIO); 60827c478bd9Sstevel@tonic-gate } 60837c478bd9Sstevel@tonic-gate 60847c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 60857c478bd9Sstevel@tonic-gate } 60867c478bd9Sstevel@tonic-gate 60877c478bd9Sstevel@tonic-gate un->un_media_state = fd_get_media_state(fdc, unit); 60887c478bd9Sstevel@tonic-gate 60897c478bd9Sstevel@tonic-gate /* turn on timeout */ 60907c478bd9Sstevel@tonic-gate un->un_media_timeout = drv_usectohz(fd_check_media_time); 60917c478bd9Sstevel@tonic-gate un->un_media_timeout_id = timeout(fd_media_watch, 60927c478bd9Sstevel@tonic-gate (void *)(ulong_t)dev, un->un_media_timeout); 60937c478bd9Sstevel@tonic-gate 60947c478bd9Sstevel@tonic-gate while (un->un_media_state == state) { 60957c478bd9Sstevel@tonic-gate if (cv_wait_sig(&fdc->c_statecv, &fdc->c_lolock) == 0) { 60967c478bd9Sstevel@tonic-gate un->un_media_timeout = 0; 60977c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 60987c478bd9Sstevel@tonic-gate return (EINTR); 60997c478bd9Sstevel@tonic-gate } 61007c478bd9Sstevel@tonic-gate } 61017c478bd9Sstevel@tonic-gate 61027c478bd9Sstevel@tonic-gate if (un->un_media_timeout_id) { 61037c478bd9Sstevel@tonic-gate timeout_id_t timeid = un->un_media_timeout_id; 61047c478bd9Sstevel@tonic-gate un->un_media_timeout_id = 0; 61057c478bd9Sstevel@tonic-gate 61067c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 61077c478bd9Sstevel@tonic-gate (void) untimeout(timeid); 61087c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 61097c478bd9Sstevel@tonic-gate } 61107c478bd9Sstevel@tonic-gate 61117c478bd9Sstevel@tonic-gate if (un->un_media_state == DKIO_INSERTED) { 61127c478bd9Sstevel@tonic-gate if (fdgetlabel(fdc, unit)) { 61137c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 61147c478bd9Sstevel@tonic-gate return (EIO); 61157c478bd9Sstevel@tonic-gate } 61167c478bd9Sstevel@tonic-gate } 61177c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 61187c478bd9Sstevel@tonic-gate 61197c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: end\n")); 61207c478bd9Sstevel@tonic-gate return (0); 61217c478bd9Sstevel@tonic-gate } 61227c478bd9Sstevel@tonic-gate 61237c478bd9Sstevel@tonic-gate /* 61247c478bd9Sstevel@tonic-gate * fd_get_media_info : 61257c478bd9Sstevel@tonic-gate * Collects medium information for 61267c478bd9Sstevel@tonic-gate * DKIOCGMEDIAINFO ioctl. 61277c478bd9Sstevel@tonic-gate */ 61287c478bd9Sstevel@tonic-gate 61297c478bd9Sstevel@tonic-gate static int 61307c478bd9Sstevel@tonic-gate fd_get_media_info(struct fdunit *un, caddr_t buf, int flag) 61317c478bd9Sstevel@tonic-gate { 61327c478bd9Sstevel@tonic-gate struct dk_minfo media_info; 61337c478bd9Sstevel@tonic-gate int err = 0; 61347c478bd9Sstevel@tonic-gate 61357c478bd9Sstevel@tonic-gate media_info.dki_media_type = DK_FLOPPY; 61367c478bd9Sstevel@tonic-gate media_info.dki_lbsize = un->un_chars->fdc_sec_size; 61377c478bd9Sstevel@tonic-gate media_info.dki_capacity = un->un_chars->fdc_ncyl * 61387c478bd9Sstevel@tonic-gate un->un_chars->fdc_secptrack * un->un_chars->fdc_nhead; 61397c478bd9Sstevel@tonic-gate 61407c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&media_info, buf, 61417c478bd9Sstevel@tonic-gate sizeof (struct dk_minfo), flag)) 61427c478bd9Sstevel@tonic-gate err = EFAULT; 61437c478bd9Sstevel@tonic-gate return (err); 61447c478bd9Sstevel@tonic-gate } 61457c478bd9Sstevel@tonic-gate 61467c478bd9Sstevel@tonic-gate /* 61477c478bd9Sstevel@tonic-gate * fd_power : 61487c478bd9Sstevel@tonic-gate * Power entry point of fd driver. 61497c478bd9Sstevel@tonic-gate */ 61507c478bd9Sstevel@tonic-gate 61517c478bd9Sstevel@tonic-gate static int 61527c478bd9Sstevel@tonic-gate fd_power(dev_info_t *dip, int component, int level) 61537c478bd9Sstevel@tonic-gate { 61547c478bd9Sstevel@tonic-gate 61557c478bd9Sstevel@tonic-gate struct fdctlr *fdc; 61567c478bd9Sstevel@tonic-gate int instance; 61577c478bd9Sstevel@tonic-gate int rval; 61587c478bd9Sstevel@tonic-gate 61597c478bd9Sstevel@tonic-gate if ((level < PM_LEVEL_OFF) || (level > PM_LEVEL_ON) || 61607c478bd9Sstevel@tonic-gate (component != 0)) { 61617c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 61627c478bd9Sstevel@tonic-gate } 61637c478bd9Sstevel@tonic-gate 61647c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 61657c478bd9Sstevel@tonic-gate fdc = fd_getctlr(instance << FDINSTSHIFT); 61667c478bd9Sstevel@tonic-gate if (fdc->c_un == NULL) 61677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 61687c478bd9Sstevel@tonic-gate 61697c478bd9Sstevel@tonic-gate if (level == PM_LEVEL_OFF) { 61707c478bd9Sstevel@tonic-gate rval = fd_pm_lower_power(fdc); 61717c478bd9Sstevel@tonic-gate } 61727c478bd9Sstevel@tonic-gate if (level == PM_LEVEL_ON) { 61737c478bd9Sstevel@tonic-gate rval = fd_pm_raise_power(fdc); 61747c478bd9Sstevel@tonic-gate } 61757c478bd9Sstevel@tonic-gate return (rval); 61767c478bd9Sstevel@tonic-gate } 61777c478bd9Sstevel@tonic-gate 61787c478bd9Sstevel@tonic-gate /* 61797c478bd9Sstevel@tonic-gate * fd_pm_lower_power : 61807c478bd9Sstevel@tonic-gate * This function is called only during pm suspend. At this point, 61817c478bd9Sstevel@tonic-gate * the power management framework thinks the device is idle for 61827c478bd9Sstevel@tonic-gate * long enough to go to a low power mode. If the device is busy, 61837c478bd9Sstevel@tonic-gate * then this function returns DDI_FAILURE. 61847c478bd9Sstevel@tonic-gate */ 61857c478bd9Sstevel@tonic-gate 61867c478bd9Sstevel@tonic-gate static int 61877c478bd9Sstevel@tonic-gate fd_pm_lower_power(struct fdctlr *fdc) 61887c478bd9Sstevel@tonic-gate { 61897c478bd9Sstevel@tonic-gate 61907c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 61917c478bd9Sstevel@tonic-gate 61927c478bd9Sstevel@tonic-gate if ((fdc->c_un->un_state == FD_STATE_SUSPENDED) || 61937c478bd9Sstevel@tonic-gate (fdc->c_un->un_state == FD_STATE_STOPPED)) { 61947c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 61957c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 61967c478bd9Sstevel@tonic-gate } 61977c478bd9Sstevel@tonic-gate 61987c478bd9Sstevel@tonic-gate 61997c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_lower_power called\n")); 62007c478bd9Sstevel@tonic-gate 62017c478bd9Sstevel@tonic-gate /* if the device is busy then we fail the lower power request */ 62027c478bd9Sstevel@tonic-gate if (fdc->c_flags & FDCFLG_BUSY) { 62037c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_PWR, (C, "fd_pm_lower_power : \ 62047c478bd9Sstevel@tonic-gate controller is busy.\n")); 62057c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 62067c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 62077c478bd9Sstevel@tonic-gate } 62087c478bd9Sstevel@tonic-gate 62097c478bd9Sstevel@tonic-gate fdc->c_un->un_state = FD_STATE_STOPPED; 62107c478bd9Sstevel@tonic-gate 62117c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 62127c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 62137c478bd9Sstevel@tonic-gate } 62147c478bd9Sstevel@tonic-gate 62157c478bd9Sstevel@tonic-gate /* 62167c478bd9Sstevel@tonic-gate * fd_pm_raise_power : 62177c478bd9Sstevel@tonic-gate * This function performs the necessary steps for resuming a 62187c478bd9Sstevel@tonic-gate * device, either from pm suspend or CPR. Here the controller 62197c478bd9Sstevel@tonic-gate * is reset, initialized and the state is set to FD_STATE_NORMAL. 62207c478bd9Sstevel@tonic-gate */ 62217c478bd9Sstevel@tonic-gate 62227c478bd9Sstevel@tonic-gate static int 62237c478bd9Sstevel@tonic-gate fd_pm_raise_power(struct fdctlr *fdc) 62247c478bd9Sstevel@tonic-gate { 62257c478bd9Sstevel@tonic-gate 62267c478bd9Sstevel@tonic-gate struct fdunit *un = fdc->c_un; 62277c478bd9Sstevel@tonic-gate int unit; 62287c478bd9Sstevel@tonic-gate 62297c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_raise_power called\n")); 62307c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_lolock); 62317c478bd9Sstevel@tonic-gate fdgetcsb(fdc); 62327c478bd9Sstevel@tonic-gate 62337c478bd9Sstevel@tonic-gate /* Reset the dma engine */ 62347c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_DMA) { 62357c478bd9Sstevel@tonic-gate mutex_enter(&fdc->c_hilock); 62367c478bd9Sstevel@tonic-gate reset_dma_controller(fdc); 62377c478bd9Sstevel@tonic-gate set_dma_control_register(fdc, DCSR_INIT_BITS); 62387c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_hilock); 62397c478bd9Sstevel@tonic-gate } 62407c478bd9Sstevel@tonic-gate 62417c478bd9Sstevel@tonic-gate /* 62427c478bd9Sstevel@tonic-gate * Force a rotational speed set in the next 62437c478bd9Sstevel@tonic-gate * call to set_rotational_speed(). 62447c478bd9Sstevel@tonic-gate */ 62457c478bd9Sstevel@tonic-gate 62467c478bd9Sstevel@tonic-gate fdc->c_un->un_flags |= FDUNIT_SET_SPEED; 62477c478bd9Sstevel@tonic-gate 62487c478bd9Sstevel@tonic-gate /* Reset and configure the controller */ 62497c478bd9Sstevel@tonic-gate (void) fdreset(fdc); 62507c478bd9Sstevel@tonic-gate 62517c478bd9Sstevel@tonic-gate unit = fdc->c_un->un_unit_no; 62527c478bd9Sstevel@tonic-gate 62537c478bd9Sstevel@tonic-gate /* Recalibrate the drive */ 62547c478bd9Sstevel@tonic-gate if (fdrecalseek(fdc, unit, -1, 0) != 0) { 62557c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "raise_power : recalibrate \ 62567c478bd9Sstevel@tonic-gate failed\n")); 62577c478bd9Sstevel@tonic-gate fdretcsb(fdc); 62587c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 62597c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 62607c478bd9Sstevel@tonic-gate } 62617c478bd9Sstevel@tonic-gate 62627c478bd9Sstevel@tonic-gate /* Select the drive through the AUXIO registers */ 62637c478bd9Sstevel@tonic-gate fdselect(fdc, unit, 0); 62647c478bd9Sstevel@tonic-gate un->un_state = FD_STATE_NORMAL; 62657c478bd9Sstevel@tonic-gate fdretcsb(fdc); 62667c478bd9Sstevel@tonic-gate mutex_exit(&fdc->c_lolock); 62677c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 62687c478bd9Sstevel@tonic-gate } 62697c478bd9Sstevel@tonic-gate 62707c478bd9Sstevel@tonic-gate /* 62717c478bd9Sstevel@tonic-gate * create_pm_components : 62727c478bd9Sstevel@tonic-gate * creates the power management components for auto pm framework. 62737c478bd9Sstevel@tonic-gate */ 62747c478bd9Sstevel@tonic-gate 62757c478bd9Sstevel@tonic-gate static void 62767c478bd9Sstevel@tonic-gate create_pm_components(dev_info_t *dip) 62777c478bd9Sstevel@tonic-gate { 62787c478bd9Sstevel@tonic-gate char *un_pm_comp[] = { "NAME=spindle-motor", "0=off", "1=on"}; 62797c478bd9Sstevel@tonic-gate 62807c478bd9Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 62817c478bd9Sstevel@tonic-gate "pm-components", un_pm_comp, 3) == DDI_PROP_SUCCESS) { 62827c478bd9Sstevel@tonic-gate 62837c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, PM_LEVEL_ON); 62847c478bd9Sstevel@tonic-gate } 62857c478bd9Sstevel@tonic-gate } 62867c478bd9Sstevel@tonic-gate 62877c478bd9Sstevel@tonic-gate /* 62887c478bd9Sstevel@tonic-gate * set_data_count_register(struct fdctlr *fdc, uint32_t count) 62897c478bd9Sstevel@tonic-gate * Set the data count in appropriate dma register. 62907c478bd9Sstevel@tonic-gate */ 62917c478bd9Sstevel@tonic-gate 62927c478bd9Sstevel@tonic-gate static void 62937c478bd9Sstevel@tonic-gate set_data_count_register(struct fdctlr *fdc, uint32_t count) 62947c478bd9Sstevel@tonic-gate { 62957c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 62967c478bd9Sstevel@tonic-gate struct cheerio_dma_reg *dma_reg; 62977c478bd9Sstevel@tonic-gate dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs; 62987c478bd9Sstevel@tonic-gate ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr, count); 62997c478bd9Sstevel@tonic-gate } else if (fdc->c_fdtype & FDCTYPE_SB) { 63007c478bd9Sstevel@tonic-gate struct sb_dma_reg *dma_reg; 63017c478bd9Sstevel@tonic-gate count = count - 1; /* 8237 needs it */ 63027c478bd9Sstevel@tonic-gate dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs; 63037c478bd9Sstevel@tonic-gate switch (fdc->sb_dma_channel) { 63047c478bd9Sstevel@tonic-gate case 0 : 63057c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 63067c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT], 63077c478bd9Sstevel@tonic-gate count & 0xFFFF); 63087c478bd9Sstevel@tonic-gate break; 63097c478bd9Sstevel@tonic-gate case 1 : 63107c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 63117c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT], 63127c478bd9Sstevel@tonic-gate count & 0xFFFF); 63137c478bd9Sstevel@tonic-gate break; 63147c478bd9Sstevel@tonic-gate case 2 : 63157c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 63167c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT], 63177c478bd9Sstevel@tonic-gate count & 0xFFFF); 63187c478bd9Sstevel@tonic-gate break; 63197c478bd9Sstevel@tonic-gate case 3 : 63207c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 63217c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT], 63227c478bd9Sstevel@tonic-gate count & 0xFFFF); 63237c478bd9Sstevel@tonic-gate break; 63247c478bd9Sstevel@tonic-gate default : 63257c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_SDMA, 63267c478bd9Sstevel@tonic-gate (C, "set_data_count: wrong channel %x\n", 63277c478bd9Sstevel@tonic-gate fdc->sb_dma_channel)); 63287c478bd9Sstevel@tonic-gate break; 63297c478bd9Sstevel@tonic-gate } 63307c478bd9Sstevel@tonic-gate } 63317c478bd9Sstevel@tonic-gate } 63327c478bd9Sstevel@tonic-gate 63337c478bd9Sstevel@tonic-gate /* 63347c478bd9Sstevel@tonic-gate * get_data_count_register(struct fdctlr *fdc) 63357c478bd9Sstevel@tonic-gate * Read the data count from appropriate dma register. 63367c478bd9Sstevel@tonic-gate */ 63377c478bd9Sstevel@tonic-gate 63387c478bd9Sstevel@tonic-gate static uint32_t 63397c478bd9Sstevel@tonic-gate get_data_count_register(struct fdctlr *fdc) 63407c478bd9Sstevel@tonic-gate { 63417c478bd9Sstevel@tonic-gate uint32_t retval = 0; 63427c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 63437c478bd9Sstevel@tonic-gate struct cheerio_dma_reg *dma_reg; 63447c478bd9Sstevel@tonic-gate dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs; 63457c478bd9Sstevel@tonic-gate retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr); 63467c478bd9Sstevel@tonic-gate } else if (fdc->c_fdtype & FDCTYPE_SB) { 63477c478bd9Sstevel@tonic-gate struct sb_dma_reg *dma_reg; 63487c478bd9Sstevel@tonic-gate dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs; 63497c478bd9Sstevel@tonic-gate switch (fdc->sb_dma_channel) { 63507c478bd9Sstevel@tonic-gate case 0 : 63517c478bd9Sstevel@tonic-gate retval = ddi_get16(fdc->c_handlep_dma, 63527c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT]); 63537c478bd9Sstevel@tonic-gate break; 63547c478bd9Sstevel@tonic-gate case 1 : 63557c478bd9Sstevel@tonic-gate retval = ddi_get16(fdc->c_handlep_dma, 63567c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT]); 63577c478bd9Sstevel@tonic-gate break; 63587c478bd9Sstevel@tonic-gate case 2 : 63597c478bd9Sstevel@tonic-gate retval = ddi_get16(fdc->c_handlep_dma, 63607c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT]); 63617c478bd9Sstevel@tonic-gate break; 63627c478bd9Sstevel@tonic-gate case 3 : 63637c478bd9Sstevel@tonic-gate retval = ddi_get16(fdc->c_handlep_dma, 63647c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT]); 63657c478bd9Sstevel@tonic-gate break; 63667c478bd9Sstevel@tonic-gate default : 63677c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_SDMA, 63687c478bd9Sstevel@tonic-gate (C, "get_data_count: wrong channel %x\n", 63697c478bd9Sstevel@tonic-gate fdc->sb_dma_channel)); 63707c478bd9Sstevel@tonic-gate break; 63717c478bd9Sstevel@tonic-gate } 63727c478bd9Sstevel@tonic-gate retval = (uint32_t)((uint16_t)(retval +1)); 63737c478bd9Sstevel@tonic-gate } 63747c478bd9Sstevel@tonic-gate 63757c478bd9Sstevel@tonic-gate return (retval); 63767c478bd9Sstevel@tonic-gate 63777c478bd9Sstevel@tonic-gate } 63787c478bd9Sstevel@tonic-gate 63797c478bd9Sstevel@tonic-gate /* 63807c478bd9Sstevel@tonic-gate * reset_dma_controller(struct fdctlr *fdc) 63817c478bd9Sstevel@tonic-gate * Reset and initialize the dma controller. 63827c478bd9Sstevel@tonic-gate */ 63837c478bd9Sstevel@tonic-gate 63847c478bd9Sstevel@tonic-gate static void 63857c478bd9Sstevel@tonic-gate reset_dma_controller(struct fdctlr *fdc) 63867c478bd9Sstevel@tonic-gate { 63877c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 63887c478bd9Sstevel@tonic-gate struct cheerio_dma_reg *dma_reg; 63897c478bd9Sstevel@tonic-gate dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs; 63907c478bd9Sstevel@tonic-gate ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, DCSR_RESET); 639119397407SSherry Moore while (get_dma_control_register(fdc) & DCSR_CYC_PEND) 639219397407SSherry Moore ; 63937c478bd9Sstevel@tonic-gate ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, 0); 63947c478bd9Sstevel@tonic-gate } else if (fdc->c_fdtype & FDCTYPE_SB) { 63957c478bd9Sstevel@tonic-gate struct sb_dma_reg *dma_reg; 63967c478bd9Sstevel@tonic-gate dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs; 63977c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MASK], 63987c478bd9Sstevel@tonic-gate (fdc->sb_dma_channel & 0x3)); 63997c478bd9Sstevel@tonic-gate 64007c478bd9Sstevel@tonic-gate } 64017c478bd9Sstevel@tonic-gate } 64027c478bd9Sstevel@tonic-gate 64037c478bd9Sstevel@tonic-gate /* 64047c478bd9Sstevel@tonic-gate * Get the DMA control register for CHEERIO. 64057c478bd9Sstevel@tonic-gate * For SouthBridge 8237 DMA controller, this register is not valid. 64067c478bd9Sstevel@tonic-gate * So, just return 0. 64077c478bd9Sstevel@tonic-gate */ 64087c478bd9Sstevel@tonic-gate static uint32_t 64097c478bd9Sstevel@tonic-gate get_dma_control_register(struct fdctlr *fdc) 64107c478bd9Sstevel@tonic-gate { 64117c478bd9Sstevel@tonic-gate uint32_t retval = 0; 64127c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 64137c478bd9Sstevel@tonic-gate struct cheerio_dma_reg *dma_reg; 64147c478bd9Sstevel@tonic-gate dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs; 64157c478bd9Sstevel@tonic-gate retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr); 64167c478bd9Sstevel@tonic-gate } 64177c478bd9Sstevel@tonic-gate 64187c478bd9Sstevel@tonic-gate return (retval); 64197c478bd9Sstevel@tonic-gate } 64207c478bd9Sstevel@tonic-gate 64217c478bd9Sstevel@tonic-gate 64227c478bd9Sstevel@tonic-gate /* 64237c478bd9Sstevel@tonic-gate * set_data_address_register(struct fdctlr *fdc) 64247c478bd9Sstevel@tonic-gate * Set the data address in appropriate dma register. 64257c478bd9Sstevel@tonic-gate */ 64267c478bd9Sstevel@tonic-gate static void 64277c478bd9Sstevel@tonic-gate set_data_address_register(struct fdctlr *fdc, uint32_t address) 64287c478bd9Sstevel@tonic-gate { 64297c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 64307c478bd9Sstevel@tonic-gate struct cheerio_dma_reg *dma_reg; 64317c478bd9Sstevel@tonic-gate dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs; 64327c478bd9Sstevel@tonic-gate ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dacr, address); 64337c478bd9Sstevel@tonic-gate } else if (fdc->c_fdtype & FDCTYPE_SB) { 64347c478bd9Sstevel@tonic-gate struct sb_dma_reg *dma_reg; 64357c478bd9Sstevel@tonic-gate dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs; 64367c478bd9Sstevel@tonic-gate switch (fdc->sb_dma_channel) { 64377c478bd9Sstevel@tonic-gate case 0 : 64387c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64397c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_0PAGE], 64407c478bd9Sstevel@tonic-gate (address & 0xFF0000) >>16); 64417c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64427c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_0HPG], 64437c478bd9Sstevel@tonic-gate (address & 0xFF000000) >>24); 64447c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 64457c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_0ADR], 64467c478bd9Sstevel@tonic-gate address & 0xFFFF); 64477c478bd9Sstevel@tonic-gate break; 64487c478bd9Sstevel@tonic-gate case 1 : 64497c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64507c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_1PAGE], 64517c478bd9Sstevel@tonic-gate (address & 0xFF0000) >>16); 64527c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64537c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_1HPG], 64547c478bd9Sstevel@tonic-gate (address & 0xFF000000) >>24); 64557c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 64567c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_1ADR], 64577c478bd9Sstevel@tonic-gate address & 0xFFFF); 64587c478bd9Sstevel@tonic-gate break; 64597c478bd9Sstevel@tonic-gate case 2 : 64607c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64617c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_2PAGE], 64627c478bd9Sstevel@tonic-gate (address & 0xFF0000) >>16); 64637c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64647c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_2HPG], 64657c478bd9Sstevel@tonic-gate (address & 0xFF000000) >>24); 64667c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 64677c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_2ADR], 64687c478bd9Sstevel@tonic-gate address & 0xFFFF); 64697c478bd9Sstevel@tonic-gate break; 64707c478bd9Sstevel@tonic-gate case 3 : 64717c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64727c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_3PAGE], 64737c478bd9Sstevel@tonic-gate (address & 0xFF0000) >>16); 64747c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 64757c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMA_3HPG], 64767c478bd9Sstevel@tonic-gate (address & 0xFF000000) >>24); 64777c478bd9Sstevel@tonic-gate ddi_put16(fdc->c_handlep_dma, 64787c478bd9Sstevel@tonic-gate (ushort_t *)&dma_reg->sb_dma_regs[DMA_3ADR], 64797c478bd9Sstevel@tonic-gate address & 0xFFFF); 64807c478bd9Sstevel@tonic-gate break; 64817c478bd9Sstevel@tonic-gate default : 64827c478bd9Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_SDMA, 64837c478bd9Sstevel@tonic-gate (C, "set_data_address: wrong channel %x\n", 64847c478bd9Sstevel@tonic-gate fdc->sb_dma_channel)); 64857c478bd9Sstevel@tonic-gate break; 64867c478bd9Sstevel@tonic-gate } 64877c478bd9Sstevel@tonic-gate } 64887c478bd9Sstevel@tonic-gate 64897c478bd9Sstevel@tonic-gate } 64907c478bd9Sstevel@tonic-gate 64917c478bd9Sstevel@tonic-gate 64927c478bd9Sstevel@tonic-gate /* 64937c478bd9Sstevel@tonic-gate * set_dma_mode(struct fdctlr *fdc, int val) 64947c478bd9Sstevel@tonic-gate * Set the appropriate dma direction and registers. 64957c478bd9Sstevel@tonic-gate */ 64967c478bd9Sstevel@tonic-gate static void 64977c478bd9Sstevel@tonic-gate set_dma_mode(struct fdctlr *fdc, int val) 64987c478bd9Sstevel@tonic-gate { 64997c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 65007c478bd9Sstevel@tonic-gate struct cheerio_dma_reg *dma_reg; 65017c478bd9Sstevel@tonic-gate dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs; 65027c478bd9Sstevel@tonic-gate if (val == CSB_READ) 65037c478bd9Sstevel@tonic-gate ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, 65047c478bd9Sstevel@tonic-gate DCSR_INIT_BITS|DCSR_WRITE); 65057c478bd9Sstevel@tonic-gate else 65067c478bd9Sstevel@tonic-gate ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, 65077c478bd9Sstevel@tonic-gate DCSR_INIT_BITS); 65087c478bd9Sstevel@tonic-gate 65097c478bd9Sstevel@tonic-gate } else if (fdc->c_fdtype & FDCTYPE_SB) { 65107c478bd9Sstevel@tonic-gate uint8_t mode_reg_val, chn_mask; 65117c478bd9Sstevel@tonic-gate struct sb_dma_reg *dma_reg; 65127c478bd9Sstevel@tonic-gate dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs; 65137c478bd9Sstevel@tonic-gate 65147c478bd9Sstevel@tonic-gate if (val == CSB_READ) { 65157c478bd9Sstevel@tonic-gate mode_reg_val = fdc->sb_dma_channel | DMAMODE_READ 65167c478bd9Sstevel@tonic-gate | DMAMODE_SINGLE; 65177c478bd9Sstevel@tonic-gate } else { /* Read operation */ 65187c478bd9Sstevel@tonic-gate mode_reg_val = fdc->sb_dma_channel | DMAMODE_WRITE 65197c478bd9Sstevel@tonic-gate | DMAMODE_SINGLE; 65207c478bd9Sstevel@tonic-gate } 65217c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MODE], 65227c478bd9Sstevel@tonic-gate mode_reg_val); 65237c478bd9Sstevel@tonic-gate chn_mask = 1 << (fdc->sb_dma_channel & 0x3); 65247c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 65257c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMAC1_ALLMASK], ~chn_mask); 65267c478bd9Sstevel@tonic-gate fdc->sb_dma_lock = 1; 65277c478bd9Sstevel@tonic-gate } 65287c478bd9Sstevel@tonic-gate } 65297c478bd9Sstevel@tonic-gate 65307c478bd9Sstevel@tonic-gate /* 65317c478bd9Sstevel@tonic-gate * This function is valid only for CHEERIO/RIO based 65327c478bd9Sstevel@tonic-gate * controllers. The control register for the dma channel 65337c478bd9Sstevel@tonic-gate * is initialized by this function. 65347c478bd9Sstevel@tonic-gate */ 65357c478bd9Sstevel@tonic-gate 65367c478bd9Sstevel@tonic-gate static void 65377c478bd9Sstevel@tonic-gate set_dma_control_register(struct fdctlr *fdc, uint32_t val) 65387c478bd9Sstevel@tonic-gate { 65397c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_CHEERIO) { 65407c478bd9Sstevel@tonic-gate struct cheerio_dma_reg *dma_reg; 65417c478bd9Sstevel@tonic-gate dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs; 65427c478bd9Sstevel@tonic-gate ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, val); 65437c478bd9Sstevel@tonic-gate } 65447c478bd9Sstevel@tonic-gate } 65457c478bd9Sstevel@tonic-gate 65467c478bd9Sstevel@tonic-gate static void 65477c478bd9Sstevel@tonic-gate release_sb_dma(struct fdctlr *fdc) 65487c478bd9Sstevel@tonic-gate { 65497c478bd9Sstevel@tonic-gate struct sb_dma_reg *dma_reg; 65507c478bd9Sstevel@tonic-gate dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs; 65517c478bd9Sstevel@tonic-gate /* Unmask all the channels to release the DMA controller */ 65527c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_dma, 65537c478bd9Sstevel@tonic-gate &dma_reg->sb_dma_regs[DMAC1_ALLMASK], NULL); 65547c478bd9Sstevel@tonic-gate fdc->sb_dma_lock = 0; 65557c478bd9Sstevel@tonic-gate } 65567c478bd9Sstevel@tonic-gate 65577c478bd9Sstevel@tonic-gate static void 65587c478bd9Sstevel@tonic-gate quiesce_fd_interrupt(struct fdctlr *fdc) 65597c478bd9Sstevel@tonic-gate { 65607c478bd9Sstevel@tonic-gate /* 65617c478bd9Sstevel@tonic-gate * The following code is put here to take care of HW problem. 65627c478bd9Sstevel@tonic-gate * The HW problem is as follows: 65637c478bd9Sstevel@tonic-gate * 65647c478bd9Sstevel@tonic-gate * After poweron the Southbridge floppy controller asserts the 65657c478bd9Sstevel@tonic-gate * interrupt in tristate. This causes continuous interrupts to 65667c478bd9Sstevel@tonic-gate * be generated. 65677c478bd9Sstevel@tonic-gate * Until the Hardware is FIXED we will have to use the following code 65687c478bd9Sstevel@tonic-gate * to set the interrupt line to proper state after poweron. 65697c478bd9Sstevel@tonic-gate */ 65707c478bd9Sstevel@tonic-gate if (fdc->c_fdtype & FDCTYPE_SB) { 65717c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor), 65727c478bd9Sstevel@tonic-gate 0x0); 65737c478bd9Sstevel@tonic-gate drv_usecwait(200); 65747c478bd9Sstevel@tonic-gate ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor), 65757c478bd9Sstevel@tonic-gate 0xC); 65767c478bd9Sstevel@tonic-gate drv_usecwait(200); 65777c478bd9Sstevel@tonic-gate Set_Fifo(fdc, 0xE6); 65787c478bd9Sstevel@tonic-gate drv_usecwait(200); 65797c478bd9Sstevel@tonic-gate } 65807c478bd9Sstevel@tonic-gate } 6581