10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * Floppy Disk driver 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate /* 320Sstevel@tonic-gate * Set CMOS feature: 330Sstevel@tonic-gate * CMOS_CONF_MEM: CMOS memory contains configuration info 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate #define CMOS_CONF_MEM 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <sys/types.h> 380Sstevel@tonic-gate #include <sys/param.h> 390Sstevel@tonic-gate #include <sys/systm.h> 400Sstevel@tonic-gate #include <sys/buf.h> 410Sstevel@tonic-gate #include <sys/file.h> 420Sstevel@tonic-gate #include <sys/open.h> 430Sstevel@tonic-gate #include <sys/ioctl.h> 440Sstevel@tonic-gate #include <sys/uio.h> 450Sstevel@tonic-gate #include <sys/conf.h> 460Sstevel@tonic-gate #include <sys/stat.h> 470Sstevel@tonic-gate #include <sys/autoconf.h> 480Sstevel@tonic-gate #include <sys/vtoc.h> 490Sstevel@tonic-gate #include <sys/dkio.h> 500Sstevel@tonic-gate #include <sys/ddi.h> 510Sstevel@tonic-gate #include <sys/sunddi.h> 520Sstevel@tonic-gate #include <sys/kstat.h> 530Sstevel@tonic-gate #include <sys/kmem.h> 540Sstevel@tonic-gate #include <sys/ddidmareq.h> 550Sstevel@tonic-gate #include <sys/fdio.h> 560Sstevel@tonic-gate #include <sys/fdc.h> 570Sstevel@tonic-gate #include <sys/fd_debug.h> 580Sstevel@tonic-gate #include <sys/fdmedia.h> 590Sstevel@tonic-gate #include <sys/debug.h> 600Sstevel@tonic-gate #include <sys/modctl.h> 610Sstevel@tonic-gate 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * Local Function Prototypes 640Sstevel@tonic-gate */ 650Sstevel@tonic-gate static int fd_unit_is_open(struct fdisk *); 660Sstevel@tonic-gate static int fdgetlabel(struct fcu_obj *, int); 670Sstevel@tonic-gate static void fdstart(struct fcu_obj *); 680Sstevel@tonic-gate static int fd_build_label_vtoc(struct fcu_obj *, struct fdisk *, 690Sstevel@tonic-gate struct vtoc *, struct dk_label *); 700Sstevel@tonic-gate static void fd_build_user_vtoc(struct fcu_obj *, struct fdisk *, 710Sstevel@tonic-gate struct vtoc *); 720Sstevel@tonic-gate static int fd_rawioctl(struct fcu_obj *, int, caddr_t, int); 730Sstevel@tonic-gate static void fd_media_watch(void *); 740Sstevel@tonic-gate 750Sstevel@tonic-gate static int fd_open(dev_t *, int, int, cred_t *); 760Sstevel@tonic-gate static int fd_close(dev_t, int, int, cred_t *); 770Sstevel@tonic-gate static int fd_strategy(struct buf *); 780Sstevel@tonic-gate static int fd_read(dev_t, struct uio *, cred_t *); 790Sstevel@tonic-gate static int fd_write(dev_t, struct uio *, cred_t *); 800Sstevel@tonic-gate static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 810Sstevel@tonic-gate static int fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 820Sstevel@tonic-gate caddr_t, int *); 830Sstevel@tonic-gate static int fd_check_media(dev_t dev, enum dkio_state state); 840Sstevel@tonic-gate static int fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag); 850Sstevel@tonic-gate 860Sstevel@tonic-gate static struct cb_ops fd_cb_ops = { 870Sstevel@tonic-gate fd_open, /* open */ 880Sstevel@tonic-gate fd_close, /* close */ 890Sstevel@tonic-gate fd_strategy, /* strategy */ 900Sstevel@tonic-gate nodev, /* print */ 910Sstevel@tonic-gate nodev, /* dump */ 920Sstevel@tonic-gate fd_read, /* read */ 930Sstevel@tonic-gate fd_write, /* write */ 940Sstevel@tonic-gate fd_ioctl, /* ioctl */ 950Sstevel@tonic-gate nodev, /* devmap */ 960Sstevel@tonic-gate nodev, /* mmap */ 970Sstevel@tonic-gate nodev, /* segmap */ 980Sstevel@tonic-gate nochpoll, /* poll */ 990Sstevel@tonic-gate fd_prop_op, /* cb_prop_op */ 1000Sstevel@tonic-gate 0, /* streamtab */ 1010Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 1020Sstevel@tonic-gate }; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate static int fd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1050Sstevel@tonic-gate static int fd_probe(dev_info_t *); 1060Sstevel@tonic-gate static int fd_attach(dev_info_t *, ddi_attach_cmd_t); 1070Sstevel@tonic-gate static int fd_detach(dev_info_t *, ddi_detach_cmd_t); 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate static struct dev_ops fd_ops = { 1100Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1110Sstevel@tonic-gate 0, /* refcnt */ 1120Sstevel@tonic-gate fd_getinfo, /* getinfo */ 1130Sstevel@tonic-gate nulldev, /* identify */ 1140Sstevel@tonic-gate fd_probe, /* probe */ 1150Sstevel@tonic-gate fd_attach, /* attach */ 1160Sstevel@tonic-gate fd_detach, /* detach */ 1170Sstevel@tonic-gate nodev, /* reset */ 1180Sstevel@tonic-gate &fd_cb_ops, /* driver operations */ 119*7656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* bus operations */ 120*7656SSherry.Moore@Sun.COM NULL, /* power */ 121*7656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 1220Sstevel@tonic-gate }; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* 1260Sstevel@tonic-gate * static data 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate static void *fd_state_head; /* opaque handle top of state structs */ 1290Sstevel@tonic-gate static int fd_check_media_time = 5000000; /* 5 second state check */ 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * error handling 1330Sstevel@tonic-gate * 1340Sstevel@tonic-gate * for debugging, 1350Sstevel@tonic-gate * set fderrlevel to 1 1360Sstevel@tonic-gate * set fderrmask to 224 or 644 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate #ifdef DEBUG 1390Sstevel@tonic-gate static uint_t fderrmask = FDEM_ALL; 1400Sstevel@tonic-gate #endif 1410Sstevel@tonic-gate static int fderrlevel = 5; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate #define KIOSP KSTAT_IO_PTR(fdp->d_iostat) 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate static struct driver_minor_data { 1460Sstevel@tonic-gate char *name; 1470Sstevel@tonic-gate int minor; 1480Sstevel@tonic-gate int type; 1490Sstevel@tonic-gate } fd_minor [] = { 1500Sstevel@tonic-gate { "a", 0, S_IFBLK}, 1510Sstevel@tonic-gate { "b", 1, S_IFBLK}, 1520Sstevel@tonic-gate { "c", 2, S_IFBLK}, 1530Sstevel@tonic-gate { "a,raw", 0, S_IFCHR}, 1540Sstevel@tonic-gate { "b,raw", 1, S_IFCHR}, 1550Sstevel@tonic-gate { "c,raw", 2, S_IFCHR}, 1560Sstevel@tonic-gate {0} 1570Sstevel@tonic-gate }; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static struct modldrv modldrv = { 1600Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 161*7656SSherry.Moore@Sun.COM "Floppy Disk driver", /* Name of the module. */ 1620Sstevel@tonic-gate &fd_ops, /* driver ops */ 1630Sstevel@tonic-gate }; 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate static struct modlinkage modlinkage = { 1660Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1670Sstevel@tonic-gate }; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate int 1710Sstevel@tonic-gate _init(void) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate int retval; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate if ((retval = ddi_soft_state_init(&fd_state_head, 1760Sstevel@tonic-gate sizeof (struct fdisk) + sizeof (struct fd_drive) + 1770Sstevel@tonic-gate sizeof (struct fd_char) + sizeof (struct fdattr), 0)) != 0) 1780Sstevel@tonic-gate return (retval); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if ((retval = mod_install(&modlinkage)) != 0) 1810Sstevel@tonic-gate ddi_soft_state_fini(&fd_state_head); 1820Sstevel@tonic-gate return (retval); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate int 1860Sstevel@tonic-gate _fini(void) 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate int retval; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate if ((retval = mod_remove(&modlinkage)) != 0) 1910Sstevel@tonic-gate return (retval); 1920Sstevel@tonic-gate ddi_soft_state_fini(&fd_state_head); 1930Sstevel@tonic-gate return (retval); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate int 1970Sstevel@tonic-gate _info(struct modinfo *modinfop) 1980Sstevel@tonic-gate { 1990Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate static int 2040Sstevel@tonic-gate fd_getdrive(dev_t dev, struct fcu_obj **fjpp, struct fdisk **fdpp) 2050Sstevel@tonic-gate { 2060Sstevel@tonic-gate if (fdpp) { 2070Sstevel@tonic-gate *fdpp = ddi_get_soft_state(fd_state_head, DRIVE(dev)); 2080Sstevel@tonic-gate if (*fdpp && fjpp) { 2090Sstevel@tonic-gate *fjpp = (*fdpp)->d_obj; 2100Sstevel@tonic-gate if (*fjpp) 2110Sstevel@tonic-gate return ((*fjpp)->fj_unit); 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate return (-1); 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate /*ARGSUSED*/ 2180Sstevel@tonic-gate static int 2190Sstevel@tonic-gate fd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate dev_t dev = (dev_t)arg; 2220Sstevel@tonic-gate struct fcu_obj *fjp = NULL; 2230Sstevel@tonic-gate struct fdisk *fdp = NULL; 2240Sstevel@tonic-gate int rval; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate switch (cmd) { 2270Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2280Sstevel@tonic-gate (void) fd_getdrive(dev, &fjp, &fdp); 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * Ignoring return value because success is checked by 2310Sstevel@tonic-gate * verifying fjp and fdp and returned unit value is not used. 2320Sstevel@tonic-gate */ 2330Sstevel@tonic-gate if (fjp && fdp) { 2340Sstevel@tonic-gate *result = fjp->fj_dip; 2350Sstevel@tonic-gate rval = DDI_SUCCESS; 2360Sstevel@tonic-gate } else 2370Sstevel@tonic-gate rval = DDI_FAILURE; 2380Sstevel@tonic-gate break; 2390Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2400Sstevel@tonic-gate *result = (void *)(uintptr_t)DRIVE(dev); 2410Sstevel@tonic-gate rval = DDI_SUCCESS; 2420Sstevel@tonic-gate break; 2430Sstevel@tonic-gate default: 2440Sstevel@tonic-gate rval = DDI_FAILURE; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate return (rval); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate #ifdef CMOS_CONF_MEM 2500Sstevel@tonic-gate #define CMOS_ADDR 0x70 2510Sstevel@tonic-gate #define CMOS_DATA 0x71 2520Sstevel@tonic-gate #define CMOS_FDRV 0x10 2530Sstevel@tonic-gate #endif /* CMOS_CONF_MEM */ 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate static int 2560Sstevel@tonic-gate fd_probe(dev_info_t *dip) 2570Sstevel@tonic-gate { 2580Sstevel@tonic-gate #ifdef CMOS_CONF_MEM 2590Sstevel@tonic-gate int cmos; 2600Sstevel@tonic-gate int drive_type; 2610Sstevel@tonic-gate #endif /* CMOS_CONF_MEM */ 2620Sstevel@tonic-gate int debug[2]; 2630Sstevel@tonic-gate int drive_size; 2640Sstevel@tonic-gate int len; 2650Sstevel@tonic-gate int unit_num; 2660Sstevel@tonic-gate char density[8]; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate len = sizeof (debug); 2690Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 2700Sstevel@tonic-gate DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) == 2710Sstevel@tonic-gate DDI_PROP_SUCCESS) { 2720Sstevel@tonic-gate fderrlevel = debug[0]; 2730Sstevel@tonic-gate #ifdef DEBUG 2740Sstevel@tonic-gate fderrmask = (uint_t)debug[1]; 2750Sstevel@tonic-gate #endif 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate len = sizeof (unit_num); 2780Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 2790Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) != 2800Sstevel@tonic-gate DDI_PROP_SUCCESS) { 2810Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 2820Sstevel@tonic-gate (CE_WARN, "fd_probe failed: dip %p", (void *)dip)); 2830Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate #ifdef CMOS_CONF_MEM 2870Sstevel@tonic-gate /* get the cmos memory values quick and dirty */ 2880Sstevel@tonic-gate outb(CMOS_ADDR, CMOS_FDRV); 2890Sstevel@tonic-gate cmos = drive_type = (int)inb(CMOS_DATA); 2900Sstevel@tonic-gate #endif /* CMOS_CONF_MEM */ 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate switch (unit_num) { 2930Sstevel@tonic-gate #ifdef CMOS_CONF_MEM 2940Sstevel@tonic-gate case 0: 2950Sstevel@tonic-gate drive_type = drive_type >> 4; 2960Sstevel@tonic-gate /* FALLTHROUGH */ 2970Sstevel@tonic-gate case 1: 2980Sstevel@tonic-gate if (cmos && (drive_type & 0x0F)) { 2990Sstevel@tonic-gate break; 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate /* 3020Sstevel@tonic-gate * Some enhanced floppy-disk controller adaptor cards 3030Sstevel@tonic-gate * require NO drives defined in the CMOS configuration 3040Sstevel@tonic-gate * memory. 3050Sstevel@tonic-gate * So fall through 3060Sstevel@tonic-gate */ 3070Sstevel@tonic-gate #endif /* CMOS_CONF_MEM */ 3080Sstevel@tonic-gate default: /* need to check conf file */ 3090Sstevel@tonic-gate len = sizeof (density); 3100Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 3110Sstevel@tonic-gate DDI_PROP_DONTPASS, "density", (caddr_t)&density, &len) != 3120Sstevel@tonic-gate DDI_PROP_SUCCESS) { 3130Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 3140Sstevel@tonic-gate (CE_WARN, 3150Sstevel@tonic-gate "fd_probe failed density: dip %p unit %d", 3160Sstevel@tonic-gate (void *)dip, unit_num)); 3170Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate len = sizeof (drive_size); 3200Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 3210Sstevel@tonic-gate DDI_PROP_DONTPASS, "size", (caddr_t)&drive_size, &len) != 3220Sstevel@tonic-gate DDI_PROP_SUCCESS) { 3230Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 3240Sstevel@tonic-gate (CE_WARN, "fd_probe failed size: dip %p unit %d", 3250Sstevel@tonic-gate (void *)dip, unit_num)); 3260Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 3300Sstevel@tonic-gate (CE_WARN, "fd_probe dip %p unit %d", (void *)dip, unit_num)); 3310Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* ARGSUSED */ 3360Sstevel@tonic-gate static int 3370Sstevel@tonic-gate fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3380Sstevel@tonic-gate { 3390Sstevel@tonic-gate struct fcu_obj *fjp; 3400Sstevel@tonic-gate struct fdisk *fdp; 3410Sstevel@tonic-gate struct driver_minor_data *dmdp; 3420Sstevel@tonic-gate int mode_3D; 3430Sstevel@tonic-gate int drive_num, drive_size, drive_type; 3440Sstevel@tonic-gate #ifdef CMOS_CONF_MEM 3450Sstevel@tonic-gate int cmos; 3460Sstevel@tonic-gate #endif /* CMOS_CONF_MEM */ 3470Sstevel@tonic-gate int len, sig_minor; 3480Sstevel@tonic-gate int unit_num; 3490Sstevel@tonic-gate char density[8]; 3500Sstevel@tonic-gate char name[MAXNAMELEN]; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate switch (cmd) { 3530Sstevel@tonic-gate case DDI_ATTACH: 3540Sstevel@tonic-gate len = sizeof (unit_num); 3550Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 3560Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) != 3570Sstevel@tonic-gate DDI_PROP_SUCCESS) { 3580Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 3590Sstevel@tonic-gate (CE_WARN, "fd_attach failed: dip %p", (void *)dip)); 3600Sstevel@tonic-gate return (DDI_FAILURE); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate #ifdef CMOS_CONF_MEM 3640Sstevel@tonic-gate outb(CMOS_ADDR, CMOS_FDRV); 3650Sstevel@tonic-gate cmos = drive_type = (int)inb(CMOS_DATA); 3660Sstevel@tonic-gate #endif /* CMOS_CONF_MEM */ 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate switch (unit_num) { 3690Sstevel@tonic-gate #ifdef CMOS_CONF_MEM 3700Sstevel@tonic-gate case 0: 3710Sstevel@tonic-gate drive_type = drive_type >> 4; 3720Sstevel@tonic-gate /* FALLTHROUGH */ 3730Sstevel@tonic-gate case 1: 3740Sstevel@tonic-gate drive_type = drive_type & 0x0F; 3750Sstevel@tonic-gate if (cmos) 3760Sstevel@tonic-gate break; 3770Sstevel@tonic-gate /* 3780Sstevel@tonic-gate * Some enhanced floppy-disk controller adaptor cards 3790Sstevel@tonic-gate * require NO drives defined in the CMOS configuration 3800Sstevel@tonic-gate * memory. 3810Sstevel@tonic-gate * So fall through 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate #endif /* CMOS_CONF_MEM */ 3840Sstevel@tonic-gate default: /* need to check .conf file */ 3850Sstevel@tonic-gate drive_type = 0; 3860Sstevel@tonic-gate len = sizeof (density); 3870Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, 3880Sstevel@tonic-gate PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "density", 3890Sstevel@tonic-gate (caddr_t)&density, &len) != DDI_PROP_SUCCESS) 3900Sstevel@tonic-gate density[0] = '\0'; 3910Sstevel@tonic-gate len = sizeof (drive_size); 3920Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, 3930Sstevel@tonic-gate PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "size", 3940Sstevel@tonic-gate (caddr_t)&drive_size, &len) != DDI_PROP_SUCCESS) 3950Sstevel@tonic-gate drive_size = 0; 3960Sstevel@tonic-gate if (strcmp(density, "DSDD") == 0) { 3970Sstevel@tonic-gate if (drive_size == 5) 3980Sstevel@tonic-gate drive_type = 1; 3990Sstevel@tonic-gate else if (drive_size == 3) 4000Sstevel@tonic-gate drive_type = 3; 4010Sstevel@tonic-gate } else if (strcmp(density, "DSHD") == 0) { 4020Sstevel@tonic-gate if (drive_size == 5) 4030Sstevel@tonic-gate drive_type = 2; 4040Sstevel@tonic-gate else if (drive_size == 3) 4050Sstevel@tonic-gate drive_type = 4; 4060Sstevel@tonic-gate } else if (strcmp(density, "DSED") == 0 && 4070Sstevel@tonic-gate drive_size == 3) { 4080Sstevel@tonic-gate drive_type = 6; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate break; 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate if (drive_type == 0) { 4130Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 4140Sstevel@tonic-gate (CE_WARN, "fd_attach failed type: dip %p unit %d", 4150Sstevel@tonic-gate (void *)dip, unit_num)); 4160Sstevel@tonic-gate return (DDI_FAILURE); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate drive_num = ddi_get_instance(dip); 4200Sstevel@tonic-gate if (ddi_soft_state_zalloc(fd_state_head, drive_num) != 0) 4210Sstevel@tonic-gate return (DDI_FAILURE); 4220Sstevel@tonic-gate fdp = ddi_get_soft_state(fd_state_head, drive_num); 4230Sstevel@tonic-gate fjp = fdp->d_obj = ddi_get_driver_private(dip); 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate mutex_init(&fjp->fj_lock, NULL, MUTEX_DRIVER, *fjp->fj_iblock); 4260Sstevel@tonic-gate sema_init(&fdp->d_ocsem, 1, NULL, SEMA_DRIVER, NULL); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate fjp->fj_drive = (struct fd_drive *)(fdp + 1); 4290Sstevel@tonic-gate fjp->fj_chars = (struct fd_char *)(fjp->fj_drive + 1); 4300Sstevel@tonic-gate fjp->fj_attr = (struct fdattr *)(fjp->fj_chars + 1); 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * set default floppy drive characteristics & geometry 4340Sstevel@tonic-gate */ 4350Sstevel@tonic-gate switch (drive_type) { /* assume doubled sided */ 4360Sstevel@tonic-gate case 2: /* 5.25 high density */ 4370Sstevel@tonic-gate *fjp->fj_drive = dfd_525HD; 4380Sstevel@tonic-gate fdp->d_media = 1<<FMT_5H | 1<<FMT_5D9 | 1<<FMT_5D8 | 4390Sstevel@tonic-gate 1<<FMT_5D4 | 1<<FMT_5D16; 4400Sstevel@tonic-gate fdp->d_deffdtype = fdp->d_curfdtype = FMT_5H; 4410Sstevel@tonic-gate break; 4420Sstevel@tonic-gate case 4: /* 3.5 high density */ 4430Sstevel@tonic-gate *fjp->fj_drive = dfd_350HD; 4440Sstevel@tonic-gate fdp->d_media = 1<<FMT_3H | 1<<FMT_3I | 1<<FMT_3D; 4450Sstevel@tonic-gate len = sizeof (mode_3D); 4460Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, 4470Sstevel@tonic-gate PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "mode_3D", 4480Sstevel@tonic-gate (caddr_t)&mode_3D, &len) != DDI_PROP_SUCCESS) 4490Sstevel@tonic-gate mode_3D = 0; 4500Sstevel@tonic-gate if (mode_3D && (fjp->fj_fdc->c_flags & FCFLG_3DMODE)) 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * 3D mode should be enabled only if a dual- 4530Sstevel@tonic-gate * speed 3.5" high-density drive and a 4540Sstevel@tonic-gate * supported floppy controller are installed. 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate fdp->d_media |= 1 << FMT_3M; 4570Sstevel@tonic-gate fdp->d_deffdtype = fdp->d_curfdtype = FMT_3H; 4580Sstevel@tonic-gate break; 4590Sstevel@tonic-gate case 1: /* 5.25 double density */ 4600Sstevel@tonic-gate *fjp->fj_drive = dfd_525DD; 4610Sstevel@tonic-gate fdp->d_media = 1<<FMT_5D9 | 1<<FMT_5D8 | 1<<FMT_5D4 | 4620Sstevel@tonic-gate 1<<FMT_5D16; 4630Sstevel@tonic-gate fdp->d_deffdtype = fdp->d_curfdtype = FMT_5D9; 4640Sstevel@tonic-gate break; 4650Sstevel@tonic-gate case 3: /* 3.5 double density */ 4660Sstevel@tonic-gate *fjp->fj_drive = dfd_350HD; 4670Sstevel@tonic-gate fdp->d_media = 1<<FMT_3D; 4680Sstevel@tonic-gate fdp->d_deffdtype = fdp->d_curfdtype = FMT_3D; 4690Sstevel@tonic-gate break; 4700Sstevel@tonic-gate case 5: /* 3.5 extended density */ 4710Sstevel@tonic-gate case 6: 4720Sstevel@tonic-gate case 7: 4730Sstevel@tonic-gate *fjp->fj_drive = dfd_350ED; 4740Sstevel@tonic-gate fdp->d_media = 1<<FMT_3E | 1<<FMT_3H | 1<<FMT_3I | 4750Sstevel@tonic-gate 1<<FMT_3D; 4760Sstevel@tonic-gate fdp->d_deffdtype = fdp->d_curfdtype = FMT_3E; 4770Sstevel@tonic-gate break; 4780Sstevel@tonic-gate case 0: /* no drive defined */ 4790Sstevel@tonic-gate default: 4800Sstevel@tonic-gate goto no_attach; 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate *fjp->fj_chars = *defchar[fdp->d_deffdtype]; 4830Sstevel@tonic-gate *fjp->fj_attr = fdtypes[fdp->d_deffdtype]; 4840Sstevel@tonic-gate bcopy(fdparts[fdp->d_deffdtype], fdp->d_part, 4850Sstevel@tonic-gate sizeof (struct partition) * NDKMAP); 4860Sstevel@tonic-gate fjp->fj_rotspd = fdtypes[fdp->d_deffdtype].fda_rotatespd; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate sig_minor = drive_num << 3; 4890Sstevel@tonic-gate for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) { 4900Sstevel@tonic-gate if (ddi_create_minor_node(dip, dmdp->name, dmdp->type, 4910Sstevel@tonic-gate sig_minor | dmdp->minor, DDI_NT_FD, NULL) 4920Sstevel@tonic-gate == DDI_FAILURE) { 4930Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 4940Sstevel@tonic-gate goto no_attach; 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 4990Sstevel@tonic-gate (CE_WARN, "fd_attach: dip %p unit %d", 5000Sstevel@tonic-gate (void *)dip, unit_num)); 5010Sstevel@tonic-gate (void) sprintf(name, "fd%d", drive_num); 5020Sstevel@tonic-gate fdp->d_iostat = kstat_create("fd", drive_num, name, "disk", 5030Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 5040Sstevel@tonic-gate if (fdp->d_iostat) { 5050Sstevel@tonic-gate fdp->d_iostat->ks_lock = &fjp->fj_lock; 5060Sstevel@tonic-gate kstat_install(fdp->d_iostat); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate fjp->fj_data = (caddr_t)fdp; 5100Sstevel@tonic-gate fjp->fj_flags |= FUNIT_DRVATCH; 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate /* 5130Sstevel@tonic-gate * Add a zero-length attribute to tell the world we support 5140Sstevel@tonic-gate * kernel ioctls (for layered drivers) 5150Sstevel@tonic-gate */ 5160Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 5170Sstevel@tonic-gate DDI_KERNEL_IOCTL, NULL, 0); 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * Ignoring return value because, for passed arguments, only 5200Sstevel@tonic-gate * DDI_SUCCESS is returned. 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate ddi_report_dev(dip); 5230Sstevel@tonic-gate return (DDI_SUCCESS); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate #ifdef NOT_YET 5260Sstevel@tonic-gate case DDI_RESUME: 5270Sstevel@tonic-gate drive_num = ddi_get_instance(dip); 5280Sstevel@tonic-gate if (!(fdp = ddi_get_soft_state(fd_state_head, drive_num))) 5290Sstevel@tonic-gate return (DDI_FAILURE); 5300Sstevel@tonic-gate fjp = (struct fcu_obj *)fdp->d_obj; 5310Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 5320Sstevel@tonic-gate if (!fjp->fj_suspended) { 5330Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 5340Sstevel@tonic-gate return (DDI_SUCCESS); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate fjp->fj_fdc->c_curpcyl[drive_num & 3] = -1; 5370Sstevel@tonic-gate fjp->fj_suspended = 0; 5380Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 5390Sstevel@tonic-gate return (DDI_SUCCESS); 5400Sstevel@tonic-gate #endif 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate default: 5430Sstevel@tonic-gate return (DDI_FAILURE); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate no_attach: 5460Sstevel@tonic-gate fjp->fj_drive = NULL; 5470Sstevel@tonic-gate fjp->fj_chars = NULL; 5480Sstevel@tonic-gate fjp->fj_attr = NULL; 5490Sstevel@tonic-gate mutex_destroy(&fjp->fj_lock); 5500Sstevel@tonic-gate sema_destroy(&fdp->d_ocsem); 5510Sstevel@tonic-gate ddi_soft_state_free(fd_state_head, drive_num); 5520Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, 5530Sstevel@tonic-gate (CE_WARN, "fd_attach failed: dip %p unit %d", 5540Sstevel@tonic-gate (void *)dip, unit_num)); 5550Sstevel@tonic-gate return (DDI_FAILURE); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate /* ARGSUSED */ 5600Sstevel@tonic-gate static int 5610Sstevel@tonic-gate fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5620Sstevel@tonic-gate { 5630Sstevel@tonic-gate struct fcu_obj *fjp; 5640Sstevel@tonic-gate struct fdisk *fdp; 5650Sstevel@tonic-gate int drive_num; 5660Sstevel@tonic-gate int rval = DDI_SUCCESS; 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fd_detach dip %p", 569*7656SSherry.Moore@Sun.COM (void *)dip)); 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate drive_num = ddi_get_instance(dip); 5720Sstevel@tonic-gate if (!(fdp = ddi_get_soft_state(fd_state_head, drive_num))) 5730Sstevel@tonic-gate return (rval); 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate switch (cmd) { 5760Sstevel@tonic-gate case DDI_DETACH: 5770Sstevel@tonic-gate if (fd_unit_is_open(fdp)) { 5780Sstevel@tonic-gate rval = EBUSY; 5790Sstevel@tonic-gate break; 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate kstat_delete(fdp->d_iostat); 5820Sstevel@tonic-gate fdp->d_iostat = NULL; 5830Sstevel@tonic-gate fjp = (struct fcu_obj *)fdp->d_obj; 5840Sstevel@tonic-gate fjp->fj_data = NULL; 5850Sstevel@tonic-gate fjp->fj_drive = NULL; 5860Sstevel@tonic-gate fjp->fj_chars = NULL; 5870Sstevel@tonic-gate fjp->fj_attr = NULL; 5880Sstevel@tonic-gate ddi_prop_remove_all(dip); 5890Sstevel@tonic-gate mutex_destroy(&fjp->fj_lock); 5900Sstevel@tonic-gate sema_destroy(&fdp->d_ocsem); 5910Sstevel@tonic-gate ddi_soft_state_free(fd_state_head, drive_num); 5920Sstevel@tonic-gate break; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate #ifdef NOT_YET 5950Sstevel@tonic-gate case DDI_SUSPEND: 5960Sstevel@tonic-gate fjp = (struct fcu_obj *)fdp->d_obj; 5970Sstevel@tonic-gate fjp->fj_suspended = 1; /* Must be before mutex */ 5980Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 5990Sstevel@tonic-gate while (fjp->fj_flags & FUNIT_BUSY) { 6000Sstevel@tonic-gate /* Wait for I/O to finish */ 6010Sstevel@tonic-gate cv_wait(&fjp->fj_flags, &fjp->fj_lock); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 6040Sstevel@tonic-gate break; 6050Sstevel@tonic-gate #endif 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate default: 6080Sstevel@tonic-gate rval = EINVAL; 6090Sstevel@tonic-gate break; 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate return (rval); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate static int 6160Sstevel@tonic-gate fd_part_is_open(struct fdisk *fdp, int part) 6170Sstevel@tonic-gate { 6180Sstevel@tonic-gate int i; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate for (i = 0; i < (OTYPCNT - 1); i++) 6210Sstevel@tonic-gate if (fdp->d_regopen[i] & (1 << part)) 6220Sstevel@tonic-gate return (1); 6230Sstevel@tonic-gate return (0); 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate static int 6270Sstevel@tonic-gate fd_unit_is_open(struct fdisk *fdp) 6280Sstevel@tonic-gate { 6290Sstevel@tonic-gate int i; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate for (i = 0; i < NDKMAP; i++) 6320Sstevel@tonic-gate if (fdp->d_lyropen[i]) 6330Sstevel@tonic-gate return (1); 6340Sstevel@tonic-gate for (i = 0; i < (OTYPCNT - 1); i++) 6350Sstevel@tonic-gate if (fdp->d_regopen[i]) 6360Sstevel@tonic-gate return (1); 6370Sstevel@tonic-gate return (0); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate /*ARGSUSED*/ 6410Sstevel@tonic-gate static int 6420Sstevel@tonic-gate fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 6430Sstevel@tonic-gate { 6440Sstevel@tonic-gate struct fcu_obj *fjp = NULL; 6450Sstevel@tonic-gate struct fdisk *fdp = NULL; 6460Sstevel@tonic-gate struct partition *pp; 6470Sstevel@tonic-gate dev_t dev; 6480Sstevel@tonic-gate int part, unit; 6490Sstevel@tonic-gate int part_is_open; 6500Sstevel@tonic-gate int rval; 6510Sstevel@tonic-gate uint_t pbit; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate dev = *devp; 6540Sstevel@tonic-gate unit = fd_getdrive(dev, &fjp, &fdp); 6550Sstevel@tonic-gate if (!fjp || !fdp) 6560Sstevel@tonic-gate return (ENXIO); 6570Sstevel@tonic-gate part = PARTITION(dev); 6580Sstevel@tonic-gate pbit = 1 << part; 6590Sstevel@tonic-gate pp = &fdp->d_part[part]; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate /* 6620Sstevel@tonic-gate * Serialize opens/closes 6630Sstevel@tonic-gate */ 6640Sstevel@tonic-gate sema_p(&fdp->d_ocsem); 6650Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_OPEN, 6660Sstevel@tonic-gate (CE_CONT, "fd_open: fd%d part %d flag %x otype %x\n", DRIVE(dev), 6670Sstevel@tonic-gate part, flag, otyp)); 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate /* 6700Sstevel@tonic-gate * Check for previous exclusive open, or trying to exclusive open 6710Sstevel@tonic-gate * An "exclusive open" on any partition is not guaranteed to 6720Sstevel@tonic-gate * protect against opens on another partition that overlaps it. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate if (otyp == OTYP_LYR) { 6750Sstevel@tonic-gate part_is_open = (fdp->d_lyropen[part] != 0); 6760Sstevel@tonic-gate } else { 6770Sstevel@tonic-gate part_is_open = fd_part_is_open(fdp, part); 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate if ((fdp->d_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) { 6800Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_OPEN, (CE_CONT, 6810Sstevel@tonic-gate "fd_open: exclparts %lx openparts %lx lyrcnt %lx pbit %x\n", 6820Sstevel@tonic-gate fdp->d_exclmask, fdp->d_regopen[otyp], fdp->d_lyropen[part], 6830Sstevel@tonic-gate pbit)); 6840Sstevel@tonic-gate sema_v(&fdp->d_ocsem); 6850Sstevel@tonic-gate return (EBUSY); 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * Ensure that drive is recalibrated on first open of new diskette. 6900Sstevel@tonic-gate */ 6910Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 6920Sstevel@tonic-gate if (fjp->fj_ops->fco_getchng(fjp, unit) != 0) { 6930Sstevel@tonic-gate if (fjp->fj_ops->fco_rcseek(fjp, unit, -1, 0)) { 6940Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_OPEN, 6950Sstevel@tonic-gate (CE_NOTE, "fd_open fd%d: not ready", DRIVE(dev))); 6960Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 6970Sstevel@tonic-gate sema_v(&fdp->d_ocsem); 6980Sstevel@tonic-gate return (ENXIO); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate if (flag & (FNDELAY | FNONBLOCK)) { 7030Sstevel@tonic-gate /* don't attempt access, just return successfully */ 7040Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 7050Sstevel@tonic-gate goto out; 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* 7090Sstevel@tonic-gate * auto-sense the density/format of the diskette 7100Sstevel@tonic-gate */ 7110Sstevel@tonic-gate rval = fdgetlabel(fjp, unit); 7120Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 7130Sstevel@tonic-gate if (rval) { 7140Sstevel@tonic-gate /* didn't find label (couldn't read anything) */ 7150Sstevel@tonic-gate FDERRPRINT(FDEP_L2, FDEM_OPEN, 7160Sstevel@tonic-gate (CE_NOTE, "fd%d: drive not ready", DRIVE(dev))); 7170Sstevel@tonic-gate sema_v(&fdp->d_ocsem); 7180Sstevel@tonic-gate return (EIO); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate /* check partition */ 7210Sstevel@tonic-gate if (pp->p_size == 0) { 7220Sstevel@tonic-gate sema_v(&fdp->d_ocsem); 7230Sstevel@tonic-gate return (ENXIO); 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate /* 7260Sstevel@tonic-gate * if opening for writing, check write protect on diskette 7270Sstevel@tonic-gate */ 7280Sstevel@tonic-gate if ((flag & FWRITE) && (fdp->d_obj->fj_flags & FUNIT_WPROT)) { 7290Sstevel@tonic-gate sema_v(&fdp->d_ocsem); 7300Sstevel@tonic-gate return (EROFS); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate out: 7340Sstevel@tonic-gate /* 7350Sstevel@tonic-gate * mark open as having succeeded 7360Sstevel@tonic-gate */ 7370Sstevel@tonic-gate if (flag & FEXCL) 7380Sstevel@tonic-gate fdp->d_exclmask |= pbit; 7390Sstevel@tonic-gate if (otyp == OTYP_LYR) 7400Sstevel@tonic-gate fdp->d_lyropen[part]++; 7410Sstevel@tonic-gate else 7420Sstevel@tonic-gate fdp->d_regopen[otyp] |= 1 << part; 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate sema_v(&fdp->d_ocsem); 7450Sstevel@tonic-gate return (0); 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * fdgetlabel - read the SunOS label off the diskette 7500Sstevel@tonic-gate * if it can read a valid label it does so, else it will use a 7510Sstevel@tonic-gate * default. If it can`t read the diskette - that is an error. 7520Sstevel@tonic-gate * 7530Sstevel@tonic-gate * RETURNS: 0 for ok - meaning that it could at least read the device, 7540Sstevel@tonic-gate * !0 for error XXX TBD NYD error codes 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate static int 7570Sstevel@tonic-gate fdgetlabel(struct fcu_obj *fjp, int unit) 7580Sstevel@tonic-gate { 7590Sstevel@tonic-gate struct dk_label *label; 7600Sstevel@tonic-gate struct fdisk *fdp; 7610Sstevel@tonic-gate char *newlabel; 7620Sstevel@tonic-gate short *sp; 7630Sstevel@tonic-gate short count; 7640Sstevel@tonic-gate short xsum; 7650Sstevel@tonic-gate int tries, try_this; 7660Sstevel@tonic-gate uint_t nexttype; 7670Sstevel@tonic-gate int rval; 7680Sstevel@tonic-gate short oldlvl; 7690Sstevel@tonic-gate int i; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_GETL, 7720Sstevel@tonic-gate (CE_CONT, "fdgetlabel fd unit %d\n", unit)); 7730Sstevel@tonic-gate fdp = (struct fdisk *)fjp->fj_data; 7740Sstevel@tonic-gate fjp->fj_flags &= ~(FUNIT_UNLABELED); 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate /* 7770Sstevel@tonic-gate * get some space to play with the label 7780Sstevel@tonic-gate */ 7790Sstevel@tonic-gate label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 7800Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_GETL, (CE_CONT, 7810Sstevel@tonic-gate "fdgetlabel fd unit %d kmem_zalloc: ptr = %p, size = %lx\n", 7820Sstevel@tonic-gate unit, (void *)label, (size_t)sizeof (struct dk_label))); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate /* 7850Sstevel@tonic-gate * read block 0 (0/0/1) to find the label 7860Sstevel@tonic-gate * (disk is potentially not present or unformatted) 7870Sstevel@tonic-gate */ 7880Sstevel@tonic-gate /* noerrprint since this is a private cmd */ 7890Sstevel@tonic-gate oldlvl = fderrlevel; 7900Sstevel@tonic-gate fderrlevel = FDEP_LMAX; 7910Sstevel@tonic-gate /* 7920Sstevel@tonic-gate * try different characteristics (ie densities) 7930Sstevel@tonic-gate * 7940Sstevel@tonic-gate * if fdp->d_curfdtype is -1 then the current characteristics 7950Sstevel@tonic-gate * were set by ioctl and need to try it as well as everything 7960Sstevel@tonic-gate * in the table 7970Sstevel@tonic-gate */ 7980Sstevel@tonic-gate nexttype = fdp->d_deffdtype; 7990Sstevel@tonic-gate try_this = 1; /* always try the current characteristics */ 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate for (tries = nfdtypes; tries; tries--) { 8020Sstevel@tonic-gate if (try_this) { 8030Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHAROK; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate /* try reading last sector of cyl 1, head 0 */ 8060Sstevel@tonic-gate if (!(rval = fjp->fj_ops->fco_rw(fjp, unit, 8070Sstevel@tonic-gate FDREAD, 1, 0, fjp->fj_chars->fdc_secptrack, 8080Sstevel@tonic-gate (caddr_t)label, 8090Sstevel@tonic-gate sizeof (struct dk_label))) && 8100Sstevel@tonic-gate /* and last sector plus 1 of cylinder 1 */ 8110Sstevel@tonic-gate fjp->fj_ops->fco_rw(fjp, unit, FDREAD, 1, 8120Sstevel@tonic-gate 0, fjp->fj_chars->fdc_secptrack + 1, 8130Sstevel@tonic-gate (caddr_t)label, 8140Sstevel@tonic-gate sizeof (struct dk_label)) && 8150Sstevel@tonic-gate /* and label sector on cylinder 0 */ 8160Sstevel@tonic-gate !(rval = fjp->fj_ops->fco_rw(fjp, unit, 8170Sstevel@tonic-gate FDREAD, 0, 0, 1, (caddr_t)label, 8180Sstevel@tonic-gate sizeof (struct dk_label)))) 8190Sstevel@tonic-gate break; 8200Sstevel@tonic-gate if (rval == ENXIO) 8210Sstevel@tonic-gate break; 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * try the next entry in the characteristics tbl 8250Sstevel@tonic-gate */ 8260Sstevel@tonic-gate fdp->d_curfdtype = (signed char)nexttype; 8270Sstevel@tonic-gate nexttype = (nexttype + 1) % nfdtypes; 8280Sstevel@tonic-gate if ((1 << fdp->d_curfdtype) & fdp->d_media) { 8290Sstevel@tonic-gate *fjp->fj_chars = *defchar[fdp->d_curfdtype]; 8300Sstevel@tonic-gate *fjp->fj_attr = fdtypes[fdp->d_curfdtype]; 8310Sstevel@tonic-gate bcopy(fdparts[fdp->d_curfdtype], fdp->d_part, 8320Sstevel@tonic-gate sizeof (struct partition) * NDKMAP); 8330Sstevel@tonic-gate /* 8340Sstevel@tonic-gate * check for a double_density diskette 8350Sstevel@tonic-gate * in a high_density 5.25" drive 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate if (fjp->fj_chars->fdc_transfer_rate == 250 && 8380Sstevel@tonic-gate fjp->fj_rotspd > fjp->fj_attr->fda_rotatespd) { 8390Sstevel@tonic-gate /* 8400Sstevel@tonic-gate * yes - adjust transfer rate since we don't 8410Sstevel@tonic-gate * know if we have a 5.25" dual-speed drive 8420Sstevel@tonic-gate */ 8430Sstevel@tonic-gate fjp->fj_attr->fda_rotatespd = 360; 8440Sstevel@tonic-gate fjp->fj_chars->fdc_transfer_rate = 300; 8450Sstevel@tonic-gate fjp->fj_chars->fdc_medium = 5; 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate if ((2 * fjp->fj_chars->fdc_ncyl) == 8480Sstevel@tonic-gate defchar[fdp->d_deffdtype]->fdc_ncyl) { 8490Sstevel@tonic-gate /* yes - adjust steps per cylinder */ 8500Sstevel@tonic-gate fjp->fj_chars->fdc_steps = 2; 8510Sstevel@tonic-gate } else 8520Sstevel@tonic-gate fjp->fj_chars->fdc_steps = 1; 8530Sstevel@tonic-gate try_this = 1; 8540Sstevel@tonic-gate } else 8550Sstevel@tonic-gate try_this = 0; 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate fderrlevel = oldlvl; /* print errors again */ 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate if (rval) { 8600Sstevel@tonic-gate fdp->d_curfdtype = fdp->d_deffdtype; 8610Sstevel@tonic-gate goto out; /* couldn't read anything */ 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_GETL, 8650Sstevel@tonic-gate (CE_CONT, 8660Sstevel@tonic-gate "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n", 8670Sstevel@tonic-gate unit, fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_secptrack, 8680Sstevel@tonic-gate fjp->fj_chars->fdc_steps, fjp->fj_attr->fda_rotatespd, 8690Sstevel@tonic-gate fjp->fj_attr->fda_intrlv)); 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * _something_ was read - look for unixtype label 8730Sstevel@tonic-gate */ 8740Sstevel@tonic-gate if (label->dkl_magic != DKL_MAGIC || 8750Sstevel@tonic-gate label->dkl_vtoc.v_sanity != VTOC_SANE) { 8760Sstevel@tonic-gate /* not a label - no magic number */ 8770Sstevel@tonic-gate goto nolabel; /* no errors, but no label */ 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate count = sizeof (struct dk_label) / sizeof (short); 8810Sstevel@tonic-gate sp = (short *)label; 8820Sstevel@tonic-gate xsum = 0; 8830Sstevel@tonic-gate while (count--) 8840Sstevel@tonic-gate xsum ^= *sp++; /* should add up to 0 */ 8850Sstevel@tonic-gate if (xsum) { 8860Sstevel@tonic-gate /* not a label - checksum didn't compute */ 8870Sstevel@tonic-gate goto nolabel; /* no errors, but no label */ 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * the SunOS label overrides current diskette characteristics 8920Sstevel@tonic-gate */ 8930Sstevel@tonic-gate fjp->fj_chars->fdc_ncyl = label->dkl_pcyl; 8940Sstevel@tonic-gate fjp->fj_chars->fdc_nhead = label->dkl_nhead; 8950Sstevel@tonic-gate fjp->fj_chars->fdc_secptrack = (label->dkl_nsect * DEV_BSIZE) / 8960Sstevel@tonic-gate fjp->fj_chars->fdc_sec_size; 8970Sstevel@tonic-gate if (defchar[fdp->d_deffdtype]->fdc_ncyl == 2 * fjp->fj_chars->fdc_ncyl) 8980Sstevel@tonic-gate fjp->fj_chars->fdc_steps = 2; 8990Sstevel@tonic-gate else 9000Sstevel@tonic-gate fjp->fj_chars->fdc_steps = 1; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate fjp->fj_attr->fda_rotatespd = label->dkl_rpm; 9030Sstevel@tonic-gate fjp->fj_attr->fda_intrlv = label->dkl_intrlv; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate fdp->d_vtoc_version = label->dkl_vtoc.v_version; 9060Sstevel@tonic-gate bcopy(label->dkl_vtoc.v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL); 9070Sstevel@tonic-gate bcopy(label->dkl_vtoc.v_asciilabel, 9080Sstevel@tonic-gate fdp->d_vtoc_asciilabel, LEN_DKL_ASCII); 9090Sstevel@tonic-gate /* 9100Sstevel@tonic-gate * logical partitions 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate for (i = 0; i < NDKMAP; i++) { 9130Sstevel@tonic-gate fdp->d_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag; 9140Sstevel@tonic-gate fdp->d_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag; 9150Sstevel@tonic-gate fdp->d_part[i].p_start = label->dkl_vtoc.v_part[i].p_start; 9160Sstevel@tonic-gate fdp->d_part[i].p_size = label->dkl_vtoc.v_part[i].p_size; 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate fdp->d_vtoc_timestamp[i] = label->dkl_vtoc.timestamp[i]; 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate fjp->fj_flags |= FUNIT_LABELOK; 9220Sstevel@tonic-gate goto out; 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate nolabel: 9250Sstevel@tonic-gate /* 9260Sstevel@tonic-gate * if not found, fill in label info from default (mark default used) 9270Sstevel@tonic-gate */ 9280Sstevel@tonic-gate if (fdp->d_media & (1<<FMT_3D)) 9290Sstevel@tonic-gate newlabel = deflabel_35; 9300Sstevel@tonic-gate else /* if (fdp->d_media & (1<<FMT_5D9)) */ 9310Sstevel@tonic-gate newlabel = deflabel_525; 9320Sstevel@tonic-gate bzero(fdp->d_vtoc_volume, LEN_DKL_VVOL); 9330Sstevel@tonic-gate (void) sprintf(fdp->d_vtoc_asciilabel, newlabel, 9340Sstevel@tonic-gate fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_nhead, 9350Sstevel@tonic-gate fjp->fj_chars->fdc_secptrack); 9360Sstevel@tonic-gate fjp->fj_flags |= FUNIT_UNLABELED; 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate out: 9390Sstevel@tonic-gate kmem_free(label, sizeof (struct dk_label)); 9400Sstevel@tonic-gate return (rval); 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate /*ARGSUSED*/ 9450Sstevel@tonic-gate static int 9460Sstevel@tonic-gate fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 9470Sstevel@tonic-gate { 9480Sstevel@tonic-gate struct fcu_obj *fjp = NULL; 9490Sstevel@tonic-gate struct fdisk *fdp = NULL; 9500Sstevel@tonic-gate int part, part_is_closed; 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate #ifdef DEBUG 9530Sstevel@tonic-gate int unit; 9540Sstevel@tonic-gate #define DEBUG_ASSIGN unit= 9550Sstevel@tonic-gate #else 9560Sstevel@tonic-gate #define DEBUG_ASSIGN (void) 9570Sstevel@tonic-gate #endif 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate DEBUG_ASSIGN fd_getdrive(dev, &fjp, &fdp); 9600Sstevel@tonic-gate /* 9610Sstevel@tonic-gate * Ignoring return in non DEBUG mode because success is checked by 9620Sstevel@tonic-gate * verifying fjp and fdp and returned unit value is not used. 9630Sstevel@tonic-gate */ 9640Sstevel@tonic-gate if (!fjp || !fdp) 9650Sstevel@tonic-gate return (ENXIO); 9660Sstevel@tonic-gate part = PARTITION(dev); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate sema_p(&fdp->d_ocsem); 9690Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_CLOS, 9700Sstevel@tonic-gate (CE_CONT, "fd_close: fd unit %d part %d otype %x\n", 9710Sstevel@tonic-gate unit, part, otyp)); 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate if (otyp == OTYP_LYR) { 9740Sstevel@tonic-gate if (fdp->d_lyropen[part]) 9750Sstevel@tonic-gate fdp->d_lyropen[part]--; 9760Sstevel@tonic-gate part_is_closed = (fdp->d_lyropen[part] == 0); 9770Sstevel@tonic-gate } else { 9780Sstevel@tonic-gate fdp->d_regopen[otyp] &= ~(1<<part); 9790Sstevel@tonic-gate part_is_closed = 1; 9800Sstevel@tonic-gate } 9810Sstevel@tonic-gate if (part_is_closed) { 9820Sstevel@tonic-gate if (part == 2 && fdp->d_exclmask&(1<<part)) 9830Sstevel@tonic-gate fdp->d_exclmask = 0; 9840Sstevel@tonic-gate else 9850Sstevel@tonic-gate fdp->d_exclmask &= ~(1<<part); 9860Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_CLOS, 9870Sstevel@tonic-gate (CE_CONT, 9880Sstevel@tonic-gate "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n", 9890Sstevel@tonic-gate fdp->d_exclmask, fdp->d_regopen[otyp], 9900Sstevel@tonic-gate fdp->d_lyropen[part])); 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate if (fd_unit_is_open(fdp) == 0) 9930Sstevel@tonic-gate fdp->d_obj->fj_flags &= ~FUNIT_CHANGED; 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate sema_v(&fdp->d_ocsem); 9960Sstevel@tonic-gate return (0); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate /* ARGSUSED */ 10000Sstevel@tonic-gate static int 10010Sstevel@tonic-gate fd_read(dev_t dev, struct uio *uio, cred_t *cred_p) 10020Sstevel@tonic-gate { 10030Sstevel@tonic-gate return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio)); 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate /* ARGSUSED */ 10070Sstevel@tonic-gate static int 10080Sstevel@tonic-gate fd_write(dev_t dev, struct uio *uio, cred_t *cred_p) 10090Sstevel@tonic-gate { 10100Sstevel@tonic-gate return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio)); 10110Sstevel@tonic-gate } 10120Sstevel@tonic-gate 10130Sstevel@tonic-gate /* 10140Sstevel@tonic-gate * fd_strategy 10150Sstevel@tonic-gate * checks operation, hangs buf struct off fdcntlr, calls fdstart 10160Sstevel@tonic-gate * if not already busy. Note that if we call start, then the operation 10170Sstevel@tonic-gate * will already be done on return (start sleeps). 10180Sstevel@tonic-gate */ 10190Sstevel@tonic-gate static int 10200Sstevel@tonic-gate fd_strategy(struct buf *bp) 10210Sstevel@tonic-gate { 10220Sstevel@tonic-gate struct fcu_obj *fjp; 10230Sstevel@tonic-gate struct fdisk *fdp; 10240Sstevel@tonic-gate struct partition *pp; 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_STRA, 10270Sstevel@tonic-gate (CE_CONT, "fd_strategy: bp = 0x%p, dev = 0x%lx\n", 10280Sstevel@tonic-gate (void *)bp, bp->b_edev)); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate (void) fd_getdrive(bp->b_edev, &fjp, &fdp); 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate /* 10330Sstevel@tonic-gate * Ignoring return because device exist. 10340Sstevel@tonic-gate * Returned unit value is not used. 10350Sstevel@tonic-gate */ 10360Sstevel@tonic-gate pp = &fdp->d_part[PARTITION(bp->b_edev)]; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if (fjp->fj_chars->fdc_sec_size > NBPSCTR && (bp->b_blkno & 1)) { 10390Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRA, 10400Sstevel@tonic-gate (CE_WARN, "fd%d: block %ld is not start of sector!", 10410Sstevel@tonic-gate DRIVE(bp->b_edev), (long)bp->b_blkno)); 10420Sstevel@tonic-gate bp->b_error = EINVAL; 10430Sstevel@tonic-gate goto bad; 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate if ((bp->b_blkno > pp->p_size)) { 10470Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRA, 10480Sstevel@tonic-gate (CE_WARN, "fd%d: block %ld is past the end! (nblk=%ld)", 10490Sstevel@tonic-gate DRIVE(bp->b_edev), (long)bp->b_blkno, pp->p_size)); 10500Sstevel@tonic-gate bp->b_error = ENOSPC; 10510Sstevel@tonic-gate goto bad; 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate /* if at end of file, skip out now */ 10550Sstevel@tonic-gate if (bp->b_blkno == pp->p_size) { 10560Sstevel@tonic-gate if ((bp->b_flags & B_READ) == 0) { 10570Sstevel@tonic-gate /* a write needs to get an error! */ 10580Sstevel@tonic-gate bp->b_error = ENOSPC; 10590Sstevel@tonic-gate goto bad; 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 10620Sstevel@tonic-gate biodone(bp); 10630Sstevel@tonic-gate return (0); 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate /* if operation not a multiple of sector size, is error! */ 10670Sstevel@tonic-gate if (bp->b_bcount % fjp->fj_chars->fdc_sec_size) { 10680Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRA, 10690Sstevel@tonic-gate (CE_WARN, "fd%d: count %ld must be a multiple of %d", 10700Sstevel@tonic-gate DRIVE(bp->b_edev), bp->b_bcount, 10710Sstevel@tonic-gate fjp->fj_chars->fdc_sec_size)); 10720Sstevel@tonic-gate bp->b_error = EINVAL; 10730Sstevel@tonic-gate goto bad; 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate /* 10770Sstevel@tonic-gate * Put the buf request in the drive's queue, FIFO. 10780Sstevel@tonic-gate */ 10790Sstevel@tonic-gate bp->av_forw = 0; 10800Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 10810Sstevel@tonic-gate if (fdp->d_iostat) 10820Sstevel@tonic-gate kstat_waitq_enter(KIOSP); 10830Sstevel@tonic-gate if (fdp->d_actf) 10840Sstevel@tonic-gate fdp->d_actl->av_forw = bp; 10850Sstevel@tonic-gate else 10860Sstevel@tonic-gate fdp->d_actf = bp; 10870Sstevel@tonic-gate fdp->d_actl = bp; 10880Sstevel@tonic-gate if (!(fjp->fj_flags & FUNIT_BUSY)) { 10890Sstevel@tonic-gate fdstart(fjp); 10900Sstevel@tonic-gate } 10910Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 10920Sstevel@tonic-gate return (0); 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate bad: 10950Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 10960Sstevel@tonic-gate bp->b_flags |= B_ERROR; 10970Sstevel@tonic-gate biodone(bp); 10980Sstevel@tonic-gate return (0); 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate /* 11020Sstevel@tonic-gate * fdstart 11030Sstevel@tonic-gate * called from fd_strategy() or from fdXXXX() to setup and 11040Sstevel@tonic-gate * start operations of read or write only (using buf structs). 11050Sstevel@tonic-gate * Because the chip doesn't handle crossing cylinder boundaries on 11060Sstevel@tonic-gate * the fly, this takes care of those boundary conditions. Note that 11070Sstevel@tonic-gate * it sleeps until the operation is done *within fdstart* - so that 11080Sstevel@tonic-gate * when fdstart returns, the operation is already done. 11090Sstevel@tonic-gate */ 11100Sstevel@tonic-gate static void 11110Sstevel@tonic-gate fdstart(struct fcu_obj *fjp) 11120Sstevel@tonic-gate { 11130Sstevel@tonic-gate struct buf *bp; 11140Sstevel@tonic-gate struct fdisk *fdp = (struct fdisk *)fjp->fj_data; 11150Sstevel@tonic-gate struct fd_char *chp; 11160Sstevel@tonic-gate struct partition *pp; 11170Sstevel@tonic-gate uint_t ptend; 11180Sstevel@tonic-gate uint_t bincyl; /* (the number of the desired) block in cyl. */ 11190Sstevel@tonic-gate uint_t blk, len, tlen; 11200Sstevel@tonic-gate uint_t secpcyl; /* number of sectors per cylinder */ 11210Sstevel@tonic-gate int cyl, head, sect; 11220Sstevel@tonic-gate int sctrshft, unit; 11230Sstevel@tonic-gate caddr_t addr; 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate ASSERT(MUTEX_HELD(&fjp->fj_lock)); 11260Sstevel@tonic-gate fjp->fj_flags |= FUNIT_BUSY; 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate while ((bp = fdp->d_actf) != NULL) { 11290Sstevel@tonic-gate fdp->d_actf = bp->av_forw; 11300Sstevel@tonic-gate fdp->d_current = bp; 11310Sstevel@tonic-gate if (fdp->d_iostat) { 11320Sstevel@tonic-gate kstat_waitq_to_runq(KIOSP); 11330Sstevel@tonic-gate } 11340Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_STRT, 11370Sstevel@tonic-gate (CE_CONT, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n", 11380Sstevel@tonic-gate (void *)bp, (long)bp->b_blkno, bp->b_bcount)); 11390Sstevel@tonic-gate bp->b_flags &= ~B_ERROR; 11400Sstevel@tonic-gate bp->b_error = 0; 11410Sstevel@tonic-gate bp->b_resid = bp->b_bcount; /* init resid */ 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate ASSERT(DRIVE(bp->b_edev) == ddi_get_instance(fjp->fj_dip)); 11440Sstevel@tonic-gate unit = fjp->fj_unit; 11450Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate bp_mapin(bp); /* map in buffers */ 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate pp = &fdp->d_part[PARTITION(bp->b_edev)]; 11500Sstevel@tonic-gate /* starting blk adjusted for the partition */ 11510Sstevel@tonic-gate blk = bp->b_blkno + pp->p_start; 11520Sstevel@tonic-gate ptend = pp->p_start + pp->p_size; /* end of the partition */ 11530Sstevel@tonic-gate 11540Sstevel@tonic-gate chp = fjp->fj_chars; 11550Sstevel@tonic-gate secpcyl = chp->fdc_nhead * chp->fdc_secptrack; 11560Sstevel@tonic-gate switch (chp->fdc_sec_size) { 11570Sstevel@tonic-gate /* convert logical block numbers to sector numbers */ 11580Sstevel@tonic-gate case 1024: 11590Sstevel@tonic-gate sctrshft = SCTRSHFT + 1; 11600Sstevel@tonic-gate blk >>= 1; 11610Sstevel@tonic-gate ptend >>= 1; 11620Sstevel@tonic-gate break; 11630Sstevel@tonic-gate default: 11640Sstevel@tonic-gate case NBPSCTR: 11650Sstevel@tonic-gate sctrshft = SCTRSHFT; 11660Sstevel@tonic-gate break; 11670Sstevel@tonic-gate case 256: 11680Sstevel@tonic-gate sctrshft = SCTRSHFT - 1; 11690Sstevel@tonic-gate blk <<= 1; 11700Sstevel@tonic-gate ptend <<= 1; 11710Sstevel@tonic-gate break; 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate /* 11750Sstevel@tonic-gate * If off the end, limit to actual amount that 11760Sstevel@tonic-gate * can be transferred. 11770Sstevel@tonic-gate */ 11780Sstevel@tonic-gate if ((blk + (bp->b_bcount >> sctrshft)) > ptend) 11790Sstevel@tonic-gate /* to end of partition */ 11800Sstevel@tonic-gate len = (ptend - blk) << sctrshft; 11810Sstevel@tonic-gate else 11820Sstevel@tonic-gate len = bp->b_bcount; 11830Sstevel@tonic-gate addr = bp->b_un.b_addr; /* data buffer address */ 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate /* 11860Sstevel@tonic-gate * now we have the real start blk, addr and len for xfer op 11870Sstevel@tonic-gate */ 11880Sstevel@tonic-gate while (len != 0) { 11890Sstevel@tonic-gate /* start cyl of req */ 11900Sstevel@tonic-gate cyl = blk / secpcyl; 11910Sstevel@tonic-gate bincyl = blk % secpcyl; 11920Sstevel@tonic-gate /* start head of req */ 11930Sstevel@tonic-gate head = bincyl / chp->fdc_secptrack; 11940Sstevel@tonic-gate /* start sector of req */ 11950Sstevel@tonic-gate sect = (bincyl % chp->fdc_secptrack) + 1; 11960Sstevel@tonic-gate /* 11970Sstevel@tonic-gate * If the desired block and length will go beyond the 11980Sstevel@tonic-gate * cylinder end, then limit it to the cylinder end. 11990Sstevel@tonic-gate */ 12000Sstevel@tonic-gate if (bp->b_flags & B_READ) { 12010Sstevel@tonic-gate if (len > ((secpcyl - bincyl) << sctrshft)) 12020Sstevel@tonic-gate tlen = (secpcyl - bincyl) << sctrshft; 12030Sstevel@tonic-gate else 12040Sstevel@tonic-gate tlen = len; 12050Sstevel@tonic-gate } else { 12060Sstevel@tonic-gate if (len > 12070Sstevel@tonic-gate ((chp->fdc_secptrack - sect + 1) << 12080Sstevel@tonic-gate sctrshft)) 12090Sstevel@tonic-gate tlen = 12100Sstevel@tonic-gate (chp->fdc_secptrack - sect + 1) << 12110Sstevel@tonic-gate sctrshft; 12120Sstevel@tonic-gate else 12130Sstevel@tonic-gate tlen = len; 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_STRT, (CE_CONT, 12170Sstevel@tonic-gate " blk 0x%x addr 0x%p len 0x%x " 12180Sstevel@tonic-gate "cyl %d head %d sec %d\n resid 0x%lx, tlen %d\n", 12190Sstevel@tonic-gate blk, (void *)addr, len, cyl, head, sect, 12200Sstevel@tonic-gate bp->b_resid, tlen)); 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate /* 12230Sstevel@tonic-gate * (try to) do the operation - failure returns an errno 12240Sstevel@tonic-gate */ 12250Sstevel@tonic-gate bp->b_error = fjp->fj_ops->fco_rw(fjp, unit, 12260Sstevel@tonic-gate bp->b_flags & B_READ, cyl, head, sect, addr, tlen); 12270Sstevel@tonic-gate if (bp->b_error != 0) { 12280Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_STRT, (CE_WARN, 12290Sstevel@tonic-gate "fdstart: bad exec of bp: 0x%p, err=%d", 12300Sstevel@tonic-gate (void *)bp, bp->b_error)); 12310Sstevel@tonic-gate bp->b_flags |= B_ERROR; 12320Sstevel@tonic-gate break; 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate blk += tlen >> sctrshft; 12350Sstevel@tonic-gate len -= tlen; 12360Sstevel@tonic-gate addr += tlen; 12370Sstevel@tonic-gate bp->b_resid -= tlen; 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_STRT, 12400Sstevel@tonic-gate (CE_CONT, "fdstart done: b_resid %lu, b_count %lu\n", 12410Sstevel@tonic-gate bp->b_resid, bp->b_bcount)); 12420Sstevel@tonic-gate if (fdp->d_iostat) { 12430Sstevel@tonic-gate if (bp->b_flags & B_READ) { 12440Sstevel@tonic-gate KIOSP->reads++; 12450Sstevel@tonic-gate KIOSP->nread += (bp->b_bcount - bp->b_resid); 12460Sstevel@tonic-gate } else { 12470Sstevel@tonic-gate KIOSP->writes++; 12480Sstevel@tonic-gate KIOSP->nwritten += (bp->b_bcount - bp->b_resid); 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate kstat_runq_exit(KIOSP); 12510Sstevel@tonic-gate } 12520Sstevel@tonic-gate bp_mapout(bp); 12530Sstevel@tonic-gate biodone(bp); 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 12560Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 12570Sstevel@tonic-gate fdp->d_current = 0; 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate fjp->fj_flags ^= FUNIT_BUSY; 12600Sstevel@tonic-gate } 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate /* ARGSUSED */ 12630Sstevel@tonic-gate static int 12640Sstevel@tonic-gate fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, 12650Sstevel@tonic-gate int *rval_p) 12660Sstevel@tonic-gate { 12670Sstevel@tonic-gate union { 12680Sstevel@tonic-gate struct dk_cinfo dki; 12690Sstevel@tonic-gate struct dk_geom dkg; 12700Sstevel@tonic-gate struct dk_allmap dka; 12710Sstevel@tonic-gate struct fd_char fdchar; 12720Sstevel@tonic-gate struct fd_drive drvchar; 12730Sstevel@tonic-gate int temp; 12740Sstevel@tonic-gate } cpy; 12750Sstevel@tonic-gate struct vtoc vtoc; 12760Sstevel@tonic-gate struct fcu_obj *fjp = NULL; 12770Sstevel@tonic-gate struct fdisk *fdp = NULL; 12780Sstevel@tonic-gate struct dk_map *dmp; 12790Sstevel@tonic-gate struct dk_label *label; 12800Sstevel@tonic-gate int nblks, part, unit; 12810Sstevel@tonic-gate int rval = 0; 12820Sstevel@tonic-gate enum dkio_state state; 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate unit = fd_getdrive(dev, &fjp, &fdp); 12850Sstevel@tonic-gate if (!fjp || !fdp) 12860Sstevel@tonic-gate return (ENXIO); 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_IOCT, 12890Sstevel@tonic-gate (CE_CONT, "fd_ioctl fd unit %d: cmd %x, arg %lx\n", 12900Sstevel@tonic-gate unit, cmd, arg)); 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate switch (cmd) { 12930Sstevel@tonic-gate case DKIOCINFO: 12940Sstevel@tonic-gate fjp->fj_ops->fco_dkinfo(fjp, &cpy.dki); 12950Sstevel@tonic-gate cpy.dki.dki_cnum = FDCTLR(fjp->fj_unit); 12960Sstevel@tonic-gate cpy.dki.dki_unit = FDUNIT(fjp->fj_unit); 12970Sstevel@tonic-gate cpy.dki.dki_partition = PARTITION(dev); 12980Sstevel@tonic-gate if (ddi_copyout(&cpy.dki, (void *)arg, sizeof (cpy.dki), flag)) 12990Sstevel@tonic-gate rval = EFAULT; 13000Sstevel@tonic-gate break; 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate case DKIOCG_PHYGEOM: 13030Sstevel@tonic-gate case DKIOCG_VIRTGEOM: 13040Sstevel@tonic-gate cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack; 13050Sstevel@tonic-gate goto get_geom; 13060Sstevel@tonic-gate case DKIOCGGEOM: 13070Sstevel@tonic-gate if (fjp->fj_flags & FUNIT_LABELOK) 13080Sstevel@tonic-gate cpy.dkg.dkg_nsect = (fjp->fj_chars->fdc_secptrack * 13090Sstevel@tonic-gate fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 13100Sstevel@tonic-gate else 13110Sstevel@tonic-gate cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack; 13120Sstevel@tonic-gate get_geom: 13130Sstevel@tonic-gate cpy.dkg.dkg_pcyl = fjp->fj_chars->fdc_ncyl; 13140Sstevel@tonic-gate cpy.dkg.dkg_ncyl = fjp->fj_chars->fdc_ncyl; 13150Sstevel@tonic-gate cpy.dkg.dkg_nhead = fjp->fj_chars->fdc_nhead; 13160Sstevel@tonic-gate cpy.dkg.dkg_intrlv = fjp->fj_attr->fda_intrlv; 13170Sstevel@tonic-gate cpy.dkg.dkg_rpm = fjp->fj_attr->fda_rotatespd; 13180Sstevel@tonic-gate cpy.dkg.dkg_read_reinstruct = 13190Sstevel@tonic-gate (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000; 13200Sstevel@tonic-gate cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct; 13210Sstevel@tonic-gate if (ddi_copyout(&cpy.dkg, (void *)arg, sizeof (cpy.dkg), flag)) 13220Sstevel@tonic-gate rval = EFAULT; 13230Sstevel@tonic-gate break; 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate case DKIOCSGEOM: 13260Sstevel@tonic-gate if (ddi_copyin((void *)arg, &cpy.dkg, 13270Sstevel@tonic-gate sizeof (struct dk_geom), flag)) { 13280Sstevel@tonic-gate rval = EFAULT; 13290Sstevel@tonic-gate break; 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 13320Sstevel@tonic-gate fjp->fj_chars->fdc_ncyl = cpy.dkg.dkg_ncyl; 13330Sstevel@tonic-gate fjp->fj_chars->fdc_nhead = cpy.dkg.dkg_nhead; 13340Sstevel@tonic-gate fjp->fj_chars->fdc_secptrack = cpy.dkg.dkg_nsect; 13350Sstevel@tonic-gate fjp->fj_attr->fda_intrlv = cpy.dkg.dkg_intrlv; 13360Sstevel@tonic-gate fjp->fj_attr->fda_rotatespd = cpy.dkg.dkg_rpm; 13370Sstevel@tonic-gate fdp->d_curfdtype = -1; 13380Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 13390Sstevel@tonic-gate break; 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate /* 13420Sstevel@tonic-gate * return the map of all logical partitions 13430Sstevel@tonic-gate */ 13440Sstevel@tonic-gate case DKIOCGAPART: 13450Sstevel@tonic-gate /* 13460Sstevel@tonic-gate * Note the conversion from starting sector number 13470Sstevel@tonic-gate * to starting cylinder number. 13480Sstevel@tonic-gate * Return error if division results in a remainder. 13490Sstevel@tonic-gate */ 13500Sstevel@tonic-gate nblks = fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack; 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 13530Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 13540Sstevel@tonic-gate case DDI_MODEL_ILP32: 13550Sstevel@tonic-gate { 13560Sstevel@tonic-gate struct dk_allmap32 dka32; 13570Sstevel@tonic-gate 13580Sstevel@tonic-gate for (part = 0; part < NDKMAP; part++) { 13590Sstevel@tonic-gate if ((fdp->d_part[part].p_start % nblks) != 0) 13600Sstevel@tonic-gate return (EINVAL); 13610Sstevel@tonic-gate dka32.dka_map[part].dkl_cylno = 13620Sstevel@tonic-gate fdp->d_part[part].p_start / nblks; 13630Sstevel@tonic-gate dka32.dka_map[part].dkl_nblk = 13640Sstevel@tonic-gate fdp->d_part[part].p_size; 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate if (ddi_copyout(&dka32, (void *)arg, 13680Sstevel@tonic-gate sizeof (struct dk_allmap32), flag)) 13690Sstevel@tonic-gate rval = EFAULT; 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate break; 13720Sstevel@tonic-gate } 13730Sstevel@tonic-gate case DDI_MODEL_NONE: 13740Sstevel@tonic-gate 13750Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate dmp = (struct dk_map *)&cpy.dka; 13780Sstevel@tonic-gate for (part = 0; part < NDKMAP; part++) { 13790Sstevel@tonic-gate if ((fdp->d_part[part].p_start % nblks) != 0) 13800Sstevel@tonic-gate return (EINVAL); 13810Sstevel@tonic-gate dmp->dkl_cylno = 13820Sstevel@tonic-gate fdp->d_part[part].p_start / nblks; 13830Sstevel@tonic-gate dmp->dkl_nblk = fdp->d_part[part].p_size; 13840Sstevel@tonic-gate dmp++; 13850Sstevel@tonic-gate } 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate if (ddi_copyout(&cpy.dka, (void *)arg, 13880Sstevel@tonic-gate sizeof (struct dk_allmap), flag)) 13890Sstevel@tonic-gate rval = EFAULT; 13900Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 13910Sstevel@tonic-gate break; 13920Sstevel@tonic-gate 13930Sstevel@tonic-gate } 13940Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate break; 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate /* 13990Sstevel@tonic-gate * Set the map of all logical partitions 14000Sstevel@tonic-gate */ 14010Sstevel@tonic-gate case DKIOCSAPART: 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 14040Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 14050Sstevel@tonic-gate case DDI_MODEL_ILP32: 14060Sstevel@tonic-gate { 14070Sstevel@tonic-gate struct dk_allmap32 dka32; 14080Sstevel@tonic-gate 14090Sstevel@tonic-gate if (ddi_copyin((void *)arg, &dka32, 14100Sstevel@tonic-gate sizeof (dka32), flag)) { 14110Sstevel@tonic-gate rval = EFAULT; 14120Sstevel@tonic-gate break; 14130Sstevel@tonic-gate } 14140Sstevel@tonic-gate for (part = 0; part < NDKMAP; part++) { 14150Sstevel@tonic-gate cpy.dka.dka_map[part].dkl_cylno = 14160Sstevel@tonic-gate dka32.dka_map[part].dkl_cylno; 14170Sstevel@tonic-gate cpy.dka.dka_map[part].dkl_nblk = 14180Sstevel@tonic-gate dka32.dka_map[part].dkl_nblk; 14190Sstevel@tonic-gate } 14200Sstevel@tonic-gate break; 14210Sstevel@tonic-gate } 14220Sstevel@tonic-gate case DDI_MODEL_NONE: 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14250Sstevel@tonic-gate if (ddi_copyin((void *)arg, &cpy.dka, sizeof (cpy.dka), flag)) 14260Sstevel@tonic-gate rval = EFAULT; 14270Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate break; 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate if (rval != 0) 14340Sstevel@tonic-gate break; 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate dmp = (struct dk_map *)&cpy.dka; 14370Sstevel@tonic-gate nblks = fjp->fj_chars->fdc_nhead * 14380Sstevel@tonic-gate fjp->fj_chars->fdc_secptrack; 14390Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 14400Sstevel@tonic-gate /* 14410Sstevel@tonic-gate * Note the conversion from starting cylinder number 14420Sstevel@tonic-gate * to starting sector number. 14430Sstevel@tonic-gate */ 14440Sstevel@tonic-gate for (part = 0; part < NDKMAP; part++) { 14450Sstevel@tonic-gate fdp->d_part[part].p_start = dmp->dkl_cylno * 14460Sstevel@tonic-gate nblks; 14470Sstevel@tonic-gate fdp->d_part[part].p_size = dmp->dkl_nblk; 14480Sstevel@tonic-gate dmp++; 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate break; 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate case DKIOCGVTOC: 14550Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate /* 14580Sstevel@tonic-gate * Exit if the diskette has no label. 14590Sstevel@tonic-gate * Also, get the label to make sure the correct one is 14600Sstevel@tonic-gate * being used since the diskette may have changed 14610Sstevel@tonic-gate */ 14620Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 14630Sstevel@tonic-gate rval = fdgetlabel(fjp, unit); 14640Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 14650Sstevel@tonic-gate if (rval) { 14660Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 14670Sstevel@tonic-gate rval = EINVAL; 14680Sstevel@tonic-gate break; 14690Sstevel@tonic-gate } 14700Sstevel@tonic-gate 14710Sstevel@tonic-gate fd_build_user_vtoc(fjp, fdp, &vtoc); 14720Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 14750Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 14760Sstevel@tonic-gate case DDI_MODEL_ILP32: 14770Sstevel@tonic-gate { 14780Sstevel@tonic-gate struct vtoc32 vtoc32; 14790Sstevel@tonic-gate 14800Sstevel@tonic-gate vtoctovtoc32(vtoc, vtoc32); 14810Sstevel@tonic-gate 14820Sstevel@tonic-gate if (ddi_copyout(&vtoc32, (void *)arg, 14830Sstevel@tonic-gate sizeof (vtoc32), flag)) 14840Sstevel@tonic-gate rval = EFAULT; 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate break; 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate case DDI_MODEL_NONE: 14890Sstevel@tonic-gate 14900Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14910Sstevel@tonic-gate if (ddi_copyout(&vtoc, (void *)arg, 14920Sstevel@tonic-gate sizeof (vtoc), flag)) 14930Sstevel@tonic-gate rval = EFAULT; 14940Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 14950Sstevel@tonic-gate break; 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate break; 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate case DKIOCSVTOC: 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 15040Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 15050Sstevel@tonic-gate case DDI_MODEL_ILP32: 15060Sstevel@tonic-gate { 15070Sstevel@tonic-gate struct vtoc32 vtoc32; 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate if (ddi_copyin((void *)arg, &vtoc32, 15100Sstevel@tonic-gate sizeof (vtoc32), flag)) { 15110Sstevel@tonic-gate rval = EFAULT; 15120Sstevel@tonic-gate break; 15130Sstevel@tonic-gate } 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate vtoc32tovtoc(vtoc32, vtoc); 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate break; 15180Sstevel@tonic-gate } 15190Sstevel@tonic-gate case DDI_MODEL_NONE: 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 15220Sstevel@tonic-gate if (ddi_copyin((void *)arg, &vtoc, sizeof (vtoc), flag)) 15230Sstevel@tonic-gate rval = EFAULT; 15240Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 15250Sstevel@tonic-gate break; 15260Sstevel@tonic-gate } 15270Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate if (rval != 0) 15300Sstevel@tonic-gate break; 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 15360Sstevel@tonic-gate 15370Sstevel@tonic-gate if ((rval = fd_build_label_vtoc(fjp, fdp, &vtoc, label)) == 0) { 15380Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 15390Sstevel@tonic-gate rval = fjp->fj_ops->fco_rw(fjp, unit, FDWRITE, 15400Sstevel@tonic-gate 0, 0, 1, (caddr_t)label, sizeof (struct dk_label)); 15410Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 15440Sstevel@tonic-gate kmem_free(label, sizeof (struct dk_label)); 15450Sstevel@tonic-gate break; 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate case DKIOCSTATE: 15480Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_IOCT, 15490Sstevel@tonic-gate (CE_CONT, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit)); 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) { 15520Sstevel@tonic-gate rval = EFAULT; 15530Sstevel@tonic-gate break; 15540Sstevel@tonic-gate } 15550Sstevel@tonic-gate 15560Sstevel@tonic-gate rval = fd_check_media(dev, state); 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate if (ddi_copyout(&fdp->d_media_state, (void *)arg, 15590Sstevel@tonic-gate sizeof (int), flag)) 15600Sstevel@tonic-gate rval = EFAULT; 15610Sstevel@tonic-gate break; 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate case FDIOGCHAR: 15640Sstevel@tonic-gate if (ddi_copyout(fjp->fj_chars, (void *)arg, 15650Sstevel@tonic-gate sizeof (struct fd_char), flag)) 15660Sstevel@tonic-gate rval = EFAULT; 15670Sstevel@tonic-gate break; 15680Sstevel@tonic-gate 15690Sstevel@tonic-gate case FDIOSCHAR: 15700Sstevel@tonic-gate if (ddi_copyin((void *)arg, &cpy.fdchar, 15710Sstevel@tonic-gate sizeof (struct fd_char), flag)) { 15720Sstevel@tonic-gate rval = EFAULT; 15730Sstevel@tonic-gate break; 15740Sstevel@tonic-gate } 15750Sstevel@tonic-gate switch (cpy.fdchar.fdc_transfer_rate) { 15760Sstevel@tonic-gate case 417: 15770Sstevel@tonic-gate if ((fdp->d_media & (1 << FMT_3M)) == 0) { 15780Sstevel@tonic-gate cmn_err(CE_CONT, 15790Sstevel@tonic-gate "fdioschar:Medium density not supported\n"); 15800Sstevel@tonic-gate rval = EINVAL; 15810Sstevel@tonic-gate break; 15820Sstevel@tonic-gate } 15830Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 15840Sstevel@tonic-gate fjp->fj_attr->fda_rotatespd = 360; 15850Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 15860Sstevel@tonic-gate /* cpy.fdchar.fdc_transfer_rate = 500; */ 15870Sstevel@tonic-gate /* FALLTHROUGH */ 15880Sstevel@tonic-gate case 1000: 15890Sstevel@tonic-gate case 500: 15900Sstevel@tonic-gate case 300: 15910Sstevel@tonic-gate case 250: 15920Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 15930Sstevel@tonic-gate *(fjp->fj_chars) = cpy.fdchar; 15940Sstevel@tonic-gate fdp->d_curfdtype = -1; 15950Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHAROK; 15960Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 15970Sstevel@tonic-gate 15980Sstevel@tonic-gate break; 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate default: 16010Sstevel@tonic-gate FDERRPRINT(FDEP_L4, FDEM_IOCT, 16020Sstevel@tonic-gate (CE_WARN, "fd_ioctl fd unit %d: FDIOSCHAR odd " 1603*7656SSherry.Moore@Sun.COM "xfer rate %dkbs", 1604*7656SSherry.Moore@Sun.COM unit, cpy.fdchar.fdc_transfer_rate)); 16050Sstevel@tonic-gate rval = EINVAL; 16060Sstevel@tonic-gate break; 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate break; 16090Sstevel@tonic-gate 16100Sstevel@tonic-gate /* 16110Sstevel@tonic-gate * set all characteristics and geometry to the defaults 16120Sstevel@tonic-gate */ 16130Sstevel@tonic-gate case FDDEFGEOCHAR: 16140Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 16150Sstevel@tonic-gate fdp->d_curfdtype = fdp->d_deffdtype; 16160Sstevel@tonic-gate *fjp->fj_chars = *defchar[fdp->d_curfdtype]; 16170Sstevel@tonic-gate *fjp->fj_attr = fdtypes[fdp->d_curfdtype]; 16180Sstevel@tonic-gate bcopy(fdparts[fdp->d_curfdtype], 16190Sstevel@tonic-gate fdp->d_part, sizeof (struct partition) * NDKMAP); 16200Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHAROK; 16210Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 16220Sstevel@tonic-gate break; 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate case FDEJECT: /* eject disk */ 16250Sstevel@tonic-gate case DKIOCEJECT: 16260Sstevel@tonic-gate fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 16270Sstevel@tonic-gate rval = ENOSYS; 16280Sstevel@tonic-gate break; 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate case FDGETCHANGE: /* disk changed */ 16310Sstevel@tonic-gate if (ddi_copyin((void *)arg, &cpy.temp, sizeof (int), flag)) { 16320Sstevel@tonic-gate rval = EFAULT; 16330Sstevel@tonic-gate break; 16340Sstevel@tonic-gate } 16350Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 16360Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate if (fjp->fj_flags & FUNIT_CHANGED) 16390Sstevel@tonic-gate cpy.temp |= FDGC_HISTORY; 16400Sstevel@tonic-gate else 16410Sstevel@tonic-gate cpy.temp &= ~FDGC_HISTORY; 16420Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHANGED; 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate if (fjp->fj_ops->fco_getchng(fjp, unit)) { 16450Sstevel@tonic-gate cpy.temp |= FDGC_DETECTED; 16460Sstevel@tonic-gate fjp->fj_ops->fco_resetchng(fjp, unit); 16470Sstevel@tonic-gate /* 16480Sstevel@tonic-gate * check diskette again only if it was removed 16490Sstevel@tonic-gate */ 16500Sstevel@tonic-gate if (fjp->fj_ops->fco_getchng(fjp, unit)) { 16510Sstevel@tonic-gate /* 16520Sstevel@tonic-gate * no diskette is present 16530Sstevel@tonic-gate */ 16540Sstevel@tonic-gate cpy.temp |= FDGC_CURRENT; 16550Sstevel@tonic-gate if (fjp->fj_flags & FUNIT_CHGDET) 16560Sstevel@tonic-gate /* 16570Sstevel@tonic-gate * again no diskette; not a new change 16580Sstevel@tonic-gate */ 16590Sstevel@tonic-gate cpy.temp ^= FDGC_DETECTED; 16600Sstevel@tonic-gate else 16610Sstevel@tonic-gate fjp->fj_flags |= FUNIT_CHGDET; 16620Sstevel@tonic-gate } else { 16630Sstevel@tonic-gate /* 16640Sstevel@tonic-gate * a new diskette is present 16650Sstevel@tonic-gate */ 16660Sstevel@tonic-gate cpy.temp &= ~FDGC_CURRENT; 16670Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHGDET; 16680Sstevel@tonic-gate } 16690Sstevel@tonic-gate } else { 16700Sstevel@tonic-gate cpy.temp &= ~(FDGC_DETECTED | FDGC_CURRENT); 16710Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHGDET; 16720Sstevel@tonic-gate } 16730Sstevel@tonic-gate /* 16740Sstevel@tonic-gate * also get state of write protection 16750Sstevel@tonic-gate */ 16760Sstevel@tonic-gate if (fjp->fj_flags & FUNIT_WPROT) { 16770Sstevel@tonic-gate cpy.temp |= FDGC_CURWPROT; 16780Sstevel@tonic-gate } else { 16790Sstevel@tonic-gate cpy.temp &= ~FDGC_CURWPROT; 16800Sstevel@tonic-gate } 16810Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 16820Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 16830Sstevel@tonic-gate 16840Sstevel@tonic-gate if (ddi_copyout(&cpy.temp, (void *)arg, sizeof (int), flag)) 16850Sstevel@tonic-gate rval = EFAULT; 16860Sstevel@tonic-gate break; 16870Sstevel@tonic-gate 16880Sstevel@tonic-gate case FDGETDRIVECHAR: 16890Sstevel@tonic-gate if (ddi_copyout(fjp->fj_drive, (void *)arg, 16900Sstevel@tonic-gate sizeof (struct fd_drive), flag)) 16910Sstevel@tonic-gate rval = EFAULT; 16920Sstevel@tonic-gate break; 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate case FDSETDRIVECHAR: 16950Sstevel@tonic-gate if (ddi_copyin((void *)arg, &cpy.drvchar, 16960Sstevel@tonic-gate sizeof (struct fd_drive), flag)) { 16970Sstevel@tonic-gate rval = EFAULT; 16980Sstevel@tonic-gate break; 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 17010Sstevel@tonic-gate *(fjp->fj_drive) = cpy.drvchar; 17020Sstevel@tonic-gate fdp->d_curfdtype = -1; 17030Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHAROK; 17040Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 17050Sstevel@tonic-gate break; 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate case DKIOCREMOVABLE: { 17080Sstevel@tonic-gate int i = 1; 17090Sstevel@tonic-gate 17100Sstevel@tonic-gate /* no brainer: floppies are always removable */ 17110Sstevel@tonic-gate if (ddi_copyout(&i, (void *)arg, sizeof (int), flag)) { 17120Sstevel@tonic-gate rval = EFAULT; 17130Sstevel@tonic-gate } 17140Sstevel@tonic-gate break; 17150Sstevel@tonic-gate } 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate case DKIOCGMEDIAINFO: 17180Sstevel@tonic-gate rval = fd_get_media_info(fjp, (caddr_t)arg, flag); 17190Sstevel@tonic-gate break; 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate case FDIOCMD: 17220Sstevel@tonic-gate { 17230Sstevel@tonic-gate struct fd_cmd fc; 17240Sstevel@tonic-gate int cyl, head, spc, spt; 17250Sstevel@tonic-gate 17260Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 17270Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 17280Sstevel@tonic-gate case DDI_MODEL_ILP32: 17290Sstevel@tonic-gate { 17300Sstevel@tonic-gate struct fd_cmd32 fc32; 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate if (ddi_copyin((void *)arg, &fc32, 17330Sstevel@tonic-gate sizeof (fc32), flag)) { 17340Sstevel@tonic-gate rval = EFAULT; 17350Sstevel@tonic-gate break; 17360Sstevel@tonic-gate } 17370Sstevel@tonic-gate 17380Sstevel@tonic-gate fc.fdc_cmd = fc32.fdc_cmd; 17390Sstevel@tonic-gate fc.fdc_flags = fc32.fdc_flags; 17400Sstevel@tonic-gate fc.fdc_blkno = fc32.fdc_blkno; 17410Sstevel@tonic-gate fc.fdc_secnt = fc32.fdc_secnt; 17420Sstevel@tonic-gate fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr; 17430Sstevel@tonic-gate fc.fdc_buflen = fc32.fdc_buflen; 17440Sstevel@tonic-gate 17450Sstevel@tonic-gate break; 17460Sstevel@tonic-gate } 17470Sstevel@tonic-gate case DDI_MODEL_NONE: 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 17500Sstevel@tonic-gate 17510Sstevel@tonic-gate if (ddi_copyin((void *)arg, &fc, sizeof (fc), flag)) { 17520Sstevel@tonic-gate rval = EFAULT; 17530Sstevel@tonic-gate break; 17540Sstevel@tonic-gate } 17550Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 17560Sstevel@tonic-gate break; 17570Sstevel@tonic-gate } 17580Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 17590Sstevel@tonic-gate 17600Sstevel@tonic-gate if (rval != 0) 17610Sstevel@tonic-gate break; 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) { 17640Sstevel@tonic-gate auto struct iovec aiov; 17650Sstevel@tonic-gate auto struct uio auio; 17660Sstevel@tonic-gate struct uio *uio = &auio; 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE; 17690Sstevel@tonic-gate 17700Sstevel@tonic-gate bzero(&auio, sizeof (struct uio)); 17710Sstevel@tonic-gate bzero(&aiov, sizeof (struct iovec)); 17720Sstevel@tonic-gate aiov.iov_base = fc.fdc_bufaddr; 17730Sstevel@tonic-gate aiov.iov_len = (uint_t)fc.fdc_secnt * 17740Sstevel@tonic-gate fjp->fj_chars->fdc_sec_size; 17750Sstevel@tonic-gate uio->uio_iov = &aiov; 17760Sstevel@tonic-gate 17770Sstevel@tonic-gate uio->uio_iovcnt = 1; 17780Sstevel@tonic-gate uio->uio_resid = aiov.iov_len; 17790Sstevel@tonic-gate uio->uio_segflg = UIO_USERSPACE; 17800Sstevel@tonic-gate 17810Sstevel@tonic-gate rval = physio(fd_strategy, (struct buf *)0, dev, 17820Sstevel@tonic-gate spc, minphys, uio); 17830Sstevel@tonic-gate break; 17840Sstevel@tonic-gate } else if (fc.fdc_cmd == FDCMD_FORMAT_TRACK) { 17850Sstevel@tonic-gate spt = fjp->fj_chars->fdc_secptrack; /* sec/trk */ 17860Sstevel@tonic-gate spc = fjp->fj_chars->fdc_nhead * spt; /* sec/cyl */ 17870Sstevel@tonic-gate cyl = fc.fdc_blkno / spc; 17880Sstevel@tonic-gate head = (fc.fdc_blkno % spc) / spt; 17890Sstevel@tonic-gate if ((cyl | head) == 0) 17900Sstevel@tonic-gate fjp->fj_flags &= 17910Sstevel@tonic-gate ~(FUNIT_LABELOK | FUNIT_UNLABELED); 17920Sstevel@tonic-gate 17930Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_FORM, 17940Sstevel@tonic-gate (CE_CONT, "fd_format cyl %d, hd %d\n", cyl, head)); 17950Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 17960Sstevel@tonic-gate rval = fjp->fj_ops->fco_format(fjp, unit, cyl, head, 17970Sstevel@tonic-gate (int)fc.fdc_flags); 17980Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate break; 18010Sstevel@tonic-gate } 18020Sstevel@tonic-gate FDERRPRINT(FDEP_L4, FDEM_IOCT, 18030Sstevel@tonic-gate (CE_WARN, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete", 18040Sstevel@tonic-gate unit)); 18050Sstevel@tonic-gate rval = EINVAL; 18060Sstevel@tonic-gate break; 18070Sstevel@tonic-gate } 18080Sstevel@tonic-gate 18090Sstevel@tonic-gate case FDRAW: 18100Sstevel@tonic-gate rval = fd_rawioctl(fjp, unit, (caddr_t)arg, flag); 18110Sstevel@tonic-gate break; 18120Sstevel@tonic-gate 18130Sstevel@tonic-gate default: 18140Sstevel@tonic-gate FDERRPRINT(FDEP_L4, FDEM_IOCT, 18150Sstevel@tonic-gate (CE_WARN, "fd_ioctl fd unit %d: invalid ioctl 0x%x", 18160Sstevel@tonic-gate unit, cmd)); 18170Sstevel@tonic-gate rval = ENOTTY; 18180Sstevel@tonic-gate break; 18190Sstevel@tonic-gate } 18200Sstevel@tonic-gate return (rval); 18210Sstevel@tonic-gate } 18220Sstevel@tonic-gate 18230Sstevel@tonic-gate static void 18240Sstevel@tonic-gate fd_build_user_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp) 18250Sstevel@tonic-gate { 18260Sstevel@tonic-gate struct partition *vpart; 18270Sstevel@tonic-gate int i; 18280Sstevel@tonic-gate int xblk; 18290Sstevel@tonic-gate 18300Sstevel@tonic-gate /* 18310Sstevel@tonic-gate * Return vtoc structure fields in the provided VTOC area, addressed 18320Sstevel@tonic-gate * by *vtocp. 18330Sstevel@tonic-gate * 18340Sstevel@tonic-gate */ 18350Sstevel@tonic-gate bzero(vtocp, sizeof (struct vtoc)); 18360Sstevel@tonic-gate 18370Sstevel@tonic-gate bcopy(fdp->d_vtoc_bootinfo, 18380Sstevel@tonic-gate vtocp->v_bootinfo, sizeof (vtocp->v_bootinfo)); 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate vtocp->v_sanity = VTOC_SANE; 18410Sstevel@tonic-gate vtocp->v_version = fdp->d_vtoc_version; 18420Sstevel@tonic-gate bcopy(fdp->d_vtoc_volume, vtocp->v_volume, LEN_DKL_VVOL); 18430Sstevel@tonic-gate if (fjp->fj_flags & FUNIT_LABELOK) { 18440Sstevel@tonic-gate vtocp->v_sectorsz = DEV_BSIZE; 18450Sstevel@tonic-gate xblk = 1; 18460Sstevel@tonic-gate } else { 18470Sstevel@tonic-gate vtocp->v_sectorsz = fjp->fj_chars->fdc_sec_size; 18480Sstevel@tonic-gate xblk = vtocp->v_sectorsz / DEV_BSIZE; 18490Sstevel@tonic-gate } 18500Sstevel@tonic-gate vtocp->v_nparts = 3; /* <= NDKMAP; */ 18510Sstevel@tonic-gate 18520Sstevel@tonic-gate /* 18530Sstevel@tonic-gate * Copy partitioning information. 18540Sstevel@tonic-gate */ 18550Sstevel@tonic-gate bcopy(fdp->d_part, vtocp->v_part, sizeof (struct partition) * NDKMAP); 18560Sstevel@tonic-gate for (i = NDKMAP, vpart = vtocp->v_part; i && (xblk > 1); i--, vpart++) { 18570Sstevel@tonic-gate /* correct partition info if sector size > 512 bytes */ 18580Sstevel@tonic-gate vpart->p_start /= xblk; 18590Sstevel@tonic-gate vpart->p_size /= xblk; 18600Sstevel@tonic-gate } 18610Sstevel@tonic-gate 18620Sstevel@tonic-gate bcopy(fdp->d_vtoc_timestamp, 18630Sstevel@tonic-gate vtocp->timestamp, sizeof (fdp->d_vtoc_timestamp)); 18640Sstevel@tonic-gate bcopy(fdp->d_vtoc_asciilabel, vtocp->v_asciilabel, LEN_DKL_ASCII); 18650Sstevel@tonic-gate } 18660Sstevel@tonic-gate 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate static int 18690Sstevel@tonic-gate fd_build_label_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp, 18700Sstevel@tonic-gate struct dk_label *labelp) 18710Sstevel@tonic-gate { 18720Sstevel@tonic-gate struct partition *vpart; 18730Sstevel@tonic-gate int i; 18740Sstevel@tonic-gate int nblks; 18750Sstevel@tonic-gate int ncyl; 18760Sstevel@tonic-gate ushort_t sum, *sp; 18770Sstevel@tonic-gate 18780Sstevel@tonic-gate 18790Sstevel@tonic-gate /* 18800Sstevel@tonic-gate * Sanity-check the vtoc 18810Sstevel@tonic-gate */ 18820Sstevel@tonic-gate if (vtocp->v_sanity != VTOC_SANE || 18830Sstevel@tonic-gate vtocp->v_nparts > NDKMAP || vtocp->v_nparts <= 0) { 18840Sstevel@tonic-gate FDERRPRINT(FDEP_L3, FDEM_IOCT, 18850Sstevel@tonic-gate (CE_WARN, "fd_build_label: sanity check on vtoc failed")); 18860Sstevel@tonic-gate return (EINVAL); 18870Sstevel@tonic-gate } 18880Sstevel@tonic-gate 18890Sstevel@tonic-gate /* 18900Sstevel@tonic-gate * before copying the vtoc, the partition information in it should be 18910Sstevel@tonic-gate * checked against the information the driver already has on the 18920Sstevel@tonic-gate * diskette. 18930Sstevel@tonic-gate */ 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate nblks = (fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack * 1896*7656SSherry.Moore@Sun.COM fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 18970Sstevel@tonic-gate if (nblks == 0 || fjp->fj_chars->fdc_ncyl == 0) 18980Sstevel@tonic-gate return (EFAULT); 18990Sstevel@tonic-gate vpart = vtocp->v_part; 19000Sstevel@tonic-gate 19010Sstevel@tonic-gate /* 19020Sstevel@tonic-gate * Check the partition information in the vtoc. The starting sectors 19030Sstevel@tonic-gate * must lie along cylinder boundaries. (NDKMAP entries are checked 19040Sstevel@tonic-gate * to ensure that the unused entries are set to 0 if vtoc->v_nparts 19050Sstevel@tonic-gate * is less than NDKMAP) 19060Sstevel@tonic-gate */ 19070Sstevel@tonic-gate for (i = NDKMAP; i; i--) { 19080Sstevel@tonic-gate if ((vpart->p_start % nblks) != 0) { 19090Sstevel@tonic-gate return (EINVAL); 19100Sstevel@tonic-gate } 19110Sstevel@tonic-gate ncyl = vpart->p_start / nblks; 19120Sstevel@tonic-gate ncyl += vpart->p_size / nblks; 19130Sstevel@tonic-gate if ((vpart->p_size % nblks) != 0) 19140Sstevel@tonic-gate ncyl++; 19150Sstevel@tonic-gate if (ncyl > (long)fjp->fj_chars->fdc_ncyl) { 19160Sstevel@tonic-gate return (EINVAL); 19170Sstevel@tonic-gate } 19180Sstevel@tonic-gate vpart++; 19190Sstevel@tonic-gate } 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate 19220Sstevel@tonic-gate bcopy(vtocp->v_bootinfo, fdp->d_vtoc_bootinfo, 19230Sstevel@tonic-gate sizeof (vtocp->v_bootinfo)); 19240Sstevel@tonic-gate fdp->d_vtoc_version = vtocp->v_version; 19250Sstevel@tonic-gate bcopy(vtocp->v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL); 19260Sstevel@tonic-gate 19270Sstevel@tonic-gate /* 19280Sstevel@tonic-gate * Copy partitioning information. 19290Sstevel@tonic-gate */ 19300Sstevel@tonic-gate bcopy(vtocp->v_part, fdp->d_part, sizeof (struct partition) * NDKMAP); 19310Sstevel@tonic-gate bcopy(vtocp->timestamp, fdp->d_vtoc_timestamp, 19320Sstevel@tonic-gate sizeof (fdp->d_vtoc_timestamp)); 19330Sstevel@tonic-gate bcopy(vtocp->v_asciilabel, fdp->d_vtoc_asciilabel, LEN_DKL_ASCII); 19340Sstevel@tonic-gate 19350Sstevel@tonic-gate /* 19360Sstevel@tonic-gate * construct the diskette label in supplied buffer 19370Sstevel@tonic-gate */ 19380Sstevel@tonic-gate 19390Sstevel@tonic-gate /* Put appropriate vtoc structure fields into the disk label */ 19400Sstevel@tonic-gate labelp->dkl_vtoc.v_bootinfo[0] = (uint32_t)vtocp->v_bootinfo[0]; 19410Sstevel@tonic-gate labelp->dkl_vtoc.v_bootinfo[1] = (uint32_t)vtocp->v_bootinfo[1]; 19420Sstevel@tonic-gate labelp->dkl_vtoc.v_bootinfo[2] = (uint32_t)vtocp->v_bootinfo[2]; 19430Sstevel@tonic-gate 19440Sstevel@tonic-gate labelp->dkl_vtoc.v_sanity = vtocp->v_sanity; 19450Sstevel@tonic-gate labelp->dkl_vtoc.v_version = vtocp->v_version; 19460Sstevel@tonic-gate 19470Sstevel@tonic-gate bcopy(vtocp->v_volume, labelp->dkl_vtoc.v_volume, LEN_DKL_VVOL); 19480Sstevel@tonic-gate 19490Sstevel@tonic-gate labelp->dkl_vtoc.v_nparts = vtocp->v_nparts; 19500Sstevel@tonic-gate 19510Sstevel@tonic-gate bcopy(vtocp->v_reserved, labelp->dkl_vtoc.v_reserved, 19520Sstevel@tonic-gate sizeof (labelp->dkl_vtoc.v_reserved)); 19530Sstevel@tonic-gate 19540Sstevel@tonic-gate for (i = 0; i < (int)vtocp->v_nparts; i++) { 19550Sstevel@tonic-gate labelp->dkl_vtoc.v_part[i].p_tag = vtocp->v_part[i].p_tag; 19560Sstevel@tonic-gate labelp->dkl_vtoc.v_part[i].p_flag = vtocp->v_part[i].p_flag; 19570Sstevel@tonic-gate labelp->dkl_vtoc.v_part[i].p_start = vtocp->v_part[i].p_start; 19580Sstevel@tonic-gate labelp->dkl_vtoc.v_part[i].p_size = vtocp->v_part[i].p_size; 19590Sstevel@tonic-gate } 19600Sstevel@tonic-gate 19610Sstevel@tonic-gate for (i = 0; i < NDKMAP; i++) { 19620Sstevel@tonic-gate labelp->dkl_vtoc.v_timestamp[i] = vtocp->timestamp[i]; 19630Sstevel@tonic-gate } 19640Sstevel@tonic-gate bcopy(vtocp->v_asciilabel, labelp->dkl_asciilabel, LEN_DKL_ASCII); 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate 19670Sstevel@tonic-gate labelp->dkl_pcyl = fjp->fj_chars->fdc_ncyl; 19680Sstevel@tonic-gate labelp->dkl_ncyl = fjp->fj_chars->fdc_ncyl; 19690Sstevel@tonic-gate labelp->dkl_nhead = fjp->fj_chars->fdc_nhead; 19700Sstevel@tonic-gate /* 19710Sstevel@tonic-gate * The fdc_secptrack field of the fd_char structure is the number 19720Sstevel@tonic-gate * of sectors per track where the sectors are fdc_sec_size. 19730Sstevel@tonic-gate * The dkl_nsect field of the dk_label structure is the number of 19740Sstevel@tonic-gate * DEV_BSIZE (512) byte sectors per track. 19750Sstevel@tonic-gate */ 19760Sstevel@tonic-gate labelp->dkl_nsect = (fjp->fj_chars->fdc_secptrack * 19770Sstevel@tonic-gate fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 19780Sstevel@tonic-gate labelp->dkl_intrlv = fjp->fj_attr->fda_intrlv; 19790Sstevel@tonic-gate labelp->dkl_rpm = fjp->fj_attr->fda_rotatespd; 19800Sstevel@tonic-gate labelp->dkl_read_reinstruct = 19810Sstevel@tonic-gate (int)(labelp->dkl_nsect * labelp->dkl_rpm * 4) / 60000; 19820Sstevel@tonic-gate labelp->dkl_write_reinstruct = labelp->dkl_read_reinstruct; 19830Sstevel@tonic-gate 19840Sstevel@tonic-gate labelp->dkl_magic = DKL_MAGIC; 19850Sstevel@tonic-gate 19860Sstevel@tonic-gate sum = 0; 19870Sstevel@tonic-gate labelp->dkl_cksum = 0; 19880Sstevel@tonic-gate sp = (ushort_t *)labelp; 19890Sstevel@tonic-gate while (sp < &(labelp->dkl_cksum)) { 19900Sstevel@tonic-gate sum ^= *sp++; 19910Sstevel@tonic-gate } 19920Sstevel@tonic-gate labelp->dkl_cksum = sum; 19930Sstevel@tonic-gate 19940Sstevel@tonic-gate return (0); 19950Sstevel@tonic-gate } 19960Sstevel@tonic-gate 19970Sstevel@tonic-gate static int 19980Sstevel@tonic-gate fd_rawioctl(struct fcu_obj *fjp, int unit, caddr_t arg, int mode) 19990Sstevel@tonic-gate { 20000Sstevel@tonic-gate struct fd_raw fdr; 20010Sstevel@tonic-gate char *arg_result = NULL; 20020Sstevel@tonic-gate int flag = B_READ; 20030Sstevel@tonic-gate int rval = 0; 20040Sstevel@tonic-gate caddr_t uaddr; 20050Sstevel@tonic-gate uint_t ucount; 20060Sstevel@tonic-gate 20070Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_RAWI, 20080Sstevel@tonic-gate (CE_CONT, "fd_rawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0])); 20090Sstevel@tonic-gate 20100Sstevel@tonic-gate if (fjp->fj_chars->fdc_medium != 3 && fjp->fj_chars->fdc_medium != 5) { 20110Sstevel@tonic-gate cmn_err(CE_CONT, "fd_rawioctl: Medium density not supported\n"); 20120Sstevel@tonic-gate return (ENXIO); 20130Sstevel@tonic-gate } 20140Sstevel@tonic-gate 20150Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 20160Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 20170Sstevel@tonic-gate case DDI_MODEL_ILP32: 20180Sstevel@tonic-gate { 20190Sstevel@tonic-gate struct fd_raw32 fdr32; 20200Sstevel@tonic-gate 20210Sstevel@tonic-gate if (ddi_copyin(arg, &fdr32, sizeof (fdr32), mode)) 20220Sstevel@tonic-gate return (EFAULT); 20230Sstevel@tonic-gate 20240Sstevel@tonic-gate bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd)); 20250Sstevel@tonic-gate fdr.fdr_cnum = fdr32.fdr_cnum; 20260Sstevel@tonic-gate fdr.fdr_nbytes = fdr32.fdr_nbytes; 20270Sstevel@tonic-gate fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr; 20280Sstevel@tonic-gate arg_result = ((struct fd_raw32 *)arg)->fdr_result; 20290Sstevel@tonic-gate 20300Sstevel@tonic-gate break; 20310Sstevel@tonic-gate } 20320Sstevel@tonic-gate case DDI_MODEL_NONE: 20330Sstevel@tonic-gate #endif /* ! _MULTI_DATAMODEL */ 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate if (ddi_copyin(arg, &fdr, sizeof (fdr), mode)) 20360Sstevel@tonic-gate return (EFAULT); 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate arg_result = ((struct fd_raw *)arg)->fdr_result; 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 20410Sstevel@tonic-gate break; 20420Sstevel@tonic-gate } 20430Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 20440Sstevel@tonic-gate 20450Sstevel@tonic-gate 20460Sstevel@tonic-gate 20470Sstevel@tonic-gate /* 20480Sstevel@tonic-gate * copy user address & nbytes from raw_req so that we can 20490Sstevel@tonic-gate * put kernel address in req structure 20500Sstevel@tonic-gate */ 20510Sstevel@tonic-gate uaddr = fdr.fdr_addr; 20520Sstevel@tonic-gate ucount = (uint_t)fdr.fdr_nbytes; 20530Sstevel@tonic-gate unit &= 3; 20540Sstevel@tonic-gate 20550Sstevel@tonic-gate switch (fdr.fdr_cmd[0] & 0x0f) { 20560Sstevel@tonic-gate 20570Sstevel@tonic-gate case FDRAW_FORMAT: 20580Sstevel@tonic-gate ucount += 16; 20590Sstevel@tonic-gate fdr.fdr_addr = kmem_zalloc(ucount, KM_SLEEP); 20600Sstevel@tonic-gate if (ddi_copyin(uaddr, fdr.fdr_addr, 20610Sstevel@tonic-gate (size_t)fdr.fdr_nbytes, mode)) { 20620Sstevel@tonic-gate kmem_free(fdr.fdr_addr, ucount); 20630Sstevel@tonic-gate return (EFAULT); 20640Sstevel@tonic-gate } 20650Sstevel@tonic-gate if ((*fdr.fdr_addr | fdr.fdr_addr[1]) == 0) 20660Sstevel@tonic-gate fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 20670Sstevel@tonic-gate flag = B_WRITE; 20680Sstevel@tonic-gate fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 20690Sstevel@tonic-gate break; 20700Sstevel@tonic-gate 20710Sstevel@tonic-gate case FDRAW_WRCMD: 20720Sstevel@tonic-gate case FDRAW_WRITEDEL: 20730Sstevel@tonic-gate flag = B_WRITE; 20740Sstevel@tonic-gate /* FALLTHROUGH */ 20750Sstevel@tonic-gate case FDRAW_RDCMD: 20760Sstevel@tonic-gate case FDRAW_READDEL: 20770Sstevel@tonic-gate case FDRAW_READTRACK: 20780Sstevel@tonic-gate if (ucount) { 20790Sstevel@tonic-gate /* 20800Sstevel@tonic-gate * In SunOS 4.X, we used to as_fault things in. 20810Sstevel@tonic-gate * We really cannot do this in 5.0/SVr4. Unless 20820Sstevel@tonic-gate * someone really believes that speed is of the 20830Sstevel@tonic-gate * essence here, it is just much simpler to do 20840Sstevel@tonic-gate * this in kernel space and use copyin/copyout. 20850Sstevel@tonic-gate */ 20860Sstevel@tonic-gate fdr.fdr_addr = kmem_alloc((size_t)ucount, KM_SLEEP); 20870Sstevel@tonic-gate if (flag == B_WRITE) { 20880Sstevel@tonic-gate if (ddi_copyin(uaddr, fdr.fdr_addr, ucount, 20890Sstevel@tonic-gate mode)) { 20900Sstevel@tonic-gate kmem_free(fdr.fdr_addr, ucount); 20910Sstevel@tonic-gate return (EFAULT); 20920Sstevel@tonic-gate } 20930Sstevel@tonic-gate } 20940Sstevel@tonic-gate } else 20950Sstevel@tonic-gate return (EINVAL); 20960Sstevel@tonic-gate fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 20970Sstevel@tonic-gate break; 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate case FDRAW_READID: 21000Sstevel@tonic-gate case FDRAW_REZERO: 21010Sstevel@tonic-gate case FDRAW_SEEK: 21020Sstevel@tonic-gate case FDRAW_SENSE_DRV: 21030Sstevel@tonic-gate ucount = 0; 21040Sstevel@tonic-gate fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 21050Sstevel@tonic-gate break; 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate case FDRAW_SPECIFY: 21080Sstevel@tonic-gate fdr.fdr_cmd[2] &= 0xfe; /* keep NoDMA bit clear */ 21090Sstevel@tonic-gate /* FALLTHROUGH */ 21100Sstevel@tonic-gate case FDRAW_SENSE_INT: 21110Sstevel@tonic-gate ucount = 0; 21120Sstevel@tonic-gate break; 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate default: 21150Sstevel@tonic-gate return (EINVAL); 21160Sstevel@tonic-gate } 21170Sstevel@tonic-gate 21180Sstevel@tonic-gate /* 21190Sstevel@tonic-gate * Note that we ignore any error returns from controller 21200Sstevel@tonic-gate * This is the way the driver has been, and it may be 21210Sstevel@tonic-gate * that the raw ioctl senders simply don't want to 21220Sstevel@tonic-gate * see any errors returned in this fashion. 21230Sstevel@tonic-gate */ 21240Sstevel@tonic-gate 21250Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 21260Sstevel@tonic-gate rval = fjp->fj_ops->fco_rwioctl(fjp, unit, (caddr_t)&fdr); 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate if (ucount && flag == B_READ && rval == 0) { 21290Sstevel@tonic-gate if (ddi_copyout(fdr.fdr_addr, uaddr, ucount, mode)) { 21300Sstevel@tonic-gate rval = EFAULT; 21310Sstevel@tonic-gate } 21320Sstevel@tonic-gate } 21330Sstevel@tonic-gate if (ddi_copyout(fdr.fdr_result, arg_result, sizeof (fdr.fdr_cmd), mode)) 21340Sstevel@tonic-gate rval = EFAULT; 21350Sstevel@tonic-gate 21360Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 21370Sstevel@tonic-gate if (ucount) 21380Sstevel@tonic-gate kmem_free(fdr.fdr_addr, ucount); 21390Sstevel@tonic-gate 21400Sstevel@tonic-gate return (rval); 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate 21430Sstevel@tonic-gate /* 21440Sstevel@tonic-gate * property operation routine. return the number of blocks for the partition 21450Sstevel@tonic-gate * in question or forward the request to the property facilities. 21460Sstevel@tonic-gate */ 21470Sstevel@tonic-gate static int 21480Sstevel@tonic-gate fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 21490Sstevel@tonic-gate char *name, caddr_t valuep, int *lengthp) 21500Sstevel@tonic-gate { 21510Sstevel@tonic-gate struct fcu_obj *fjp = NULL; 21520Sstevel@tonic-gate struct fdisk *fdp = NULL; 21530Sstevel@tonic-gate uint64_t nblocks64; 21540Sstevel@tonic-gate 21550Sstevel@tonic-gate FDERRPRINT(FDEP_L1, FDEM_PROP, 21560Sstevel@tonic-gate (CE_CONT, "fd_prop_op: dip %p %s\n", (void *)dip, name)); 21570Sstevel@tonic-gate 21580Sstevel@tonic-gate /* 21590Sstevel@tonic-gate * Our dynamic properties are all device specific and size oriented. 21600Sstevel@tonic-gate * Requests issued under conditions where size is valid are passed 21610Sstevel@tonic-gate * to ddi_prop_op_nblocks with the size information, otherwise the 21620Sstevel@tonic-gate * request is passed to ddi_prop_op. 21630Sstevel@tonic-gate */ 21640Sstevel@tonic-gate if (dev == DDI_DEV_T_ANY) { 21650Sstevel@tonic-gate pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 21660Sstevel@tonic-gate name, valuep, lengthp)); 21670Sstevel@tonic-gate } else { 21680Sstevel@tonic-gate /* 21690Sstevel@tonic-gate * Ignoring return value because success is checked by 21700Sstevel@tonic-gate * verifying fjp and fdp and returned unit value is not used. 21710Sstevel@tonic-gate */ 21720Sstevel@tonic-gate (void) fd_getdrive(dev, &fjp, &fdp); 21730Sstevel@tonic-gate if (!fjp || !fdp) 21740Sstevel@tonic-gate goto pass; 21750Sstevel@tonic-gate 21760Sstevel@tonic-gate /* get nblocks value */ 21770Sstevel@tonic-gate nblocks64 = (ulong_t)fdp->d_part[PARTITION(dev)].p_size; 21780Sstevel@tonic-gate 21790Sstevel@tonic-gate return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags, 21800Sstevel@tonic-gate name, valuep, lengthp, nblocks64)); 21810Sstevel@tonic-gate } 21820Sstevel@tonic-gate } 21830Sstevel@tonic-gate 21840Sstevel@tonic-gate static void 21850Sstevel@tonic-gate fd_media_watch(void *arg) 21860Sstevel@tonic-gate { 21870Sstevel@tonic-gate struct fcu_obj *fjp; 21880Sstevel@tonic-gate struct fdisk *fdp; 21890Sstevel@tonic-gate 21900Sstevel@tonic-gate #ifdef DEBUG 21910Sstevel@tonic-gate int unit; 21920Sstevel@tonic-gate #define DEBUG_ASSIGN unit= 21930Sstevel@tonic-gate #else 21940Sstevel@tonic-gate #define DEBUG_ASSIGN (void) 21950Sstevel@tonic-gate #endif 21960Sstevel@tonic-gate DEBUG_ASSIGN fd_getdrive((dev_t)arg, &fjp, &fdp); 21970Sstevel@tonic-gate /* 21980Sstevel@tonic-gate * Ignoring return in non DEBUG mode because device exist. 21990Sstevel@tonic-gate * Returned unit value is not used. 22000Sstevel@tonic-gate */ 22010Sstevel@tonic-gate 22020Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_IOCT, 22030Sstevel@tonic-gate (CE_CONT, "fd_media_watch unit %d\n", unit)); 22040Sstevel@tonic-gate 22050Sstevel@tonic-gate /* 22060Sstevel@tonic-gate * fd_get_media_state() cannot be called from this timeout function 22070Sstevel@tonic-gate * because the floppy drive has to be selected first, and that could 22080Sstevel@tonic-gate * force this function to sleep (while waiting for the select 22090Sstevel@tonic-gate * semaphore). 22100Sstevel@tonic-gate * Instead, just wakeup up driver. 22110Sstevel@tonic-gate */ 22120Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 22130Sstevel@tonic-gate cv_broadcast(&fdp->d_statecv); 22140Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 22150Sstevel@tonic-gate } 22160Sstevel@tonic-gate 22170Sstevel@tonic-gate enum dkio_state 22180Sstevel@tonic-gate fd_get_media_state(struct fcu_obj *fjp, int unit) 22190Sstevel@tonic-gate { 22200Sstevel@tonic-gate enum dkio_state state; 22210Sstevel@tonic-gate 22220Sstevel@tonic-gate if (fjp->fj_ops->fco_getchng(fjp, unit)) { 22230Sstevel@tonic-gate /* recheck disk only if DSKCHG "high" */ 22240Sstevel@tonic-gate fjp->fj_ops->fco_resetchng(fjp, unit); 22250Sstevel@tonic-gate if (fjp->fj_ops->fco_getchng(fjp, unit)) { 22260Sstevel@tonic-gate if (fjp->fj_flags & FUNIT_CHGDET) { 22270Sstevel@tonic-gate /* 22280Sstevel@tonic-gate * again no diskette; not a new change 22290Sstevel@tonic-gate */ 22300Sstevel@tonic-gate state = DKIO_NONE; 22310Sstevel@tonic-gate } else { 22320Sstevel@tonic-gate /* 22330Sstevel@tonic-gate * a new change; diskette was ejected 22340Sstevel@tonic-gate */ 22350Sstevel@tonic-gate fjp->fj_flags |= FUNIT_CHGDET; 22360Sstevel@tonic-gate state = DKIO_EJECTED; 22370Sstevel@tonic-gate } 22380Sstevel@tonic-gate } else { 22390Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHGDET; 22400Sstevel@tonic-gate state = DKIO_INSERTED; 22410Sstevel@tonic-gate } 22420Sstevel@tonic-gate } else { 22430Sstevel@tonic-gate fjp->fj_flags &= ~FUNIT_CHGDET; 22440Sstevel@tonic-gate state = DKIO_INSERTED; 22450Sstevel@tonic-gate } 22460Sstevel@tonic-gate FDERRPRINT(FDEP_L0, FDEM_IOCT, 22470Sstevel@tonic-gate (CE_CONT, "fd_get_media_state unit %d: state %x\n", unit, state)); 22480Sstevel@tonic-gate return (state); 22490Sstevel@tonic-gate } 22500Sstevel@tonic-gate 22510Sstevel@tonic-gate static int 22520Sstevel@tonic-gate fd_check_media(dev_t dev, enum dkio_state state) 22530Sstevel@tonic-gate { 22540Sstevel@tonic-gate struct fcu_obj *fjp; 22550Sstevel@tonic-gate struct fdisk *fdp; 22560Sstevel@tonic-gate int unit; 22570Sstevel@tonic-gate int err; 22580Sstevel@tonic-gate 22590Sstevel@tonic-gate unit = fd_getdrive(dev, &fjp, &fdp); 22600Sstevel@tonic-gate 22610Sstevel@tonic-gate mutex_enter(&fjp->fj_lock); 22620Sstevel@tonic-gate 22630Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 22640Sstevel@tonic-gate fdp->d_media_state = fd_get_media_state(fjp, unit); 22650Sstevel@tonic-gate fdp->d_media_timeout = drv_usectohz(fd_check_media_time); 22660Sstevel@tonic-gate 22670Sstevel@tonic-gate while (fdp->d_media_state == state) { 22680Sstevel@tonic-gate /* release the controller and drive */ 22690Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 22700Sstevel@tonic-gate 22710Sstevel@tonic-gate /* turn on timer */ 22720Sstevel@tonic-gate fdp->d_media_timeout_id = timeout(fd_media_watch, 2273*7656SSherry.Moore@Sun.COM (void *)dev, fdp->d_media_timeout); 22740Sstevel@tonic-gate 22750Sstevel@tonic-gate if (cv_wait_sig(&fdp->d_statecv, &fjp->fj_lock) == 0) { 22760Sstevel@tonic-gate fdp->d_media_timeout = 0; 22770Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 22780Sstevel@tonic-gate return (EINTR); 22790Sstevel@tonic-gate } 22800Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 1); 22810Sstevel@tonic-gate fdp->d_media_state = fd_get_media_state(fjp, unit); 22820Sstevel@tonic-gate } 22830Sstevel@tonic-gate 22840Sstevel@tonic-gate if (fdp->d_media_state == DKIO_INSERTED) { 22850Sstevel@tonic-gate err = fdgetlabel(fjp, unit); 22860Sstevel@tonic-gate if (err) { 22870Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 22880Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 22890Sstevel@tonic-gate return (EIO); 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate } 22920Sstevel@tonic-gate fjp->fj_ops->fco_select(fjp, unit, 0); 22930Sstevel@tonic-gate mutex_exit(&fjp->fj_lock); 22940Sstevel@tonic-gate return (0); 22950Sstevel@tonic-gate } 22960Sstevel@tonic-gate 22970Sstevel@tonic-gate /* 22980Sstevel@tonic-gate * fd_get_media_info : 22990Sstevel@tonic-gate * Collects medium information for 23000Sstevel@tonic-gate * DKIOCGMEDIAINFO ioctl. 23010Sstevel@tonic-gate */ 23020Sstevel@tonic-gate 23030Sstevel@tonic-gate static int 23040Sstevel@tonic-gate fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag) 23050Sstevel@tonic-gate { 23060Sstevel@tonic-gate struct dk_minfo media_info; 23070Sstevel@tonic-gate int err = 0; 23080Sstevel@tonic-gate 23090Sstevel@tonic-gate media_info.dki_media_type = DK_FLOPPY; 23100Sstevel@tonic-gate media_info.dki_lbsize = fjp->fj_chars->fdc_sec_size; 23110Sstevel@tonic-gate media_info.dki_capacity = fjp->fj_chars->fdc_ncyl * 2312*7656SSherry.Moore@Sun.COM fjp->fj_chars->fdc_secptrack * fjp->fj_chars->fdc_nhead; 23130Sstevel@tonic-gate 23140Sstevel@tonic-gate if (ddi_copyout(&media_info, buf, sizeof (struct dk_minfo), flag)) 23150Sstevel@tonic-gate err = EFAULT; 23160Sstevel@tonic-gate return (err); 23170Sstevel@tonic-gate } 2318