1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 7656 Sherry * Common Development and Distribution License (the "License"). 6 7656 Sherry * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 7656 Sherry * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel 27 0 stevel /* 28 0 stevel * Floppy Disk driver 29 0 stevel */ 30 0 stevel 31 0 stevel /* 32 0 stevel * Set CMOS feature: 33 0 stevel * CMOS_CONF_MEM: CMOS memory contains configuration info 34 0 stevel */ 35 0 stevel #define CMOS_CONF_MEM 36 0 stevel 37 0 stevel #include <sys/types.h> 38 0 stevel #include <sys/param.h> 39 0 stevel #include <sys/systm.h> 40 0 stevel #include <sys/buf.h> 41 0 stevel #include <sys/file.h> 42 0 stevel #include <sys/open.h> 43 0 stevel #include <sys/ioctl.h> 44 0 stevel #include <sys/uio.h> 45 0 stevel #include <sys/conf.h> 46 0 stevel #include <sys/stat.h> 47 0 stevel #include <sys/autoconf.h> 48 0 stevel #include <sys/vtoc.h> 49 0 stevel #include <sys/dkio.h> 50 0 stevel #include <sys/ddi.h> 51 0 stevel #include <sys/sunddi.h> 52 0 stevel #include <sys/kstat.h> 53 0 stevel #include <sys/kmem.h> 54 0 stevel #include <sys/ddidmareq.h> 55 0 stevel #include <sys/fdio.h> 56 0 stevel #include <sys/fdc.h> 57 0 stevel #include <sys/fd_debug.h> 58 0 stevel #include <sys/fdmedia.h> 59 0 stevel #include <sys/debug.h> 60 0 stevel #include <sys/modctl.h> 61 0 stevel 62 0 stevel /* 63 0 stevel * Local Function Prototypes 64 0 stevel */ 65 0 stevel static int fd_unit_is_open(struct fdisk *); 66 0 stevel static int fdgetlabel(struct fcu_obj *, int); 67 0 stevel static void fdstart(struct fcu_obj *); 68 0 stevel static int fd_build_label_vtoc(struct fcu_obj *, struct fdisk *, 69 0 stevel struct vtoc *, struct dk_label *); 70 0 stevel static void fd_build_user_vtoc(struct fcu_obj *, struct fdisk *, 71 0 stevel struct vtoc *); 72 0 stevel static int fd_rawioctl(struct fcu_obj *, int, caddr_t, int); 73 0 stevel static void fd_media_watch(void *); 74 0 stevel 75 0 stevel static int fd_open(dev_t *, int, int, cred_t *); 76 0 stevel static int fd_close(dev_t, int, int, cred_t *); 77 0 stevel static int fd_strategy(struct buf *); 78 0 stevel static int fd_read(dev_t, struct uio *, cred_t *); 79 0 stevel static int fd_write(dev_t, struct uio *, cred_t *); 80 0 stevel static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 81 0 stevel static int fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 82 0 stevel caddr_t, int *); 83 0 stevel static int fd_check_media(dev_t dev, enum dkio_state state); 84 0 stevel static int fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag); 85 0 stevel 86 0 stevel static struct cb_ops fd_cb_ops = { 87 0 stevel fd_open, /* open */ 88 0 stevel fd_close, /* close */ 89 0 stevel fd_strategy, /* strategy */ 90 0 stevel nodev, /* print */ 91 0 stevel nodev, /* dump */ 92 0 stevel fd_read, /* read */ 93 0 stevel fd_write, /* write */ 94 0 stevel fd_ioctl, /* ioctl */ 95 0 stevel nodev, /* devmap */ 96 0 stevel nodev, /* mmap */ 97 0 stevel nodev, /* segmap */ 98 0 stevel nochpoll, /* poll */ 99 0 stevel fd_prop_op, /* cb_prop_op */ 100 0 stevel 0, /* streamtab */ 101 0 stevel D_NEW | D_MP /* Driver compatibility flag */ 102 0 stevel }; 103 0 stevel 104 0 stevel static int fd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 105 0 stevel static int fd_probe(dev_info_t *); 106 0 stevel static int fd_attach(dev_info_t *, ddi_attach_cmd_t); 107 0 stevel static int fd_detach(dev_info_t *, ddi_detach_cmd_t); 108 0 stevel 109 0 stevel static struct dev_ops fd_ops = { 110 0 stevel DEVO_REV, /* devo_rev, */ 111 0 stevel 0, /* refcnt */ 112 0 stevel fd_getinfo, /* getinfo */ 113 0 stevel nulldev, /* identify */ 114 0 stevel fd_probe, /* probe */ 115 0 stevel fd_attach, /* attach */ 116 0 stevel fd_detach, /* detach */ 117 0 stevel nodev, /* reset */ 118 0 stevel &fd_cb_ops, /* driver operations */ 119 7656 Sherry (struct bus_ops *)0, /* bus operations */ 120 7656 Sherry NULL, /* power */ 121 7656 Sherry ddi_quiesce_not_supported, /* devo_quiesce */ 122 0 stevel }; 123 0 stevel 124 0 stevel 125 0 stevel /* 126 0 stevel * static data 127 0 stevel */ 128 0 stevel static void *fd_state_head; /* opaque handle top of state structs */ 129 0 stevel static int fd_check_media_time = 5000000; /* 5 second state check */ 130 0 stevel 131 0 stevel /* 132 0 stevel * error handling 133 0 stevel * 134 0 stevel * for debugging, 135 0 stevel * set fderrlevel to 1 136 0 stevel * set fderrmask to 224 or 644 137 0 stevel */ 138 0 stevel #ifdef DEBUG 139 0 stevel static uint_t fderrmask = FDEM_ALL; 140 0 stevel #endif 141 0 stevel static int fderrlevel = 5; 142 0 stevel 143 0 stevel #define KIOSP KSTAT_IO_PTR(fdp->d_iostat) 144 0 stevel 145 0 stevel static struct driver_minor_data { 146 0 stevel char *name; 147 0 stevel int minor; 148 0 stevel int type; 149 0 stevel } fd_minor [] = { 150 0 stevel { "a", 0, S_IFBLK}, 151 0 stevel { "b", 1, S_IFBLK}, 152 0 stevel { "c", 2, S_IFBLK}, 153 0 stevel { "a,raw", 0, S_IFCHR}, 154 0 stevel { "b,raw", 1, S_IFCHR}, 155 0 stevel { "c,raw", 2, S_IFCHR}, 156 0 stevel {0} 157 0 stevel }; 158 0 stevel 159 0 stevel static struct modldrv modldrv = { 160 0 stevel &mod_driverops, /* Type of module. This one is a driver */ 161 7656 Sherry "Floppy Disk driver", /* Name of the module. */ 162 0 stevel &fd_ops, /* driver ops */ 163 0 stevel }; 164 0 stevel 165 0 stevel static struct modlinkage modlinkage = { 166 0 stevel MODREV_1, (void *)&modldrv, NULL 167 0 stevel }; 168 0 stevel 169 0 stevel 170 0 stevel int 171 0 stevel _init(void) 172 0 stevel { 173 0 stevel int retval; 174 0 stevel 175 0 stevel if ((retval = ddi_soft_state_init(&fd_state_head, 176 0 stevel sizeof (struct fdisk) + sizeof (struct fd_drive) + 177 0 stevel sizeof (struct fd_char) + sizeof (struct fdattr), 0)) != 0) 178 0 stevel return (retval); 179 0 stevel 180 0 stevel if ((retval = mod_install(&modlinkage)) != 0) 181 0 stevel ddi_soft_state_fini(&fd_state_head); 182 0 stevel return (retval); 183 0 stevel } 184 0 stevel 185 0 stevel int 186 0 stevel _fini(void) 187 0 stevel { 188 0 stevel int retval; 189 0 stevel 190 0 stevel if ((retval = mod_remove(&modlinkage)) != 0) 191 0 stevel return (retval); 192 0 stevel ddi_soft_state_fini(&fd_state_head); 193 0 stevel return (retval); 194 0 stevel } 195 0 stevel 196 0 stevel int 197 0 stevel _info(struct modinfo *modinfop) 198 0 stevel { 199 0 stevel return (mod_info(&modlinkage, modinfop)); 200 0 stevel } 201 0 stevel 202 0 stevel 203 0 stevel static int 204 0 stevel fd_getdrive(dev_t dev, struct fcu_obj **fjpp, struct fdisk **fdpp) 205 0 stevel { 206 0 stevel if (fdpp) { 207 0 stevel *fdpp = ddi_get_soft_state(fd_state_head, DRIVE(dev)); 208 0 stevel if (*fdpp && fjpp) { 209 0 stevel *fjpp = (*fdpp)->d_obj; 210 0 stevel if (*fjpp) 211 0 stevel return ((*fjpp)->fj_unit); 212 0 stevel } 213 0 stevel } 214 0 stevel return (-1); 215 0 stevel } 216 0 stevel 217 0 stevel /*ARGSUSED*/ 218 0 stevel static int 219 0 stevel fd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 220 0 stevel { 221 0 stevel dev_t dev = (dev_t)arg; 222 0 stevel struct fcu_obj *fjp = NULL; 223 0 stevel struct fdisk *fdp = NULL; 224 0 stevel int rval; 225 0 stevel 226 0 stevel switch (cmd) { 227 0 stevel case DDI_INFO_DEVT2DEVINFO: 228 0 stevel (void) fd_getdrive(dev, &fjp, &fdp); 229 0 stevel /* 230 0 stevel * Ignoring return value because success is checked by 231 0 stevel * verifying fjp and fdp and returned unit value is not used. 232 0 stevel */ 233 0 stevel if (fjp && fdp) { 234 0 stevel *result = fjp->fj_dip; 235 0 stevel rval = DDI_SUCCESS; 236 0 stevel } else 237 0 stevel rval = DDI_FAILURE; 238 0 stevel break; 239 0 stevel case DDI_INFO_DEVT2INSTANCE: 240 0 stevel *result = (void *)(uintptr_t)DRIVE(dev); 241 0 stevel rval = DDI_SUCCESS; 242 0 stevel break; 243 0 stevel default: 244 0 stevel rval = DDI_FAILURE; 245 0 stevel } 246 0 stevel return (rval); 247 0 stevel } 248 0 stevel 249 0 stevel #ifdef CMOS_CONF_MEM 250 0 stevel #define CMOS_ADDR 0x70 251 0 stevel #define CMOS_DATA 0x71 252 0 stevel #define CMOS_FDRV 0x10 253 0 stevel #endif /* CMOS_CONF_MEM */ 254 0 stevel 255 0 stevel static int 256 0 stevel fd_probe(dev_info_t *dip) 257 0 stevel { 258 0 stevel #ifdef CMOS_CONF_MEM 259 0 stevel int cmos; 260 0 stevel int drive_type; 261 0 stevel #endif /* CMOS_CONF_MEM */ 262 0 stevel int debug[2]; 263 0 stevel int drive_size; 264 0 stevel int len; 265 0 stevel int unit_num; 266 0 stevel char density[8]; 267 0 stevel 268 0 stevel len = sizeof (debug); 269 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 270 0 stevel DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) == 271 0 stevel DDI_PROP_SUCCESS) { 272 0 stevel fderrlevel = debug[0]; 273 0 stevel #ifdef DEBUG 274 0 stevel fderrmask = (uint_t)debug[1]; 275 0 stevel #endif 276 0 stevel } 277 0 stevel len = sizeof (unit_num); 278 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 279 0 stevel DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) != 280 0 stevel DDI_PROP_SUCCESS) { 281 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 282 0 stevel (CE_WARN, "fd_probe failed: dip %p", (void *)dip)); 283 0 stevel return (DDI_PROBE_FAILURE); 284 0 stevel } 285 0 stevel 286 0 stevel #ifdef CMOS_CONF_MEM 287 0 stevel /* get the cmos memory values quick and dirty */ 288 0 stevel outb(CMOS_ADDR, CMOS_FDRV); 289 0 stevel cmos = drive_type = (int)inb(CMOS_DATA); 290 0 stevel #endif /* CMOS_CONF_MEM */ 291 0 stevel 292 0 stevel switch (unit_num) { 293 0 stevel #ifdef CMOS_CONF_MEM 294 0 stevel case 0: 295 0 stevel drive_type = drive_type >> 4; 296 0 stevel /* FALLTHROUGH */ 297 0 stevel case 1: 298 0 stevel if (cmos && (drive_type & 0x0F)) { 299 0 stevel break; 300 0 stevel } 301 0 stevel /* 302 0 stevel * Some enhanced floppy-disk controller adaptor cards 303 0 stevel * require NO drives defined in the CMOS configuration 304 0 stevel * memory. 305 0 stevel * So fall through 306 0 stevel */ 307 0 stevel #endif /* CMOS_CONF_MEM */ 308 0 stevel default: /* need to check conf file */ 309 0 stevel len = sizeof (density); 310 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 311 0 stevel DDI_PROP_DONTPASS, "density", (caddr_t)&density, &len) != 312 0 stevel DDI_PROP_SUCCESS) { 313 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 314 0 stevel (CE_WARN, 315 0 stevel "fd_probe failed density: dip %p unit %d", 316 0 stevel (void *)dip, unit_num)); 317 0 stevel return (DDI_PROBE_FAILURE); 318 0 stevel } 319 0 stevel len = sizeof (drive_size); 320 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 321 0 stevel DDI_PROP_DONTPASS, "size", (caddr_t)&drive_size, &len) != 322 0 stevel DDI_PROP_SUCCESS) { 323 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 324 0 stevel (CE_WARN, "fd_probe failed size: dip %p unit %d", 325 0 stevel (void *)dip, unit_num)); 326 0 stevel return (DDI_PROBE_FAILURE); 327 0 stevel } 328 0 stevel } 329 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 330 0 stevel (CE_WARN, "fd_probe dip %p unit %d", (void *)dip, unit_num)); 331 0 stevel return (DDI_PROBE_SUCCESS); 332 0 stevel } 333 0 stevel 334 0 stevel 335 0 stevel /* ARGSUSED */ 336 0 stevel static int 337 0 stevel fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 338 0 stevel { 339 0 stevel struct fcu_obj *fjp; 340 0 stevel struct fdisk *fdp; 341 0 stevel struct driver_minor_data *dmdp; 342 0 stevel int mode_3D; 343 0 stevel int drive_num, drive_size, drive_type; 344 0 stevel #ifdef CMOS_CONF_MEM 345 0 stevel int cmos; 346 0 stevel #endif /* CMOS_CONF_MEM */ 347 0 stevel int len, sig_minor; 348 0 stevel int unit_num; 349 0 stevel char density[8]; 350 0 stevel char name[MAXNAMELEN]; 351 0 stevel 352 0 stevel switch (cmd) { 353 0 stevel case DDI_ATTACH: 354 0 stevel len = sizeof (unit_num); 355 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 356 0 stevel DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) != 357 0 stevel DDI_PROP_SUCCESS) { 358 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 359 0 stevel (CE_WARN, "fd_attach failed: dip %p", (void *)dip)); 360 0 stevel return (DDI_FAILURE); 361 0 stevel } 362 0 stevel 363 0 stevel #ifdef CMOS_CONF_MEM 364 0 stevel outb(CMOS_ADDR, CMOS_FDRV); 365 0 stevel cmos = drive_type = (int)inb(CMOS_DATA); 366 0 stevel #endif /* CMOS_CONF_MEM */ 367 0 stevel 368 0 stevel switch (unit_num) { 369 0 stevel #ifdef CMOS_CONF_MEM 370 0 stevel case 0: 371 0 stevel drive_type = drive_type >> 4; 372 0 stevel /* FALLTHROUGH */ 373 0 stevel case 1: 374 0 stevel drive_type = drive_type & 0x0F; 375 0 stevel if (cmos) 376 0 stevel break; 377 0 stevel /* 378 0 stevel * Some enhanced floppy-disk controller adaptor cards 379 0 stevel * require NO drives defined in the CMOS configuration 380 0 stevel * memory. 381 0 stevel * So fall through 382 0 stevel */ 383 0 stevel #endif /* CMOS_CONF_MEM */ 384 0 stevel default: /* need to check .conf file */ 385 0 stevel drive_type = 0; 386 0 stevel len = sizeof (density); 387 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, 388 0 stevel PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "density", 389 0 stevel (caddr_t)&density, &len) != DDI_PROP_SUCCESS) 390 0 stevel density[0] = '\0'; 391 0 stevel len = sizeof (drive_size); 392 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, 393 0 stevel PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "size", 394 0 stevel (caddr_t)&drive_size, &len) != DDI_PROP_SUCCESS) 395 0 stevel drive_size = 0; 396 0 stevel if (strcmp(density, "DSDD") == 0) { 397 0 stevel if (drive_size == 5) 398 0 stevel drive_type = 1; 399 0 stevel else if (drive_size == 3) 400 0 stevel drive_type = 3; 401 0 stevel } else if (strcmp(density, "DSHD") == 0) { 402 0 stevel if (drive_size == 5) 403 0 stevel drive_type = 2; 404 0 stevel else if (drive_size == 3) 405 0 stevel drive_type = 4; 406 0 stevel } else if (strcmp(density, "DSED") == 0 && 407 0 stevel drive_size == 3) { 408 0 stevel drive_type = 6; 409 0 stevel } 410 0 stevel break; 411 0 stevel } 412 0 stevel if (drive_type == 0) { 413 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 414 0 stevel (CE_WARN, "fd_attach failed type: dip %p unit %d", 415 0 stevel (void *)dip, unit_num)); 416 0 stevel return (DDI_FAILURE); 417 0 stevel } 418 0 stevel 419 0 stevel drive_num = ddi_get_instance(dip); 420 0 stevel if (ddi_soft_state_zalloc(fd_state_head, drive_num) != 0) 421 0 stevel return (DDI_FAILURE); 422 0 stevel fdp = ddi_get_soft_state(fd_state_head, drive_num); 423 0 stevel fjp = fdp->d_obj = ddi_get_driver_private(dip); 424 0 stevel 425 0 stevel mutex_init(&fjp->fj_lock, NULL, MUTEX_DRIVER, *fjp->fj_iblock); 426 0 stevel sema_init(&fdp->d_ocsem, 1, NULL, SEMA_DRIVER, NULL); 427 0 stevel 428 0 stevel fjp->fj_drive = (struct fd_drive *)(fdp + 1); 429 0 stevel fjp->fj_chars = (struct fd_char *)(fjp->fj_drive + 1); 430 0 stevel fjp->fj_attr = (struct fdattr *)(fjp->fj_chars + 1); 431 0 stevel 432 0 stevel /* 433 0 stevel * set default floppy drive characteristics & geometry 434 0 stevel */ 435 0 stevel switch (drive_type) { /* assume doubled sided */ 436 0 stevel case 2: /* 5.25 high density */ 437 0 stevel *fjp->fj_drive = dfd_525HD; 438 0 stevel fdp->d_media = 1<<FMT_5H | 1<<FMT_5D9 | 1<<FMT_5D8 | 439 0 stevel 1<<FMT_5D4 | 1<<FMT_5D16; 440 0 stevel fdp->d_deffdtype = fdp->d_curfdtype = FMT_5H; 441 0 stevel break; 442 0 stevel case 4: /* 3.5 high density */ 443 0 stevel *fjp->fj_drive = dfd_350HD; 444 0 stevel fdp->d_media = 1<<FMT_3H | 1<<FMT_3I | 1<<FMT_3D; 445 0 stevel len = sizeof (mode_3D); 446 0 stevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, 447 0 stevel PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "mode_3D", 448 0 stevel (caddr_t)&mode_3D, &len) != DDI_PROP_SUCCESS) 449 0 stevel mode_3D = 0; 450 0 stevel if (mode_3D && (fjp->fj_fdc->c_flags & FCFLG_3DMODE)) 451 0 stevel /* 452 0 stevel * 3D mode should be enabled only if a dual- 453 0 stevel * speed 3.5" high-density drive and a 454 0 stevel * supported floppy controller are installed. 455 0 stevel */ 456 0 stevel fdp->d_media |= 1 << FMT_3M; 457 0 stevel fdp->d_deffdtype = fdp->d_curfdtype = FMT_3H; 458 0 stevel break; 459 0 stevel case 1: /* 5.25 double density */ 460 0 stevel *fjp->fj_drive = dfd_525DD; 461 0 stevel fdp->d_media = 1<<FMT_5D9 | 1<<FMT_5D8 | 1<<FMT_5D4 | 462 0 stevel 1<<FMT_5D16; 463 0 stevel fdp->d_deffdtype = fdp->d_curfdtype = FMT_5D9; 464 0 stevel break; 465 0 stevel case 3: /* 3.5 double density */ 466 0 stevel *fjp->fj_drive = dfd_350HD; 467 0 stevel fdp->d_media = 1<<FMT_3D; 468 0 stevel fdp->d_deffdtype = fdp->d_curfdtype = FMT_3D; 469 0 stevel break; 470 0 stevel case 5: /* 3.5 extended density */ 471 0 stevel case 6: 472 0 stevel case 7: 473 0 stevel *fjp->fj_drive = dfd_350ED; 474 0 stevel fdp->d_media = 1<<FMT_3E | 1<<FMT_3H | 1<<FMT_3I | 475 0 stevel 1<<FMT_3D; 476 0 stevel fdp->d_deffdtype = fdp->d_curfdtype = FMT_3E; 477 0 stevel break; 478 0 stevel case 0: /* no drive defined */ 479 0 stevel default: 480 0 stevel goto no_attach; 481 0 stevel } 482 0 stevel *fjp->fj_chars = *defchar[fdp->d_deffdtype]; 483 0 stevel *fjp->fj_attr = fdtypes[fdp->d_deffdtype]; 484 0 stevel bcopy(fdparts[fdp->d_deffdtype], fdp->d_part, 485 0 stevel sizeof (struct partition) * NDKMAP); 486 0 stevel fjp->fj_rotspd = fdtypes[fdp->d_deffdtype].fda_rotatespd; 487 0 stevel 488 0 stevel sig_minor = drive_num << 3; 489 0 stevel for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) { 490 0 stevel if (ddi_create_minor_node(dip, dmdp->name, dmdp->type, 491 0 stevel sig_minor | dmdp->minor, DDI_NT_FD, NULL) 492 0 stevel == DDI_FAILURE) { 493 0 stevel ddi_remove_minor_node(dip, NULL); 494 0 stevel goto no_attach; 495 0 stevel } 496 0 stevel } 497 0 stevel 498 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 499 0 stevel (CE_WARN, "fd_attach: dip %p unit %d", 500 0 stevel (void *)dip, unit_num)); 501 0 stevel (void) sprintf(name, "fd%d", drive_num); 502 0 stevel fdp->d_iostat = kstat_create("fd", drive_num, name, "disk", 503 0 stevel KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 504 0 stevel if (fdp->d_iostat) { 505 0 stevel fdp->d_iostat->ks_lock = &fjp->fj_lock; 506 0 stevel kstat_install(fdp->d_iostat); 507 0 stevel } 508 0 stevel 509 0 stevel fjp->fj_data = (caddr_t)fdp; 510 0 stevel fjp->fj_flags |= FUNIT_DRVATCH; 511 0 stevel 512 0 stevel /* 513 0 stevel * Add a zero-length attribute to tell the world we support 514 0 stevel * kernel ioctls (for layered drivers) 515 0 stevel */ 516 0 stevel (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 517 0 stevel DDI_KERNEL_IOCTL, NULL, 0); 518 8258 gdamore 519 8258 gdamore /* 520 8258 gdamore * We want to get suspend/resume events, so that we can 521 8258 gdamore * refuse to suspend when pcfs is mounted. 522 8258 gdamore */ 523 8258 gdamore (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 524 8258 gdamore "pm-hardware-state", "needs-suspend-resume"); 525 8258 gdamore 526 0 stevel /* 527 0 stevel * Ignoring return value because, for passed arguments, only 528 0 stevel * DDI_SUCCESS is returned. 529 0 stevel */ 530 0 stevel ddi_report_dev(dip); 531 0 stevel return (DDI_SUCCESS); 532 0 stevel 533 0 stevel case DDI_RESUME: 534 8258 gdamore /* nothing for us to do */ 535 0 stevel return (DDI_SUCCESS); 536 0 stevel 537 0 stevel default: 538 0 stevel return (DDI_FAILURE); 539 0 stevel } 540 0 stevel no_attach: 541 0 stevel fjp->fj_drive = NULL; 542 0 stevel fjp->fj_chars = NULL; 543 0 stevel fjp->fj_attr = NULL; 544 0 stevel mutex_destroy(&fjp->fj_lock); 545 0 stevel sema_destroy(&fdp->d_ocsem); 546 0 stevel ddi_soft_state_free(fd_state_head, drive_num); 547 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, 548 0 stevel (CE_WARN, "fd_attach failed: dip %p unit %d", 549 0 stevel (void *)dip, unit_num)); 550 0 stevel return (DDI_FAILURE); 551 0 stevel } 552 0 stevel 553 0 stevel 554 0 stevel /* ARGSUSED */ 555 0 stevel static int 556 0 stevel fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 557 0 stevel { 558 0 stevel struct fcu_obj *fjp; 559 0 stevel struct fdisk *fdp; 560 0 stevel int drive_num; 561 0 stevel int rval = DDI_SUCCESS; 562 0 stevel 563 0 stevel FDERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fd_detach dip %p", 564 7656 Sherry (void *)dip)); 565 0 stevel 566 0 stevel drive_num = ddi_get_instance(dip); 567 0 stevel if (!(fdp = ddi_get_soft_state(fd_state_head, drive_num))) 568 0 stevel return (rval); 569 0 stevel 570 0 stevel switch (cmd) { 571 0 stevel case DDI_DETACH: 572 0 stevel if (fd_unit_is_open(fdp)) { 573 8258 gdamore rval = DDI_FAILURE; 574 0 stevel break; 575 0 stevel } 576 0 stevel kstat_delete(fdp->d_iostat); 577 0 stevel fdp->d_iostat = NULL; 578 0 stevel fjp = (struct fcu_obj *)fdp->d_obj; 579 8258 gdamore fjp->fj_flags &= ~FUNIT_DRVATCH; 580 0 stevel fjp->fj_data = NULL; 581 0 stevel fjp->fj_drive = NULL; 582 0 stevel fjp->fj_chars = NULL; 583 0 stevel fjp->fj_attr = NULL; 584 0 stevel ddi_prop_remove_all(dip); 585 0 stevel mutex_destroy(&fjp->fj_lock); 586 0 stevel sema_destroy(&fdp->d_ocsem); 587 0 stevel ddi_soft_state_free(fd_state_head, drive_num); 588 0 stevel break; 589 0 stevel 590 0 stevel case DDI_SUSPEND: 591 8258 gdamore /* 592 8258 gdamore * Bad, bad, bad things will happen if someone 593 8258 gdamore * *changes* the disk in the drive while it is mounted 594 8258 gdamore * and the system is suspended. We have no way to 595 8258 gdamore * detect that. (Undetected filesystem corruption. 596 8258 gdamore * Its akin to changing the boot disk while the system 597 8258 gdamore * is suspended. Don't do it!) 598 8258 gdamore * 599 8258 gdamore * So we refuse to suspend if there is a mounted filesystem. 600 8258 gdamore * (We guess this by looking for a block open. Character 601 8258 gdamore * opens are fine.) This limits some of the usability of 602 8258 gdamore * suspend/resume, but it certainly avoids this 603 8258 gdamore * potential filesytem corruption from pilot error. 604 8258 gdamore * Given the decreasing popularity of floppy media, we 605 8258 gdamore * don't see this as much of a limitation. 606 8258 gdamore */ 607 8258 gdamore if (fdp->d_regopen[OTYP_BLK]) { 608 8258 gdamore cmn_err(CE_NOTE, 609 8258 gdamore "Unable to suspend while floppy is in use."); 610 8258 gdamore rval = DDI_FAILURE; 611 0 stevel } 612 0 stevel break; 613 0 stevel 614 0 stevel default: 615 8258 gdamore rval = DDI_FAILURE; 616 0 stevel break; 617 0 stevel } 618 0 stevel return (rval); 619 0 stevel } 620 0 stevel 621 0 stevel 622 0 stevel static int 623 0 stevel fd_part_is_open(struct fdisk *fdp, int part) 624 0 stevel { 625 0 stevel int i; 626 0 stevel 627 0 stevel for (i = 0; i < (OTYPCNT - 1); i++) 628 0 stevel if (fdp->d_regopen[i] & (1 << part)) 629 0 stevel return (1); 630 0 stevel return (0); 631 0 stevel } 632 0 stevel 633 0 stevel static int 634 0 stevel fd_unit_is_open(struct fdisk *fdp) 635 0 stevel { 636 0 stevel int i; 637 0 stevel 638 0 stevel for (i = 0; i < NDKMAP; i++) 639 0 stevel if (fdp->d_lyropen[i]) 640 0 stevel return (1); 641 0 stevel for (i = 0; i < (OTYPCNT - 1); i++) 642 0 stevel if (fdp->d_regopen[i]) 643 0 stevel return (1); 644 0 stevel return (0); 645 0 stevel } 646 0 stevel 647 0 stevel /*ARGSUSED*/ 648 0 stevel static int 649 0 stevel fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 650 0 stevel { 651 0 stevel struct fcu_obj *fjp = NULL; 652 0 stevel struct fdisk *fdp = NULL; 653 0 stevel struct partition *pp; 654 0 stevel dev_t dev; 655 0 stevel int part, unit; 656 0 stevel int part_is_open; 657 0 stevel int rval; 658 0 stevel uint_t pbit; 659 0 stevel 660 0 stevel dev = *devp; 661 0 stevel unit = fd_getdrive(dev, &fjp, &fdp); 662 0 stevel if (!fjp || !fdp) 663 0 stevel return (ENXIO); 664 0 stevel part = PARTITION(dev); 665 0 stevel pbit = 1 << part; 666 0 stevel pp = &fdp->d_part[part]; 667 0 stevel 668 0 stevel /* 669 0 stevel * Serialize opens/closes 670 0 stevel */ 671 0 stevel sema_p(&fdp->d_ocsem); 672 0 stevel FDERRPRINT(FDEP_L1, FDEM_OPEN, 673 0 stevel (CE_CONT, "fd_open: fd%d part %d flag %x otype %x\n", DRIVE(dev), 674 0 stevel part, flag, otyp)); 675 0 stevel 676 0 stevel /* 677 0 stevel * Check for previous exclusive open, or trying to exclusive open 678 0 stevel * An "exclusive open" on any partition is not guaranteed to 679 0 stevel * protect against opens on another partition that overlaps it. 680 0 stevel */ 681 0 stevel if (otyp == OTYP_LYR) { 682 0 stevel part_is_open = (fdp->d_lyropen[part] != 0); 683 0 stevel } else { 684 0 stevel part_is_open = fd_part_is_open(fdp, part); 685 0 stevel } 686 0 stevel if ((fdp->d_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) { 687 0 stevel FDERRPRINT(FDEP_L0, FDEM_OPEN, (CE_CONT, 688 0 stevel "fd_open: exclparts %lx openparts %lx lyrcnt %lx pbit %x\n", 689 0 stevel fdp->d_exclmask, fdp->d_regopen[otyp], fdp->d_lyropen[part], 690 0 stevel pbit)); 691 0 stevel sema_v(&fdp->d_ocsem); 692 0 stevel return (EBUSY); 693 0 stevel } 694 0 stevel 695 0 stevel /* 696 0 stevel * Ensure that drive is recalibrated on first open of new diskette. 697 0 stevel */ 698 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 699 0 stevel if (fjp->fj_ops->fco_getchng(fjp, unit) != 0) { 700 0 stevel if (fjp->fj_ops->fco_rcseek(fjp, unit, -1, 0)) { 701 0 stevel FDERRPRINT(FDEP_L2, FDEM_OPEN, 702 0 stevel (CE_NOTE, "fd_open fd%d: not ready", DRIVE(dev))); 703 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 704 0 stevel sema_v(&fdp->d_ocsem); 705 0 stevel return (ENXIO); 706 0 stevel } 707 0 stevel fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 708 0 stevel } 709 0 stevel if (flag & (FNDELAY | FNONBLOCK)) { 710 0 stevel /* don't attempt access, just return successfully */ 711 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 712 0 stevel goto out; 713 0 stevel } 714 0 stevel 715 0 stevel /* 716 0 stevel * auto-sense the density/format of the diskette 717 0 stevel */ 718 0 stevel rval = fdgetlabel(fjp, unit); 719 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 720 0 stevel if (rval) { 721 0 stevel /* didn't find label (couldn't read anything) */ 722 0 stevel FDERRPRINT(FDEP_L2, FDEM_OPEN, 723 0 stevel (CE_NOTE, "fd%d: drive not ready", DRIVE(dev))); 724 0 stevel sema_v(&fdp->d_ocsem); 725 0 stevel return (EIO); 726 0 stevel } 727 0 stevel /* check partition */ 728 0 stevel if (pp->p_size == 0) { 729 0 stevel sema_v(&fdp->d_ocsem); 730 0 stevel return (ENXIO); 731 0 stevel } 732 0 stevel /* 733 0 stevel * if opening for writing, check write protect on diskette 734 0 stevel */ 735 0 stevel if ((flag & FWRITE) && (fdp->d_obj->fj_flags & FUNIT_WPROT)) { 736 0 stevel sema_v(&fdp->d_ocsem); 737 0 stevel return (EROFS); 738 0 stevel } 739 0 stevel 740 0 stevel out: 741 0 stevel /* 742 0 stevel * mark open as having succeeded 743 0 stevel */ 744 0 stevel if (flag & FEXCL) 745 0 stevel fdp->d_exclmask |= pbit; 746 0 stevel if (otyp == OTYP_LYR) 747 0 stevel fdp->d_lyropen[part]++; 748 0 stevel else 749 0 stevel fdp->d_regopen[otyp] |= 1 << part; 750 0 stevel 751 0 stevel sema_v(&fdp->d_ocsem); 752 0 stevel return (0); 753 0 stevel } 754 0 stevel 755 0 stevel /* 756 0 stevel * fdgetlabel - read the SunOS label off the diskette 757 0 stevel * if it can read a valid label it does so, else it will use a 758 0 stevel * default. If it can`t read the diskette - that is an error. 759 0 stevel * 760 0 stevel * RETURNS: 0 for ok - meaning that it could at least read the device, 761 0 stevel * !0 for error XXX TBD NYD error codes 762 0 stevel */ 763 0 stevel static int 764 0 stevel fdgetlabel(struct fcu_obj *fjp, int unit) 765 0 stevel { 766 0 stevel struct dk_label *label; 767 0 stevel struct fdisk *fdp; 768 0 stevel char *newlabel; 769 0 stevel short *sp; 770 0 stevel short count; 771 0 stevel short xsum; 772 0 stevel int tries, try_this; 773 0 stevel uint_t nexttype; 774 0 stevel int rval; 775 0 stevel short oldlvl; 776 0 stevel int i; 777 0 stevel 778 0 stevel FDERRPRINT(FDEP_L0, FDEM_GETL, 779 0 stevel (CE_CONT, "fdgetlabel fd unit %d\n", unit)); 780 0 stevel fdp = (struct fdisk *)fjp->fj_data; 781 0 stevel fjp->fj_flags &= ~(FUNIT_UNLABELED); 782 0 stevel 783 0 stevel /* 784 0 stevel * get some space to play with the label 785 0 stevel */ 786 0 stevel label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 787 0 stevel FDERRPRINT(FDEP_L0, FDEM_GETL, (CE_CONT, 788 0 stevel "fdgetlabel fd unit %d kmem_zalloc: ptr = %p, size = %lx\n", 789 0 stevel unit, (void *)label, (size_t)sizeof (struct dk_label))); 790 0 stevel 791 0 stevel /* 792 0 stevel * read block 0 (0/0/1) to find the label 793 0 stevel * (disk is potentially not present or unformatted) 794 0 stevel */ 795 0 stevel /* noerrprint since this is a private cmd */ 796 0 stevel oldlvl = fderrlevel; 797 0 stevel fderrlevel = FDEP_LMAX; 798 0 stevel /* 799 0 stevel * try different characteristics (ie densities) 800 0 stevel * 801 0 stevel * if fdp->d_curfdtype is -1 then the current characteristics 802 0 stevel * were set by ioctl and need to try it as well as everything 803 0 stevel * in the table 804 0 stevel */ 805 0 stevel nexttype = fdp->d_deffdtype; 806 0 stevel try_this = 1; /* always try the current characteristics */ 807 0 stevel 808 0 stevel for (tries = nfdtypes; tries; tries--) { 809 0 stevel if (try_this) { 810 0 stevel fjp->fj_flags &= ~FUNIT_CHAROK; 811 0 stevel 812 0 stevel /* try reading last sector of cyl 1, head 0 */ 813 0 stevel if (!(rval = fjp->fj_ops->fco_rw(fjp, unit, 814 0 stevel FDREAD, 1, 0, fjp->fj_chars->fdc_secptrack, 815 0 stevel (caddr_t)label, 816 0 stevel sizeof (struct dk_label))) && 817 0 stevel /* and last sector plus 1 of cylinder 1 */ 818 0 stevel fjp->fj_ops->fco_rw(fjp, unit, FDREAD, 1, 819 0 stevel 0, fjp->fj_chars->fdc_secptrack + 1, 820 0 stevel (caddr_t)label, 821 0 stevel sizeof (struct dk_label)) && 822 0 stevel /* and label sector on cylinder 0 */ 823 0 stevel !(rval = fjp->fj_ops->fco_rw(fjp, unit, 824 0 stevel FDREAD, 0, 0, 1, (caddr_t)label, 825 0 stevel sizeof (struct dk_label)))) 826 0 stevel break; 827 0 stevel if (rval == ENXIO) 828 0 stevel break; 829 0 stevel } 830 0 stevel /* 831 0 stevel * try the next entry in the characteristics tbl 832 0 stevel */ 833 0 stevel fdp->d_curfdtype = (signed char)nexttype; 834 0 stevel nexttype = (nexttype + 1) % nfdtypes; 835 0 stevel if ((1 << fdp->d_curfdtype) & fdp->d_media) { 836 0 stevel *fjp->fj_chars = *defchar[fdp->d_curfdtype]; 837 0 stevel *fjp->fj_attr = fdtypes[fdp->d_curfdtype]; 838 0 stevel bcopy(fdparts[fdp->d_curfdtype], fdp->d_part, 839 0 stevel sizeof (struct partition) * NDKMAP); 840 0 stevel /* 841 0 stevel * check for a double_density diskette 842 0 stevel * in a high_density 5.25" drive 843 0 stevel */ 844 0 stevel if (fjp->fj_chars->fdc_transfer_rate == 250 && 845 0 stevel fjp->fj_rotspd > fjp->fj_attr->fda_rotatespd) { 846 0 stevel /* 847 0 stevel * yes - adjust transfer rate since we don't 848 0 stevel * know if we have a 5.25" dual-speed drive 849 0 stevel */ 850 0 stevel fjp->fj_attr->fda_rotatespd = 360; 851 0 stevel fjp->fj_chars->fdc_transfer_rate = 300; 852 0 stevel fjp->fj_chars->fdc_medium = 5; 853 0 stevel } 854 0 stevel if ((2 * fjp->fj_chars->fdc_ncyl) == 855 0 stevel defchar[fdp->d_deffdtype]->fdc_ncyl) { 856 0 stevel /* yes - adjust steps per cylinder */ 857 0 stevel fjp->fj_chars->fdc_steps = 2; 858 0 stevel } else 859 0 stevel fjp->fj_chars->fdc_steps = 1; 860 0 stevel try_this = 1; 861 0 stevel } else 862 0 stevel try_this = 0; 863 0 stevel } 864 0 stevel fderrlevel = oldlvl; /* print errors again */ 865 0 stevel 866 0 stevel if (rval) { 867 0 stevel fdp->d_curfdtype = fdp->d_deffdtype; 868 0 stevel goto out; /* couldn't read anything */ 869 0 stevel } 870 0 stevel 871 0 stevel FDERRPRINT(FDEP_L0, FDEM_GETL, 872 0 stevel (CE_CONT, 873 0 stevel "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n", 874 0 stevel unit, fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_secptrack, 875 0 stevel fjp->fj_chars->fdc_steps, fjp->fj_attr->fda_rotatespd, 876 0 stevel fjp->fj_attr->fda_intrlv)); 877 0 stevel 878 0 stevel /* 879 0 stevel * _something_ was read - look for unixtype label 880 0 stevel */ 881 0 stevel if (label->dkl_magic != DKL_MAGIC || 882 0 stevel label->dkl_vtoc.v_sanity != VTOC_SANE) { 883 0 stevel /* not a label - no magic number */ 884 0 stevel goto nolabel; /* no errors, but no label */ 885 0 stevel } 886 0 stevel 887 0 stevel count = sizeof (struct dk_label) / sizeof (short); 888 0 stevel sp = (short *)label; 889 0 stevel xsum = 0; 890 0 stevel while (count--) 891 0 stevel xsum ^= *sp++; /* should add up to 0 */ 892 0 stevel if (xsum) { 893 0 stevel /* not a label - checksum didn't compute */ 894 0 stevel goto nolabel; /* no errors, but no label */ 895 0 stevel } 896 0 stevel 897 0 stevel /* 898 0 stevel * the SunOS label overrides current diskette characteristics 899 0 stevel */ 900 0 stevel fjp->fj_chars->fdc_ncyl = label->dkl_pcyl; 901 0 stevel fjp->fj_chars->fdc_nhead = label->dkl_nhead; 902 0 stevel fjp->fj_chars->fdc_secptrack = (label->dkl_nsect * DEV_BSIZE) / 903 0 stevel fjp->fj_chars->fdc_sec_size; 904 0 stevel if (defchar[fdp->d_deffdtype]->fdc_ncyl == 2 * fjp->fj_chars->fdc_ncyl) 905 0 stevel fjp->fj_chars->fdc_steps = 2; 906 0 stevel else 907 0 stevel fjp->fj_chars->fdc_steps = 1; 908 0 stevel 909 0 stevel fjp->fj_attr->fda_rotatespd = label->dkl_rpm; 910 0 stevel fjp->fj_attr->fda_intrlv = label->dkl_intrlv; 911 0 stevel 912 0 stevel fdp->d_vtoc_version = label->dkl_vtoc.v_version; 913 0 stevel bcopy(label->dkl_vtoc.v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL); 914 0 stevel bcopy(label->dkl_vtoc.v_asciilabel, 915 0 stevel fdp->d_vtoc_asciilabel, LEN_DKL_ASCII); 916 0 stevel /* 917 0 stevel * logical partitions 918 0 stevel */ 919 0 stevel for (i = 0; i < NDKMAP; i++) { 920 0 stevel fdp->d_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag; 921 0 stevel fdp->d_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag; 922 0 stevel fdp->d_part[i].p_start = label->dkl_vtoc.v_part[i].p_start; 923 0 stevel fdp->d_part[i].p_size = label->dkl_vtoc.v_part[i].p_size; 924 0 stevel 925 0 stevel fdp->d_vtoc_timestamp[i] = label->dkl_vtoc.timestamp[i]; 926 0 stevel } 927 0 stevel 928 0 stevel fjp->fj_flags |= FUNIT_LABELOK; 929 0 stevel goto out; 930 0 stevel 931 0 stevel nolabel: 932 0 stevel /* 933 0 stevel * if not found, fill in label info from default (mark default used) 934 0 stevel */ 935 0 stevel if (fdp->d_media & (1<<FMT_3D)) 936 0 stevel newlabel = deflabel_35; 937 0 stevel else /* if (fdp->d_media & (1<<FMT_5D9)) */ 938 0 stevel newlabel = deflabel_525; 939 0 stevel bzero(fdp->d_vtoc_volume, LEN_DKL_VVOL); 940 0 stevel (void) sprintf(fdp->d_vtoc_asciilabel, newlabel, 941 0 stevel fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_nhead, 942 0 stevel fjp->fj_chars->fdc_secptrack); 943 0 stevel fjp->fj_flags |= FUNIT_UNLABELED; 944 0 stevel 945 0 stevel out: 946 0 stevel kmem_free(label, sizeof (struct dk_label)); 947 0 stevel return (rval); 948 0 stevel } 949 0 stevel 950 0 stevel 951 0 stevel /*ARGSUSED*/ 952 0 stevel static int 953 0 stevel fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 954 0 stevel { 955 0 stevel struct fcu_obj *fjp = NULL; 956 0 stevel struct fdisk *fdp = NULL; 957 0 stevel int part, part_is_closed; 958 0 stevel 959 0 stevel #ifdef DEBUG 960 0 stevel int unit; 961 0 stevel #define DEBUG_ASSIGN unit= 962 0 stevel #else 963 0 stevel #define DEBUG_ASSIGN (void) 964 0 stevel #endif 965 0 stevel 966 0 stevel DEBUG_ASSIGN fd_getdrive(dev, &fjp, &fdp); 967 0 stevel /* 968 0 stevel * Ignoring return in non DEBUG mode because success is checked by 969 0 stevel * verifying fjp and fdp and returned unit value is not used. 970 0 stevel */ 971 0 stevel if (!fjp || !fdp) 972 0 stevel return (ENXIO); 973 0 stevel part = PARTITION(dev); 974 0 stevel 975 0 stevel sema_p(&fdp->d_ocsem); 976 0 stevel FDERRPRINT(FDEP_L1, FDEM_CLOS, 977 0 stevel (CE_CONT, "fd_close: fd unit %d part %d otype %x\n", 978 0 stevel unit, part, otyp)); 979 0 stevel 980 0 stevel if (otyp == OTYP_LYR) { 981 0 stevel if (fdp->d_lyropen[part]) 982 0 stevel fdp->d_lyropen[part]--; 983 0 stevel part_is_closed = (fdp->d_lyropen[part] == 0); 984 0 stevel } else { 985 0 stevel fdp->d_regopen[otyp] &= ~(1<<part); 986 0 stevel part_is_closed = 1; 987 0 stevel } 988 0 stevel if (part_is_closed) { 989 0 stevel if (part == 2 && fdp->d_exclmask&(1<<part)) 990 0 stevel fdp->d_exclmask = 0; 991 0 stevel else 992 0 stevel fdp->d_exclmask &= ~(1<<part); 993 0 stevel FDERRPRINT(FDEP_L0, FDEM_CLOS, 994 0 stevel (CE_CONT, 995 0 stevel "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n", 996 0 stevel fdp->d_exclmask, fdp->d_regopen[otyp], 997 0 stevel fdp->d_lyropen[part])); 998 0 stevel 999 0 stevel if (fd_unit_is_open(fdp) == 0) 1000 0 stevel fdp->d_obj->fj_flags &= ~FUNIT_CHANGED; 1001 0 stevel } 1002 0 stevel sema_v(&fdp->d_ocsem); 1003 0 stevel return (0); 1004 0 stevel } 1005 0 stevel 1006 0 stevel /* ARGSUSED */ 1007 0 stevel static int 1008 0 stevel fd_read(dev_t dev, struct uio *uio, cred_t *cred_p) 1009 0 stevel { 1010 0 stevel return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio)); 1011 0 stevel } 1012 0 stevel 1013 0 stevel /* ARGSUSED */ 1014 0 stevel static int 1015 0 stevel fd_write(dev_t dev, struct uio *uio, cred_t *cred_p) 1016 0 stevel { 1017 0 stevel return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio)); 1018 0 stevel } 1019 0 stevel 1020 0 stevel /* 1021 0 stevel * fd_strategy 1022 0 stevel * checks operation, hangs buf struct off fdcntlr, calls fdstart 1023 0 stevel * if not already busy. Note that if we call start, then the operation 1024 0 stevel * will already be done on return (start sleeps). 1025 0 stevel */ 1026 0 stevel static int 1027 0 stevel fd_strategy(struct buf *bp) 1028 0 stevel { 1029 0 stevel struct fcu_obj *fjp; 1030 0 stevel struct fdisk *fdp; 1031 0 stevel struct partition *pp; 1032 0 stevel 1033 0 stevel FDERRPRINT(FDEP_L1, FDEM_STRA, 1034 0 stevel (CE_CONT, "fd_strategy: bp = 0x%p, dev = 0x%lx\n", 1035 0 stevel (void *)bp, bp->b_edev)); 1036 0 stevel 1037 0 stevel (void) fd_getdrive(bp->b_edev, &fjp, &fdp); 1038 0 stevel 1039 0 stevel /* 1040 0 stevel * Ignoring return because device exist. 1041 0 stevel * Returned unit value is not used. 1042 0 stevel */ 1043 0 stevel pp = &fdp->d_part[PARTITION(bp->b_edev)]; 1044 0 stevel 1045 0 stevel if (fjp->fj_chars->fdc_sec_size > NBPSCTR && (bp->b_blkno & 1)) { 1046 0 stevel FDERRPRINT(FDEP_L3, FDEM_STRA, 1047 0 stevel (CE_WARN, "fd%d: block %ld is not start of sector!", 1048 0 stevel DRIVE(bp->b_edev), (long)bp->b_blkno)); 1049 0 stevel bp->b_error = EINVAL; 1050 0 stevel goto bad; 1051 0 stevel } 1052 0 stevel 1053 0 stevel if ((bp->b_blkno > pp->p_size)) { 1054 0 stevel FDERRPRINT(FDEP_L3, FDEM_STRA, 1055 0 stevel (CE_WARN, "fd%d: block %ld is past the end! (nblk=%ld)", 1056 0 stevel DRIVE(bp->b_edev), (long)bp->b_blkno, pp->p_size)); 1057 0 stevel bp->b_error = ENOSPC; 1058 0 stevel goto bad; 1059 0 stevel } 1060 0 stevel 1061 0 stevel /* if at end of file, skip out now */ 1062 0 stevel if (bp->b_blkno == pp->p_size) { 1063 0 stevel if ((bp->b_flags & B_READ) == 0) { 1064 0 stevel /* a write needs to get an error! */ 1065 0 stevel bp->b_error = ENOSPC; 1066 0 stevel goto bad; 1067 0 stevel } 1068 0 stevel bp->b_resid = bp->b_bcount; 1069 0 stevel biodone(bp); 1070 0 stevel return (0); 1071 0 stevel } 1072 0 stevel 1073 0 stevel /* if operation not a multiple of sector size, is error! */ 1074 0 stevel if (bp->b_bcount % fjp->fj_chars->fdc_sec_size) { 1075 0 stevel FDERRPRINT(FDEP_L3, FDEM_STRA, 1076 0 stevel (CE_WARN, "fd%d: count %ld must be a multiple of %d", 1077 0 stevel DRIVE(bp->b_edev), bp->b_bcount, 1078 0 stevel fjp->fj_chars->fdc_sec_size)); 1079 0 stevel bp->b_error = EINVAL; 1080 0 stevel goto bad; 1081 0 stevel } 1082 0 stevel 1083 0 stevel /* 1084 0 stevel * Put the buf request in the drive's queue, FIFO. 1085 0 stevel */ 1086 0 stevel bp->av_forw = 0; 1087 0 stevel mutex_enter(&fjp->fj_lock); 1088 0 stevel if (fdp->d_iostat) 1089 0 stevel kstat_waitq_enter(KIOSP); 1090 0 stevel if (fdp->d_actf) 1091 0 stevel fdp->d_actl->av_forw = bp; 1092 0 stevel else 1093 0 stevel fdp->d_actf = bp; 1094 0 stevel fdp->d_actl = bp; 1095 0 stevel if (!(fjp->fj_flags & FUNIT_BUSY)) { 1096 0 stevel fdstart(fjp); 1097 0 stevel } 1098 0 stevel mutex_exit(&fjp->fj_lock); 1099 0 stevel return (0); 1100 0 stevel 1101 0 stevel bad: 1102 0 stevel bp->b_resid = bp->b_bcount; 1103 0 stevel bp->b_flags |= B_ERROR; 1104 0 stevel biodone(bp); 1105 0 stevel return (0); 1106 0 stevel } 1107 0 stevel 1108 0 stevel /* 1109 0 stevel * fdstart 1110 0 stevel * called from fd_strategy() or from fdXXXX() to setup and 1111 0 stevel * start operations of read or write only (using buf structs). 1112 0 stevel * Because the chip doesn't handle crossing cylinder boundaries on 1113 0 stevel * the fly, this takes care of those boundary conditions. Note that 1114 0 stevel * it sleeps until the operation is done *within fdstart* - so that 1115 0 stevel * when fdstart returns, the operation is already done. 1116 0 stevel */ 1117 0 stevel static void 1118 0 stevel fdstart(struct fcu_obj *fjp) 1119 0 stevel { 1120 0 stevel struct buf *bp; 1121 0 stevel struct fdisk *fdp = (struct fdisk *)fjp->fj_data; 1122 0 stevel struct fd_char *chp; 1123 0 stevel struct partition *pp; 1124 0 stevel uint_t ptend; 1125 0 stevel uint_t bincyl; /* (the number of the desired) block in cyl. */ 1126 0 stevel uint_t blk, len, tlen; 1127 0 stevel uint_t secpcyl; /* number of sectors per cylinder */ 1128 0 stevel int cyl, head, sect; 1129 0 stevel int sctrshft, unit; 1130 0 stevel caddr_t addr; 1131 0 stevel 1132 0 stevel ASSERT(MUTEX_HELD(&fjp->fj_lock)); 1133 0 stevel fjp->fj_flags |= FUNIT_BUSY; 1134 0 stevel 1135 0 stevel while ((bp = fdp->d_actf) != NULL) { 1136 0 stevel fdp->d_actf = bp->av_forw; 1137 0 stevel fdp->d_current = bp; 1138 0 stevel if (fdp->d_iostat) { 1139 0 stevel kstat_waitq_to_runq(KIOSP); 1140 0 stevel } 1141 0 stevel mutex_exit(&fjp->fj_lock); 1142 0 stevel 1143 0 stevel FDERRPRINT(FDEP_L0, FDEM_STRT, 1144 0 stevel (CE_CONT, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n", 1145 0 stevel (void *)bp, (long)bp->b_blkno, bp->b_bcount)); 1146 0 stevel bp->b_flags &= ~B_ERROR; 1147 0 stevel bp->b_error = 0; 1148 0 stevel bp->b_resid = bp->b_bcount; /* init resid */ 1149 0 stevel 1150 0 stevel ASSERT(DRIVE(bp->b_edev) == ddi_get_instance(fjp->fj_dip)); 1151 0 stevel unit = fjp->fj_unit; 1152 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 1153 0 stevel 1154 0 stevel bp_mapin(bp); /* map in buffers */ 1155 0 stevel 1156 0 stevel pp = &fdp->d_part[PARTITION(bp->b_edev)]; 1157 0 stevel /* starting blk adjusted for the partition */ 1158 0 stevel blk = bp->b_blkno + pp->p_start; 1159 0 stevel ptend = pp->p_start + pp->p_size; /* end of the partition */ 1160 0 stevel 1161 0 stevel chp = fjp->fj_chars; 1162 0 stevel secpcyl = chp->fdc_nhead * chp->fdc_secptrack; 1163 0 stevel switch (chp->fdc_sec_size) { 1164 0 stevel /* convert logical block numbers to sector numbers */ 1165 0 stevel case 1024: 1166 0 stevel sctrshft = SCTRSHFT + 1; 1167 0 stevel blk >>= 1; 1168 0 stevel ptend >>= 1; 1169 0 stevel break; 1170 0 stevel default: 1171 0 stevel case NBPSCTR: 1172 0 stevel sctrshft = SCTRSHFT; 1173 0 stevel break; 1174 0 stevel case 256: 1175 0 stevel sctrshft = SCTRSHFT - 1; 1176 0 stevel blk <<= 1; 1177 0 stevel ptend <<= 1; 1178 0 stevel break; 1179 0 stevel } 1180 0 stevel 1181 0 stevel /* 1182 0 stevel * If off the end, limit to actual amount that 1183 0 stevel * can be transferred. 1184 0 stevel */ 1185 0 stevel if ((blk + (bp->b_bcount >> sctrshft)) > ptend) 1186 0 stevel /* to end of partition */ 1187 0 stevel len = (ptend - blk) << sctrshft; 1188 0 stevel else 1189 0 stevel len = bp->b_bcount; 1190 0 stevel addr = bp->b_un.b_addr; /* data buffer address */ 1191 0 stevel 1192 0 stevel /* 1193 0 stevel * now we have the real start blk, addr and len for xfer op 1194 0 stevel */ 1195 0 stevel while (len != 0) { 1196 0 stevel /* start cyl of req */ 1197 0 stevel cyl = blk / secpcyl; 1198 0 stevel bincyl = blk % secpcyl; 1199 0 stevel /* start head of req */ 1200 0 stevel head = bincyl / chp->fdc_secptrack; 1201 0 stevel /* start sector of req */ 1202 0 stevel sect = (bincyl % chp->fdc_secptrack) + 1; 1203 0 stevel /* 1204 0 stevel * If the desired block and length will go beyond the 1205 0 stevel * cylinder end, then limit it to the cylinder end. 1206 0 stevel */ 1207 0 stevel if (bp->b_flags & B_READ) { 1208 0 stevel if (len > ((secpcyl - bincyl) << sctrshft)) 1209 0 stevel tlen = (secpcyl - bincyl) << sctrshft; 1210 0 stevel else 1211 0 stevel tlen = len; 1212 0 stevel } else { 1213 0 stevel if (len > 1214 0 stevel ((chp->fdc_secptrack - sect + 1) << 1215 0 stevel sctrshft)) 1216 0 stevel tlen = 1217 0 stevel (chp->fdc_secptrack - sect + 1) << 1218 0 stevel sctrshft; 1219 0 stevel else 1220 0 stevel tlen = len; 1221 0 stevel } 1222 0 stevel 1223 0 stevel FDERRPRINT(FDEP_L0, FDEM_STRT, (CE_CONT, 1224 0 stevel " blk 0x%x addr 0x%p len 0x%x " 1225 0 stevel "cyl %d head %d sec %d\n resid 0x%lx, tlen %d\n", 1226 0 stevel blk, (void *)addr, len, cyl, head, sect, 1227 0 stevel bp->b_resid, tlen)); 1228 0 stevel 1229 0 stevel /* 1230 0 stevel * (try to) do the operation - failure returns an errno 1231 0 stevel */ 1232 0 stevel bp->b_error = fjp->fj_ops->fco_rw(fjp, unit, 1233 0 stevel bp->b_flags & B_READ, cyl, head, sect, addr, tlen); 1234 0 stevel if (bp->b_error != 0) { 1235 0 stevel FDERRPRINT(FDEP_L3, FDEM_STRT, (CE_WARN, 1236 0 stevel "fdstart: bad exec of bp: 0x%p, err=%d", 1237 0 stevel (void *)bp, bp->b_error)); 1238 0 stevel bp->b_flags |= B_ERROR; 1239 0 stevel break; 1240 0 stevel } 1241 0 stevel blk += tlen >> sctrshft; 1242 0 stevel len -= tlen; 1243 0 stevel addr += tlen; 1244 0 stevel bp->b_resid -= tlen; 1245 0 stevel } 1246 0 stevel FDERRPRINT(FDEP_L0, FDEM_STRT, 1247 0 stevel (CE_CONT, "fdstart done: b_resid %lu, b_count %lu\n", 1248 0 stevel bp->b_resid, bp->b_bcount)); 1249 0 stevel if (fdp->d_iostat) { 1250 0 stevel if (bp->b_flags & B_READ) { 1251 0 stevel KIOSP->reads++; 1252 0 stevel KIOSP->nread += (bp->b_bcount - bp->b_resid); 1253 0 stevel } else { 1254 0 stevel KIOSP->writes++; 1255 0 stevel KIOSP->nwritten += (bp->b_bcount - bp->b_resid); 1256 0 stevel } 1257 0 stevel kstat_runq_exit(KIOSP); 1258 0 stevel } 1259 0 stevel bp_mapout(bp); 1260 0 stevel biodone(bp); 1261 0 stevel 1262 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 1263 0 stevel mutex_enter(&fjp->fj_lock); 1264 0 stevel fdp->d_current = 0; 1265 0 stevel } 1266 0 stevel fjp->fj_flags ^= FUNIT_BUSY; 1267 0 stevel } 1268 0 stevel 1269 0 stevel /* ARGSUSED */ 1270 0 stevel static int 1271 0 stevel fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, 1272 0 stevel int *rval_p) 1273 0 stevel { 1274 0 stevel union { 1275 0 stevel struct dk_cinfo dki; 1276 0 stevel struct dk_geom dkg; 1277 0 stevel struct dk_allmap dka; 1278 0 stevel struct fd_char fdchar; 1279 0 stevel struct fd_drive drvchar; 1280 0 stevel int temp; 1281 0 stevel } cpy; 1282 0 stevel struct vtoc vtoc; 1283 0 stevel struct fcu_obj *fjp = NULL; 1284 0 stevel struct fdisk *fdp = NULL; 1285 0 stevel struct dk_map *dmp; 1286 0 stevel struct dk_label *label; 1287 0 stevel int nblks, part, unit; 1288 0 stevel int rval = 0; 1289 0 stevel enum dkio_state state; 1290 0 stevel 1291 0 stevel unit = fd_getdrive(dev, &fjp, &fdp); 1292 0 stevel if (!fjp || !fdp) 1293 0 stevel return (ENXIO); 1294 0 stevel 1295 0 stevel FDERRPRINT(FDEP_L1, FDEM_IOCT, 1296 0 stevel (CE_CONT, "fd_ioctl fd unit %d: cmd %x, arg %lx\n", 1297 0 stevel unit, cmd, arg)); 1298 0 stevel 1299 0 stevel switch (cmd) { 1300 0 stevel case DKIOCINFO: 1301 0 stevel fjp->fj_ops->fco_dkinfo(fjp, &cpy.dki); 1302 0 stevel cpy.dki.dki_cnum = FDCTLR(fjp->fj_unit); 1303 0 stevel cpy.dki.dki_unit = FDUNIT(fjp->fj_unit); 1304 0 stevel cpy.dki.dki_partition = PARTITION(dev); 1305 0 stevel if (ddi_copyout(&cpy.dki, (void *)arg, sizeof (cpy.dki), flag)) 1306 0 stevel rval = EFAULT; 1307 0 stevel break; 1308 0 stevel 1309 0 stevel case DKIOCG_PHYGEOM: 1310 0 stevel case DKIOCG_VIRTGEOM: 1311 0 stevel cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack; 1312 0 stevel goto get_geom; 1313 0 stevel case DKIOCGGEOM: 1314 0 stevel if (fjp->fj_flags & FUNIT_LABELOK) 1315 0 stevel cpy.dkg.dkg_nsect = (fjp->fj_chars->fdc_secptrack * 1316 0 stevel fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 1317 0 stevel else 1318 0 stevel cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack; 1319 0 stevel get_geom: 1320 0 stevel cpy.dkg.dkg_pcyl = fjp->fj_chars->fdc_ncyl; 1321 0 stevel cpy.dkg.dkg_ncyl = fjp->fj_chars->fdc_ncyl; 1322 0 stevel cpy.dkg.dkg_nhead = fjp->fj_chars->fdc_nhead; 1323 0 stevel cpy.dkg.dkg_intrlv = fjp->fj_attr->fda_intrlv; 1324 0 stevel cpy.dkg.dkg_rpm = fjp->fj_attr->fda_rotatespd; 1325 0 stevel cpy.dkg.dkg_read_reinstruct = 1326 0 stevel (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000; 1327 0 stevel cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct; 1328 0 stevel if (ddi_copyout(&cpy.dkg, (void *)arg, sizeof (cpy.dkg), flag)) 1329 0 stevel rval = EFAULT; 1330 0 stevel break; 1331 0 stevel 1332 0 stevel case DKIOCSGEOM: 1333 0 stevel if (ddi_copyin((void *)arg, &cpy.dkg, 1334 0 stevel sizeof (struct dk_geom), flag)) { 1335 0 stevel rval = EFAULT; 1336 0 stevel break; 1337 0 stevel } 1338 0 stevel mutex_enter(&fjp->fj_lock); 1339 0 stevel fjp->fj_chars->fdc_ncyl = cpy.dkg.dkg_ncyl; 1340 0 stevel fjp->fj_chars->fdc_nhead = cpy.dkg.dkg_nhead; 1341 0 stevel fjp->fj_chars->fdc_secptrack = cpy.dkg.dkg_nsect; 1342 0 stevel fjp->fj_attr->fda_intrlv = cpy.dkg.dkg_intrlv; 1343 0 stevel fjp->fj_attr->fda_rotatespd = cpy.dkg.dkg_rpm; 1344 0 stevel fdp->d_curfdtype = -1; 1345 0 stevel mutex_exit(&fjp->fj_lock); 1346 0 stevel break; 1347 0 stevel 1348 0 stevel /* 1349 0 stevel * return the map of all logical partitions 1350 0 stevel */ 1351 0 stevel case DKIOCGAPART: 1352 0 stevel /* 1353 0 stevel * Note the conversion from starting sector number 1354 0 stevel * to starting cylinder number. 1355 0 stevel * Return error if division results in a remainder. 1356 0 stevel */ 1357 0 stevel nblks = fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack; 1358 0 stevel 1359 0 stevel #ifdef _MULTI_DATAMODEL 1360 0 stevel switch (ddi_model_convert_from(flag & FMODELS)) { 1361 0 stevel case DDI_MODEL_ILP32: 1362 0 stevel { 1363 0 stevel struct dk_allmap32 dka32; 1364 0 stevel 1365 0 stevel for (part = 0; part < NDKMAP; part++) { 1366 0 stevel if ((fdp->d_part[part].p_start % nblks) != 0) 1367 0 stevel return (EINVAL); 1368 0 stevel dka32.dka_map[part].dkl_cylno = 1369 0 stevel fdp->d_part[part].p_start / nblks; 1370 0 stevel dka32.dka_map[part].dkl_nblk = 1371 0 stevel fdp->d_part[part].p_size; 1372 0 stevel } 1373 0 stevel 1374 0 stevel if (ddi_copyout(&dka32, (void *)arg, 1375 0 stevel sizeof (struct dk_allmap32), flag)) 1376 0 stevel rval = EFAULT; 1377 0 stevel 1378 0 stevel break; 1379 0 stevel } 1380 0 stevel case DDI_MODEL_NONE: 1381 0 stevel 1382 0 stevel #endif /* _MULTI_DATAMODEL */ 1383 0 stevel 1384 0 stevel dmp = (struct dk_map *)&cpy.dka; 1385 0 stevel for (part = 0; part < NDKMAP; part++) { 1386 0 stevel if ((fdp->d_part[part].p_start % nblks) != 0) 1387 0 stevel return (EINVAL); 1388 0 stevel dmp->dkl_cylno = 1389 0 stevel fdp->d_part[part].p_start / nblks; 1390 0 stevel dmp->dkl_nblk = fdp->d_part[part].p_size; 1391 0 stevel dmp++; 1392 0 stevel } 1393 0 stevel 1394 0 stevel if (ddi_copyout(&cpy.dka, (void *)arg, 1395 0 stevel sizeof (struct dk_allmap), flag)) 1396 0 stevel rval = EFAULT; 1397 0 stevel #ifdef _MULTI_DATAMODEL 1398 0 stevel break; 1399 0 stevel 1400 0 stevel } 1401 0 stevel #endif /* _MULTI_DATAMODEL */ 1402 0 stevel 1403 0 stevel break; 1404 0 stevel 1405 0 stevel /* 1406 0 stevel * Set the map of all logical partitions 1407 0 stevel */ 1408 0 stevel case DKIOCSAPART: 1409 0 stevel 1410 0 stevel #ifdef _MULTI_DATAMODEL 1411 0 stevel switch (ddi_model_convert_from(flag & FMODELS)) { 1412 0 stevel case DDI_MODEL_ILP32: 1413 0 stevel { 1414 0 stevel struct dk_allmap32 dka32; 1415 0 stevel 1416 0 stevel if (ddi_copyin((void *)arg, &dka32, 1417 0 stevel sizeof (dka32), flag)) { 1418 0 stevel rval = EFAULT; 1419 0 stevel break; 1420 0 stevel } 1421 0 stevel for (part = 0; part < NDKMAP; part++) { 1422 0 stevel cpy.dka.dka_map[part].dkl_cylno = 1423 0 stevel dka32.dka_map[part].dkl_cylno; 1424 0 stevel cpy.dka.dka_map[part].dkl_nblk = 1425 0 stevel dka32.dka_map[part].dkl_nblk; 1426 0 stevel } 1427 0 stevel break; 1428 0 stevel } 1429 0 stevel case DDI_MODEL_NONE: 1430 0 stevel 1431 0 stevel #endif /* _MULTI_DATAMODEL */ 1432 0 stevel if (ddi_copyin((void *)arg, &cpy.dka, sizeof (cpy.dka), flag)) 1433 0 stevel rval = EFAULT; 1434 0 stevel #ifdef _MULTI_DATAMODEL 1435 0 stevel 1436 0 stevel break; 1437 0 stevel } 1438 0 stevel #endif /* _MULTI_DATAMODEL */ 1439 0 stevel 1440 0 stevel if (rval != 0) 1441 0 stevel break; 1442 0 stevel 1443 0 stevel dmp = (struct dk_map *)&cpy.dka; 1444 0 stevel nblks = fjp->fj_chars->fdc_nhead * 1445 0 stevel fjp->fj_chars->fdc_secptrack; 1446 0 stevel mutex_enter(&fjp->fj_lock); 1447 0 stevel /* 1448 0 stevel * Note the conversion from starting cylinder number 1449 0 stevel * to starting sector number. 1450 0 stevel */ 1451 0 stevel for (part = 0; part < NDKMAP; part++) { 1452 0 stevel fdp->d_part[part].p_start = dmp->dkl_cylno * 1453 0 stevel nblks; 1454 0 stevel fdp->d_part[part].p_size = dmp->dkl_nblk; 1455 0 stevel dmp++; 1456 0 stevel } 1457 0 stevel mutex_exit(&fjp->fj_lock); 1458 0 stevel 1459 0 stevel break; 1460 0 stevel 1461 0 stevel case DKIOCGVTOC: 1462 0 stevel mutex_enter(&fjp->fj_lock); 1463 0 stevel 1464 0 stevel /* 1465 0 stevel * Exit if the diskette has no label. 1466 0 stevel * Also, get the label to make sure the correct one is 1467 0 stevel * being used since the diskette may have changed 1468 0 stevel */ 1469 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 1470 0 stevel rval = fdgetlabel(fjp, unit); 1471 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 1472 0 stevel if (rval) { 1473 0 stevel mutex_exit(&fjp->fj_lock); 1474 0 stevel rval = EINVAL; 1475 0 stevel break; 1476 0 stevel } 1477 0 stevel 1478 0 stevel fd_build_user_vtoc(fjp, fdp, &vtoc); 1479 0 stevel mutex_exit(&fjp->fj_lock); 1480 0 stevel 1481 0 stevel #ifdef _MULTI_DATAMODEL 1482 0 stevel switch (ddi_model_convert_from(flag & FMODELS)) { 1483 0 stevel case DDI_MODEL_ILP32: 1484 0 stevel { 1485 0 stevel struct vtoc32 vtoc32; 1486 0 stevel 1487 0 stevel vtoctovtoc32(vtoc, vtoc32); 1488 0 stevel 1489 0 stevel if (ddi_copyout(&vtoc32, (void *)arg, 1490 0 stevel sizeof (vtoc32), flag)) 1491 0 stevel rval = EFAULT; 1492 0 stevel 1493 0 stevel break; 1494 0 stevel } 1495 0 stevel case DDI_MODEL_NONE: 1496 0 stevel 1497 0 stevel #endif /* _MULTI_DATAMODEL */ 1498 0 stevel if (ddi_copyout(&vtoc, (void *)arg, 1499 0 stevel sizeof (vtoc), flag)) 1500 0 stevel rval = EFAULT; 1501 0 stevel #ifdef _MULTI_DATAMODEL 1502 0 stevel break; 1503 0 stevel } 1504 0 stevel #endif /* _MULTI_DATAMODEL */ 1505 0 stevel 1506 0 stevel break; 1507 0 stevel 1508 0 stevel case DKIOCSVTOC: 1509 0 stevel 1510 0 stevel #ifdef _MULTI_DATAMODEL 1511 0 stevel switch (ddi_model_convert_from(flag & FMODELS)) { 1512 0 stevel case DDI_MODEL_ILP32: 1513 0 stevel { 1514 0 stevel struct vtoc32 vtoc32; 1515 0 stevel 1516 0 stevel if (ddi_copyin((void *)arg, &vtoc32, 1517 0 stevel sizeof (vtoc32), flag)) { 1518 0 stevel rval = EFAULT; 1519 0 stevel break; 1520 0 stevel } 1521 0 stevel 1522 0 stevel vtoc32tovtoc(vtoc32, vtoc); 1523 0 stevel 1524 0 stevel break; 1525 0 stevel } 1526 0 stevel case DDI_MODEL_NONE: 1527 0 stevel 1528 0 stevel #endif /* _MULTI_DATAMODEL */ 1529 0 stevel if (ddi_copyin((void *)arg, &vtoc, sizeof (vtoc), flag)) 1530 0 stevel rval = EFAULT; 1531 0 stevel #ifdef _MULTI_DATAMODEL 1532 0 stevel break; 1533 0 stevel } 1534 0 stevel #endif /* _MULTI_DATAMODEL */ 1535 0 stevel 1536 0 stevel if (rval != 0) 1537 0 stevel break; 1538 0 stevel 1539 0 stevel 1540 0 stevel label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 1541 0 stevel 1542 0 stevel mutex_enter(&fjp->fj_lock); 1543 0 stevel 1544 0 stevel if ((rval = fd_build_label_vtoc(fjp, fdp, &vtoc, label)) == 0) { 1545 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 1546 0 stevel rval = fjp->fj_ops->fco_rw(fjp, unit, FDWRITE, 1547 0 stevel 0, 0, 1, (caddr_t)label, sizeof (struct dk_label)); 1548 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 1549 0 stevel } 1550 0 stevel mutex_exit(&fjp->fj_lock); 1551 0 stevel kmem_free(label, sizeof (struct dk_label)); 1552 0 stevel break; 1553 0 stevel 1554 0 stevel case DKIOCSTATE: 1555 0 stevel FDERRPRINT(FDEP_L1, FDEM_IOCT, 1556 0 stevel (CE_CONT, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit)); 1557 0 stevel 1558 0 stevel if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) { 1559 0 stevel rval = EFAULT; 1560 0 stevel break; 1561 0 stevel } 1562 0 stevel 1563 0 stevel rval = fd_check_media(dev, state); 1564 0 stevel 1565 0 stevel if (ddi_copyout(&fdp->d_media_state, (void *)arg, 1566 0 stevel sizeof (int), flag)) 1567 0 stevel rval = EFAULT; 1568 0 stevel break; 1569 0 stevel 1570 0 stevel case FDIOGCHAR: 1571 0 stevel if (ddi_copyout(fjp->fj_chars, (void *)arg, 1572 0 stevel sizeof (struct fd_char), flag)) 1573 0 stevel rval = EFAULT; 1574 0 stevel break; 1575 0 stevel 1576 0 stevel case FDIOSCHAR: 1577 0 stevel if (ddi_copyin((void *)arg, &cpy.fdchar, 1578 0 stevel sizeof (struct fd_char), flag)) { 1579 0 stevel rval = EFAULT; 1580 0 stevel break; 1581 0 stevel } 1582 0 stevel switch (cpy.fdchar.fdc_transfer_rate) { 1583 0 stevel case 417: 1584 0 stevel if ((fdp->d_media & (1 << FMT_3M)) == 0) { 1585 0 stevel cmn_err(CE_CONT, 1586 0 stevel "fdioschar:Medium density not supported\n"); 1587 0 stevel rval = EINVAL; 1588 0 stevel break; 1589 0 stevel } 1590 0 stevel mutex_enter(&fjp->fj_lock); 1591 0 stevel fjp->fj_attr->fda_rotatespd = 360; 1592 0 stevel mutex_exit(&fjp->fj_lock); 1593 0 stevel /* cpy.fdchar.fdc_transfer_rate = 500; */ 1594 0 stevel /* FALLTHROUGH */ 1595 0 stevel case 1000: 1596 0 stevel case 500: 1597 0 stevel case 300: 1598 0 stevel case 250: 1599 0 stevel mutex_enter(&fjp->fj_lock); 1600 0 stevel *(fjp->fj_chars) = cpy.fdchar; 1601 0 stevel fdp->d_curfdtype = -1; 1602 0 stevel fjp->fj_flags &= ~FUNIT_CHAROK; 1603 0 stevel mutex_exit(&fjp->fj_lock); 1604 0 stevel 1605 0 stevel break; 1606 0 stevel 1607 0 stevel default: 1608 0 stevel FDERRPRINT(FDEP_L4, FDEM_IOCT, 1609 0 stevel (CE_WARN, "fd_ioctl fd unit %d: FDIOSCHAR odd " 1610 7656 Sherry "xfer rate %dkbs", 1611 7656 Sherry unit, cpy.fdchar.fdc_transfer_rate)); 1612 0 stevel rval = EINVAL; 1613 0 stevel break; 1614 0 stevel } 1615 0 stevel break; 1616 0 stevel 1617 0 stevel /* 1618 0 stevel * set all characteristics and geometry to the defaults 1619 0 stevel */ 1620 0 stevel case FDDEFGEOCHAR: 1621 0 stevel mutex_enter(&fjp->fj_lock); 1622 0 stevel fdp->d_curfdtype = fdp->d_deffdtype; 1623 0 stevel *fjp->fj_chars = *defchar[fdp->d_curfdtype]; 1624 0 stevel *fjp->fj_attr = fdtypes[fdp->d_curfdtype]; 1625 0 stevel bcopy(fdparts[fdp->d_curfdtype], 1626 0 stevel fdp->d_part, sizeof (struct partition) * NDKMAP); 1627 0 stevel fjp->fj_flags &= ~FUNIT_CHAROK; 1628 0 stevel mutex_exit(&fjp->fj_lock); 1629 0 stevel break; 1630 0 stevel 1631 0 stevel case FDEJECT: /* eject disk */ 1632 0 stevel case DKIOCEJECT: 1633 0 stevel fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 1634 0 stevel rval = ENOSYS; 1635 0 stevel break; 1636 0 stevel 1637 0 stevel case FDGETCHANGE: /* disk changed */ 1638 0 stevel if (ddi_copyin((void *)arg, &cpy.temp, sizeof (int), flag)) { 1639 0 stevel rval = EFAULT; 1640 0 stevel break; 1641 0 stevel } 1642 0 stevel mutex_enter(&fjp->fj_lock); 1643 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 1644 0 stevel 1645 0 stevel if (fjp->fj_flags & FUNIT_CHANGED) 1646 0 stevel cpy.temp |= FDGC_HISTORY; 1647 0 stevel else 1648 0 stevel cpy.temp &= ~FDGC_HISTORY; 1649 0 stevel fjp->fj_flags &= ~FUNIT_CHANGED; 1650 0 stevel 1651 0 stevel if (fjp->fj_ops->fco_getchng(fjp, unit)) { 1652 0 stevel cpy.temp |= FDGC_DETECTED; 1653 0 stevel fjp->fj_ops->fco_resetchng(fjp, unit); 1654 0 stevel /* 1655 0 stevel * check diskette again only if it was removed 1656 0 stevel */ 1657 0 stevel if (fjp->fj_ops->fco_getchng(fjp, unit)) { 1658 0 stevel /* 1659 0 stevel * no diskette is present 1660 0 stevel */ 1661 0 stevel cpy.temp |= FDGC_CURRENT; 1662 0 stevel if (fjp->fj_flags & FUNIT_CHGDET) 1663 0 stevel /* 1664 0 stevel * again no diskette; not a new change 1665 0 stevel */ 1666 0 stevel cpy.temp ^= FDGC_DETECTED; 1667 0 stevel else 1668 0 stevel fjp->fj_flags |= FUNIT_CHGDET; 1669 0 stevel } else { 1670 0 stevel /* 1671 0 stevel * a new diskette is present 1672 0 stevel */ 1673 0 stevel cpy.temp &= ~FDGC_CURRENT; 1674 0 stevel fjp->fj_flags &= ~FUNIT_CHGDET; 1675 0 stevel } 1676 0 stevel } else { 1677 0 stevel cpy.temp &= ~(FDGC_DETECTED | FDGC_CURRENT); 1678 0 stevel fjp->fj_flags &= ~FUNIT_CHGDET; 1679 0 stevel } 1680 0 stevel /* 1681 0 stevel * also get state of write protection 1682 0 stevel */ 1683 0 stevel if (fjp->fj_flags & FUNIT_WPROT) { 1684 0 stevel cpy.temp |= FDGC_CURWPROT; 1685 0 stevel } else { 1686 0 stevel cpy.temp &= ~FDGC_CURWPROT; 1687 0 stevel } 1688 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 1689 0 stevel mutex_exit(&fjp->fj_lock); 1690 0 stevel 1691 0 stevel if (ddi_copyout(&cpy.temp, (void *)arg, sizeof (int), flag)) 1692 0 stevel rval = EFAULT; 1693 0 stevel break; 1694 0 stevel 1695 0 stevel case FDGETDRIVECHAR: 1696 0 stevel if (ddi_copyout(fjp->fj_drive, (void *)arg, 1697 0 stevel sizeof (struct fd_drive), flag)) 1698 0 stevel rval = EFAULT; 1699 0 stevel break; 1700 0 stevel 1701 0 stevel case FDSETDRIVECHAR: 1702 0 stevel if (ddi_copyin((void *)arg, &cpy.drvchar, 1703 0 stevel sizeof (struct fd_drive), flag)) { 1704 0 stevel rval = EFAULT; 1705 0 stevel break; 1706 0 stevel } 1707 0 stevel mutex_enter(&fjp->fj_lock); 1708 0 stevel *(fjp->fj_drive) = cpy.drvchar; 1709 0 stevel fdp->d_curfdtype = -1; 1710 0 stevel fjp->fj_flags &= ~FUNIT_CHAROK; 1711 0 stevel mutex_exit(&fjp->fj_lock); 1712 0 stevel break; 1713 0 stevel 1714 0 stevel case DKIOCREMOVABLE: { 1715 0 stevel int i = 1; 1716 0 stevel 1717 0 stevel /* no brainer: floppies are always removable */ 1718 0 stevel if (ddi_copyout(&i, (void *)arg, sizeof (int), flag)) { 1719 0 stevel rval = EFAULT; 1720 0 stevel } 1721 0 stevel break; 1722 0 stevel } 1723 0 stevel 1724 0 stevel case DKIOCGMEDIAINFO: 1725 0 stevel rval = fd_get_media_info(fjp, (caddr_t)arg, flag); 1726 0 stevel break; 1727 0 stevel 1728 0 stevel case FDIOCMD: 1729 0 stevel { 1730 0 stevel struct fd_cmd fc; 1731 0 stevel int cyl, head, spc, spt; 1732 0 stevel 1733 0 stevel #ifdef _MULTI_DATAMODEL 1734 0 stevel switch (ddi_model_convert_from(flag & FMODELS)) { 1735 0 stevel case DDI_MODEL_ILP32: 1736 0 stevel { 1737 0 stevel struct fd_cmd32 fc32; 1738 0 stevel 1739 0 stevel if (ddi_copyin((void *)arg, &fc32, 1740 0 stevel sizeof (fc32), flag)) { 1741 0 stevel rval = EFAULT; 1742 0 stevel break; 1743 0 stevel } 1744 0 stevel 1745 0 stevel fc.fdc_cmd = fc32.fdc_cmd; 1746 0 stevel fc.fdc_flags = fc32.fdc_flags; 1747 0 stevel fc.fdc_blkno = fc32.fdc_blkno; 1748 0 stevel fc.fdc_secnt = fc32.fdc_secnt; 1749 0 stevel fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr; 1750 0 stevel fc.fdc_buflen = fc32.fdc_buflen; 1751 0 stevel 1752 0 stevel break; 1753 0 stevel } 1754 0 stevel case DDI_MODEL_NONE: 1755 0 stevel 1756 0 stevel #endif /* _MULTI_DATAMODEL */ 1757 0 stevel 1758 0 stevel if (ddi_copyin((void *)arg, &fc, sizeof (fc), flag)) { 1759 0 stevel rval = EFAULT; 1760 0 stevel break; 1761 0 stevel } 1762 0 stevel #ifdef _MULTI_DATAMODEL 1763 0 stevel break; 1764 0 stevel } 1765 0 stevel #endif /* _MULTI_DATAMODEL */ 1766 0 stevel 1767 0 stevel if (rval != 0) 1768 0 stevel break; 1769 0 stevel 1770 0 stevel if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) { 1771 0 stevel auto struct iovec aiov; 1772 0 stevel auto struct uio auio; 1773 0 stevel struct uio *uio = &auio; 1774 0 stevel 1775 0 stevel spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE; 1776 0 stevel 1777 0 stevel bzero(&auio, sizeof (struct uio)); 1778 0 stevel bzero(&aiov, sizeof (struct iovec)); 1779 0 stevel aiov.iov_base = fc.fdc_bufaddr; 1780 0 stevel aiov.iov_len = (uint_t)fc.fdc_secnt * 1781 0 stevel fjp->fj_chars->fdc_sec_size; 1782 0 stevel uio->uio_iov = &aiov; 1783 0 stevel 1784 0 stevel uio->uio_iovcnt = 1; 1785 0 stevel uio->uio_resid = aiov.iov_len; 1786 0 stevel uio->uio_segflg = UIO_USERSPACE; 1787 0 stevel 1788 0 stevel rval = physio(fd_strategy, (struct buf *)0, dev, 1789 0 stevel spc, minphys, uio); 1790 0 stevel break; 1791 0 stevel } else if (fc.fdc_cmd == FDCMD_FORMAT_TRACK) { 1792 0 stevel spt = fjp->fj_chars->fdc_secptrack; /* sec/trk */ 1793 0 stevel spc = fjp->fj_chars->fdc_nhead * spt; /* sec/cyl */ 1794 0 stevel cyl = fc.fdc_blkno / spc; 1795 0 stevel head = (fc.fdc_blkno % spc) / spt; 1796 0 stevel if ((cyl | head) == 0) 1797 0 stevel fjp->fj_flags &= 1798 0 stevel ~(FUNIT_LABELOK | FUNIT_UNLABELED); 1799 0 stevel 1800 0 stevel FDERRPRINT(FDEP_L0, FDEM_FORM, 1801 0 stevel (CE_CONT, "fd_format cyl %d, hd %d\n", cyl, head)); 1802 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 1803 0 stevel rval = fjp->fj_ops->fco_format(fjp, unit, cyl, head, 1804 0 stevel (int)fc.fdc_flags); 1805 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 1806 0 stevel 1807 0 stevel break; 1808 0 stevel } 1809 0 stevel FDERRPRINT(FDEP_L4, FDEM_IOCT, 1810 0 stevel (CE_WARN, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete", 1811 0 stevel unit)); 1812 0 stevel rval = EINVAL; 1813 0 stevel break; 1814 0 stevel } 1815 0 stevel 1816 0 stevel case FDRAW: 1817 0 stevel rval = fd_rawioctl(fjp, unit, (caddr_t)arg, flag); 1818 0 stevel break; 1819 0 stevel 1820 0 stevel default: 1821 0 stevel FDERRPRINT(FDEP_L4, FDEM_IOCT, 1822 0 stevel (CE_WARN, "fd_ioctl fd unit %d: invalid ioctl 0x%x", 1823 0 stevel unit, cmd)); 1824 0 stevel rval = ENOTTY; 1825 0 stevel break; 1826 0 stevel } 1827 0 stevel return (rval); 1828 0 stevel } 1829 0 stevel 1830 0 stevel static void 1831 0 stevel fd_build_user_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp) 1832 0 stevel { 1833 0 stevel struct partition *vpart; 1834 0 stevel int i; 1835 0 stevel int xblk; 1836 0 stevel 1837 0 stevel /* 1838 0 stevel * Return vtoc structure fields in the provided VTOC area, addressed 1839 0 stevel * by *vtocp. 1840 0 stevel * 1841 0 stevel */ 1842 0 stevel bzero(vtocp, sizeof (struct vtoc)); 1843 0 stevel 1844 0 stevel bcopy(fdp->d_vtoc_bootinfo, 1845 0 stevel vtocp->v_bootinfo, sizeof (vtocp->v_bootinfo)); 1846 0 stevel 1847 0 stevel vtocp->v_sanity = VTOC_SANE; 1848 0 stevel vtocp->v_version = fdp->d_vtoc_version; 1849 0 stevel bcopy(fdp->d_vtoc_volume, vtocp->v_volume, LEN_DKL_VVOL); 1850 0 stevel if (fjp->fj_flags & FUNIT_LABELOK) { 1851 0 stevel vtocp->v_sectorsz = DEV_BSIZE; 1852 0 stevel xblk = 1; 1853 0 stevel } else { 1854 0 stevel vtocp->v_sectorsz = fjp->fj_chars->fdc_sec_size; 1855 0 stevel xblk = vtocp->v_sectorsz / DEV_BSIZE; 1856 0 stevel } 1857 0 stevel vtocp->v_nparts = 3; /* <= NDKMAP; */ 1858 0 stevel 1859 0 stevel /* 1860 0 stevel * Copy partitioning information. 1861 0 stevel */ 1862 0 stevel bcopy(fdp->d_part, vtocp->v_part, sizeof (struct partition) * NDKMAP); 1863 0 stevel for (i = NDKMAP, vpart = vtocp->v_part; i && (xblk > 1); i--, vpart++) { 1864 0 stevel /* correct partition info if sector size > 512 bytes */ 1865 0 stevel vpart->p_start /= xblk; 1866 0 stevel vpart->p_size /= xblk; 1867 0 stevel } 1868 0 stevel 1869 0 stevel bcopy(fdp->d_vtoc_timestamp, 1870 0 stevel vtocp->timestamp, sizeof (fdp->d_vtoc_timestamp)); 1871 0 stevel bcopy(fdp->d_vtoc_asciilabel, vtocp->v_asciilabel, LEN_DKL_ASCII); 1872 0 stevel } 1873 0 stevel 1874 0 stevel 1875 0 stevel static int 1876 0 stevel fd_build_label_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp, 1877 0 stevel struct dk_label *labelp) 1878 0 stevel { 1879 0 stevel struct partition *vpart; 1880 0 stevel int i; 1881 0 stevel int nblks; 1882 0 stevel int ncyl; 1883 0 stevel ushort_t sum, *sp; 1884 0 stevel 1885 0 stevel 1886 0 stevel /* 1887 0 stevel * Sanity-check the vtoc 1888 0 stevel */ 1889 0 stevel if (vtocp->v_sanity != VTOC_SANE || 1890 0 stevel vtocp->v_nparts > NDKMAP || vtocp->v_nparts <= 0) { 1891 0 stevel FDERRPRINT(FDEP_L3, FDEM_IOCT, 1892 0 stevel (CE_WARN, "fd_build_label: sanity check on vtoc failed")); 1893 0 stevel return (EINVAL); 1894 0 stevel } 1895 0 stevel 1896 0 stevel /* 1897 0 stevel * before copying the vtoc, the partition information in it should be 1898 0 stevel * checked against the information the driver already has on the 1899 0 stevel * diskette. 1900 0 stevel */ 1901 0 stevel 1902 0 stevel nblks = (fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack * 1903 7656 Sherry fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 1904 0 stevel if (nblks == 0 || fjp->fj_chars->fdc_ncyl == 0) 1905 0 stevel return (EFAULT); 1906 0 stevel vpart = vtocp->v_part; 1907 0 stevel 1908 0 stevel /* 1909 0 stevel * Check the partition information in the vtoc. The starting sectors 1910 0 stevel * must lie along cylinder boundaries. (NDKMAP entries are checked 1911 0 stevel * to ensure that the unused entries are set to 0 if vtoc->v_nparts 1912 0 stevel * is less than NDKMAP) 1913 0 stevel */ 1914 0 stevel for (i = NDKMAP; i; i--) { 1915 0 stevel if ((vpart->p_start % nblks) != 0) { 1916 0 stevel return (EINVAL); 1917 0 stevel } 1918 0 stevel ncyl = vpart->p_start / nblks; 1919 0 stevel ncyl += vpart->p_size / nblks; 1920 0 stevel if ((vpart->p_size % nblks) != 0) 1921 0 stevel ncyl++; 1922 0 stevel if (ncyl > (long)fjp->fj_chars->fdc_ncyl) { 1923 0 stevel return (EINVAL); 1924 0 stevel } 1925 0 stevel vpart++; 1926 0 stevel } 1927 0 stevel 1928 0 stevel 1929 0 stevel bcopy(vtocp->v_bootinfo, fdp->d_vtoc_bootinfo, 1930 0 stevel sizeof (vtocp->v_bootinfo)); 1931 0 stevel fdp->d_vtoc_version = vtocp->v_version; 1932 0 stevel bcopy(vtocp->v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL); 1933 0 stevel 1934 0 stevel /* 1935 0 stevel * Copy partitioning information. 1936 0 stevel */ 1937 0 stevel bcopy(vtocp->v_part, fdp->d_part, sizeof (struct partition) * NDKMAP); 1938 0 stevel bcopy(vtocp->timestamp, fdp->d_vtoc_timestamp, 1939 0 stevel sizeof (fdp->d_vtoc_timestamp)); 1940 0 stevel bcopy(vtocp->v_asciilabel, fdp->d_vtoc_asciilabel, LEN_DKL_ASCII); 1941 0 stevel 1942 0 stevel /* 1943 0 stevel * construct the diskette label in supplied buffer 1944 0 stevel */ 1945 0 stevel 1946 0 stevel /* Put appropriate vtoc structure fields into the disk label */ 1947 0 stevel labelp->dkl_vtoc.v_bootinfo[0] = (uint32_t)vtocp->v_bootinfo[0]; 1948 0 stevel labelp->dkl_vtoc.v_bootinfo[1] = (uint32_t)vtocp->v_bootinfo[1]; 1949 0 stevel labelp->dkl_vtoc.v_bootinfo[2] = (uint32_t)vtocp->v_bootinfo[2]; 1950 0 stevel 1951 0 stevel labelp->dkl_vtoc.v_sanity = vtocp->v_sanity; 1952 0 stevel labelp->dkl_vtoc.v_version = vtocp->v_version; 1953 0 stevel 1954 0 stevel bcopy(vtocp->v_volume, labelp->dkl_vtoc.v_volume, LEN_DKL_VVOL); 1955 0 stevel 1956 0 stevel labelp->dkl_vtoc.v_nparts = vtocp->v_nparts; 1957 0 stevel 1958 0 stevel bcopy(vtocp->v_reserved, labelp->dkl_vtoc.v_reserved, 1959 0 stevel sizeof (labelp->dkl_vtoc.v_reserved)); 1960 0 stevel 1961 0 stevel for (i = 0; i < (int)vtocp->v_nparts; i++) { 1962 0 stevel labelp->dkl_vtoc.v_part[i].p_tag = vtocp->v_part[i].p_tag; 1963 0 stevel labelp->dkl_vtoc.v_part[i].p_flag = vtocp->v_part[i].p_flag; 1964 0 stevel labelp->dkl_vtoc.v_part[i].p_start = vtocp->v_part[i].p_start; 1965 0 stevel labelp->dkl_vtoc.v_part[i].p_size = vtocp->v_part[i].p_size; 1966 0 stevel } 1967 0 stevel 1968 0 stevel for (i = 0; i < NDKMAP; i++) { 1969 0 stevel labelp->dkl_vtoc.v_timestamp[i] = vtocp->timestamp[i]; 1970 0 stevel } 1971 0 stevel bcopy(vtocp->v_asciilabel, labelp->dkl_asciilabel, LEN_DKL_ASCII); 1972 0 stevel 1973 0 stevel 1974 0 stevel labelp->dkl_pcyl = fjp->fj_chars->fdc_ncyl; 1975 0 stevel labelp->dkl_ncyl = fjp->fj_chars->fdc_ncyl; 1976 0 stevel labelp->dkl_nhead = fjp->fj_chars->fdc_nhead; 1977 0 stevel /* 1978 0 stevel * The fdc_secptrack field of the fd_char structure is the number 1979 0 stevel * of sectors per track where the sectors are fdc_sec_size. 1980 0 stevel * The dkl_nsect field of the dk_label structure is the number of 1981 0 stevel * DEV_BSIZE (512) byte sectors per track. 1982 0 stevel */ 1983 0 stevel labelp->dkl_nsect = (fjp->fj_chars->fdc_secptrack * 1984 0 stevel fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 1985 0 stevel labelp->dkl_intrlv = fjp->fj_attr->fda_intrlv; 1986 0 stevel labelp->dkl_rpm = fjp->fj_attr->fda_rotatespd; 1987 0 stevel labelp->dkl_read_reinstruct = 1988 0 stevel (int)(labelp->dkl_nsect * labelp->dkl_rpm * 4) / 60000; 1989 0 stevel labelp->dkl_write_reinstruct = labelp->dkl_read_reinstruct; 1990 0 stevel 1991 0 stevel labelp->dkl_magic = DKL_MAGIC; 1992 0 stevel 1993 0 stevel sum = 0; 1994 0 stevel labelp->dkl_cksum = 0; 1995 0 stevel sp = (ushort_t *)labelp; 1996 0 stevel while (sp < &(labelp->dkl_cksum)) { 1997 0 stevel sum ^= *sp++; 1998 0 stevel } 1999 0 stevel labelp->dkl_cksum = sum; 2000 0 stevel 2001 0 stevel return (0); 2002 0 stevel } 2003 0 stevel 2004 0 stevel static int 2005 0 stevel fd_rawioctl(struct fcu_obj *fjp, int unit, caddr_t arg, int mode) 2006 0 stevel { 2007 0 stevel struct fd_raw fdr; 2008 0 stevel char *arg_result = NULL; 2009 0 stevel int flag = B_READ; 2010 0 stevel int rval = 0; 2011 0 stevel caddr_t uaddr; 2012 0 stevel uint_t ucount; 2013 0 stevel 2014 0 stevel FDERRPRINT(FDEP_L1, FDEM_RAWI, 2015 0 stevel (CE_CONT, "fd_rawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0])); 2016 0 stevel 2017 0 stevel if (fjp->fj_chars->fdc_medium != 3 && fjp->fj_chars->fdc_medium != 5) { 2018 0 stevel cmn_err(CE_CONT, "fd_rawioctl: Medium density not supported\n"); 2019 0 stevel return (ENXIO); 2020 0 stevel } 2021 0 stevel 2022 0 stevel #ifdef _MULTI_DATAMODEL 2023 0 stevel switch (ddi_model_convert_from(mode & FMODELS)) { 2024 0 stevel case DDI_MODEL_ILP32: 2025 0 stevel { 2026 0 stevel struct fd_raw32 fdr32; 2027 0 stevel 2028 0 stevel if (ddi_copyin(arg, &fdr32, sizeof (fdr32), mode)) 2029 0 stevel return (EFAULT); 2030 0 stevel 2031 0 stevel bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd)); 2032 0 stevel fdr.fdr_cnum = fdr32.fdr_cnum; 2033 0 stevel fdr.fdr_nbytes = fdr32.fdr_nbytes; 2034 0 stevel fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr; 2035 0 stevel arg_result = ((struct fd_raw32 *)arg)->fdr_result; 2036 0 stevel 2037 0 stevel break; 2038 0 stevel } 2039 0 stevel case DDI_MODEL_NONE: 2040 0 stevel #endif /* ! _MULTI_DATAMODEL */ 2041 0 stevel 2042 0 stevel if (ddi_copyin(arg, &fdr, sizeof (fdr), mode)) 2043 0 stevel return (EFAULT); 2044 0 stevel 2045 0 stevel arg_result = ((struct fd_raw *)arg)->fdr_result; 2046 0 stevel 2047 0 stevel #ifdef _MULTI_DATAMODEL 2048 0 stevel break; 2049 0 stevel } 2050 0 stevel #endif /* _MULTI_DATAMODEL */ 2051 0 stevel 2052 0 stevel 2053 0 stevel 2054 0 stevel /* 2055 0 stevel * copy user address & nbytes from raw_req so that we can 2056 0 stevel * put kernel address in req structure 2057 0 stevel */ 2058 0 stevel uaddr = fdr.fdr_addr; 2059 0 stevel ucount = (uint_t)fdr.fdr_nbytes; 2060 0 stevel unit &= 3; 2061 0 stevel 2062 0 stevel switch (fdr.fdr_cmd[0] & 0x0f) { 2063 0 stevel 2064 0 stevel case FDRAW_FORMAT: 2065 0 stevel ucount += 16; 2066 0 stevel fdr.fdr_addr = kmem_zalloc(ucount, KM_SLEEP); 2067 0 stevel if (ddi_copyin(uaddr, fdr.fdr_addr, 2068 0 stevel (size_t)fdr.fdr_nbytes, mode)) { 2069 0 stevel kmem_free(fdr.fdr_addr, ucount); 2070 0 stevel return (EFAULT); 2071 0 stevel } 2072 0 stevel if ((*fdr.fdr_addr | fdr.fdr_addr[1]) == 0) 2073 0 stevel fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 2074 0 stevel flag = B_WRITE; 2075 0 stevel fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 2076 0 stevel break; 2077 0 stevel 2078 0 stevel case FDRAW_WRCMD: 2079 0 stevel case FDRAW_WRITEDEL: 2080 0 stevel flag = B_WRITE; 2081 0 stevel /* FALLTHROUGH */ 2082 0 stevel case FDRAW_RDCMD: 2083 0 stevel case FDRAW_READDEL: 2084 0 stevel case FDRAW_READTRACK: 2085 0 stevel if (ucount) { 2086 0 stevel /* 2087 0 stevel * In SunOS 4.X, we used to as_fault things in. 2088 0 stevel * We really cannot do this in 5.0/SVr4. Unless 2089 0 stevel * someone really believes that speed is of the 2090 0 stevel * essence here, it is just much simpler to do 2091 0 stevel * this in kernel space and use copyin/copyout. 2092 0 stevel */ 2093 0 stevel fdr.fdr_addr = kmem_alloc((size_t)ucount, KM_SLEEP); 2094 0 stevel if (flag == B_WRITE) { 2095 0 stevel if (ddi_copyin(uaddr, fdr.fdr_addr, ucount, 2096 0 stevel mode)) { 2097 0 stevel kmem_free(fdr.fdr_addr, ucount); 2098 0 stevel return (EFAULT); 2099 0 stevel } 2100 0 stevel } 2101 0 stevel } else 2102 0 stevel return (EINVAL); 2103 0 stevel fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 2104 0 stevel break; 2105 0 stevel 2106 0 stevel case FDRAW_READID: 2107 0 stevel case FDRAW_REZERO: 2108 0 stevel case FDRAW_SEEK: 2109 0 stevel case FDRAW_SENSE_DRV: 2110 0 stevel ucount = 0; 2111 0 stevel fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 2112 0 stevel break; 2113 0 stevel 2114 0 stevel case FDRAW_SPECIFY: 2115 0 stevel fdr.fdr_cmd[2] &= 0xfe; /* keep NoDMA bit clear */ 2116 0 stevel /* FALLTHROUGH */ 2117 0 stevel case FDRAW_SENSE_INT: 2118 0 stevel ucount = 0; 2119 0 stevel break; 2120 0 stevel 2121 0 stevel default: 2122 0 stevel return (EINVAL); 2123 0 stevel } 2124 0 stevel 2125 0 stevel /* 2126 0 stevel * Note that we ignore any error returns from controller 2127 0 stevel * This is the way the driver has been, and it may be 2128 0 stevel * that the raw ioctl senders simply don't want to 2129 0 stevel * see any errors returned in this fashion. 2130 0 stevel */ 2131 0 stevel 2132 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 2133 0 stevel rval = fjp->fj_ops->fco_rwioctl(fjp, unit, (caddr_t)&fdr); 2134 0 stevel 2135 0 stevel if (ucount && flag == B_READ && rval == 0) { 2136 0 stevel if (ddi_copyout(fdr.fdr_addr, uaddr, ucount, mode)) { 2137 0 stevel rval = EFAULT; 2138 0 stevel } 2139 0 stevel } 2140 0 stevel if (ddi_copyout(fdr.fdr_result, arg_result, sizeof (fdr.fdr_cmd), mode)) 2141 0 stevel rval = EFAULT; 2142 0 stevel 2143 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 2144 0 stevel if (ucount) 2145 0 stevel kmem_free(fdr.fdr_addr, ucount); 2146 0 stevel 2147 0 stevel return (rval); 2148 0 stevel } 2149 0 stevel 2150 0 stevel /* 2151 0 stevel * property operation routine. return the number of blocks for the partition 2152 0 stevel * in question or forward the request to the property facilities. 2153 0 stevel */ 2154 0 stevel static int 2155 0 stevel fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 2156 0 stevel char *name, caddr_t valuep, int *lengthp) 2157 0 stevel { 2158 0 stevel struct fcu_obj *fjp = NULL; 2159 0 stevel struct fdisk *fdp = NULL; 2160 0 stevel uint64_t nblocks64; 2161 0 stevel 2162 0 stevel FDERRPRINT(FDEP_L1, FDEM_PROP, 2163 0 stevel (CE_CONT, "fd_prop_op: dip %p %s\n", (void *)dip, name)); 2164 0 stevel 2165 0 stevel /* 2166 0 stevel * Our dynamic properties are all device specific and size oriented. 2167 0 stevel * Requests issued under conditions where size is valid are passed 2168 0 stevel * to ddi_prop_op_nblocks with the size information, otherwise the 2169 0 stevel * request is passed to ddi_prop_op. 2170 0 stevel */ 2171 0 stevel if (dev == DDI_DEV_T_ANY) { 2172 0 stevel pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 2173 0 stevel name, valuep, lengthp)); 2174 0 stevel } else { 2175 0 stevel /* 2176 0 stevel * Ignoring return value because success is checked by 2177 0 stevel * verifying fjp and fdp and returned unit value is not used. 2178 0 stevel */ 2179 0 stevel (void) fd_getdrive(dev, &fjp, &fdp); 2180 0 stevel if (!fjp || !fdp) 2181 0 stevel goto pass; 2182 0 stevel 2183 0 stevel /* get nblocks value */ 2184 0 stevel nblocks64 = (ulong_t)fdp->d_part[PARTITION(dev)].p_size; 2185 0 stevel 2186 0 stevel return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags, 2187 0 stevel name, valuep, lengthp, nblocks64)); 2188 0 stevel } 2189 0 stevel } 2190 0 stevel 2191 0 stevel static void 2192 0 stevel fd_media_watch(void *arg) 2193 0 stevel { 2194 0 stevel struct fcu_obj *fjp; 2195 0 stevel struct fdisk *fdp; 2196 0 stevel 2197 0 stevel #ifdef DEBUG 2198 0 stevel int unit; 2199 0 stevel #define DEBUG_ASSIGN unit= 2200 0 stevel #else 2201 0 stevel #define DEBUG_ASSIGN (void) 2202 0 stevel #endif 2203 0 stevel DEBUG_ASSIGN fd_getdrive((dev_t)arg, &fjp, &fdp); 2204 0 stevel /* 2205 0 stevel * Ignoring return in non DEBUG mode because device exist. 2206 0 stevel * Returned unit value is not used. 2207 0 stevel */ 2208 0 stevel 2209 0 stevel FDERRPRINT(FDEP_L0, FDEM_IOCT, 2210 0 stevel (CE_CONT, "fd_media_watch unit %d\n", unit)); 2211 0 stevel 2212 0 stevel /* 2213 0 stevel * fd_get_media_state() cannot be called from this timeout function 2214 0 stevel * because the floppy drive has to be selected first, and that could 2215 0 stevel * force this function to sleep (while waiting for the select 2216 0 stevel * semaphore). 2217 0 stevel * Instead, just wakeup up driver. 2218 0 stevel */ 2219 0 stevel mutex_enter(&fjp->fj_lock); 2220 0 stevel cv_broadcast(&fdp->d_statecv); 2221 0 stevel mutex_exit(&fjp->fj_lock); 2222 0 stevel } 2223 0 stevel 2224 0 stevel enum dkio_state 2225 0 stevel fd_get_media_state(struct fcu_obj *fjp, int unit) 2226 0 stevel { 2227 0 stevel enum dkio_state state; 2228 0 stevel 2229 0 stevel if (fjp->fj_ops->fco_getchng(fjp, unit)) { 2230 0 stevel /* recheck disk only if DSKCHG "high" */ 2231 0 stevel fjp->fj_ops->fco_resetchng(fjp, unit); 2232 0 stevel if (fjp->fj_ops->fco_getchng(fjp, unit)) { 2233 0 stevel if (fjp->fj_flags & FUNIT_CHGDET) { 2234 0 stevel /* 2235 0 stevel * again no diskette; not a new change 2236 0 stevel */ 2237 0 stevel state = DKIO_NONE; 2238 0 stevel } else { 2239 0 stevel /* 2240 0 stevel * a new change; diskette was ejected 2241 0 stevel */ 2242 0 stevel fjp->fj_flags |= FUNIT_CHGDET; 2243 0 stevel state = DKIO_EJECTED; 2244 0 stevel } 2245 0 stevel } else { 2246 0 stevel fjp->fj_flags &= ~FUNIT_CHGDET; 2247 0 stevel state = DKIO_INSERTED; 2248 0 stevel } 2249 0 stevel } else { 2250 0 stevel fjp->fj_flags &= ~FUNIT_CHGDET; 2251 0 stevel state = DKIO_INSERTED; 2252 0 stevel } 2253 0 stevel FDERRPRINT(FDEP_L0, FDEM_IOCT, 2254 0 stevel (CE_CONT, "fd_get_media_state unit %d: state %x\n", unit, state)); 2255 0 stevel return (state); 2256 0 stevel } 2257 0 stevel 2258 0 stevel static int 2259 0 stevel fd_check_media(dev_t dev, enum dkio_state state) 2260 0 stevel { 2261 0 stevel struct fcu_obj *fjp; 2262 0 stevel struct fdisk *fdp; 2263 0 stevel int unit; 2264 0 stevel int err; 2265 0 stevel 2266 0 stevel unit = fd_getdrive(dev, &fjp, &fdp); 2267 0 stevel 2268 0 stevel mutex_enter(&fjp->fj_lock); 2269 0 stevel 2270 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 2271 0 stevel fdp->d_media_state = fd_get_media_state(fjp, unit); 2272 0 stevel fdp->d_media_timeout = drv_usectohz(fd_check_media_time); 2273 0 stevel 2274 0 stevel while (fdp->d_media_state == state) { 2275 0 stevel /* release the controller and drive */ 2276 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 2277 0 stevel 2278 0 stevel /* turn on timer */ 2279 0 stevel fdp->d_media_timeout_id = timeout(fd_media_watch, 2280 7656 Sherry (void *)dev, fdp->d_media_timeout); 2281 0 stevel 2282 0 stevel if (cv_wait_sig(&fdp->d_statecv, &fjp->fj_lock) == 0) { 2283 0 stevel fdp->d_media_timeout = 0; 2284 0 stevel mutex_exit(&fjp->fj_lock); 2285 0 stevel return (EINTR); 2286 0 stevel } 2287 0 stevel fjp->fj_ops->fco_select(fjp, unit, 1); 2288 0 stevel fdp->d_media_state = fd_get_media_state(fjp, unit); 2289 0 stevel } 2290 0 stevel 2291 0 stevel if (fdp->d_media_state == DKIO_INSERTED) { 2292 0 stevel err = fdgetlabel(fjp, unit); 2293 0 stevel if (err) { 2294 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 2295 0 stevel mutex_exit(&fjp->fj_lock); 2296 0 stevel return (EIO); 2297 0 stevel } 2298 0 stevel } 2299 0 stevel fjp->fj_ops->fco_select(fjp, unit, 0); 2300 0 stevel mutex_exit(&fjp->fj_lock); 2301 0 stevel return (0); 2302 0 stevel } 2303 0 stevel 2304 0 stevel /* 2305 0 stevel * fd_get_media_info : 2306 0 stevel * Collects medium information for 2307 0 stevel * DKIOCGMEDIAINFO ioctl. 2308 0 stevel */ 2309 0 stevel 2310 0 stevel static int 2311 0 stevel fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag) 2312 0 stevel { 2313 0 stevel struct dk_minfo media_info; 2314 0 stevel int err = 0; 2315 0 stevel 2316 0 stevel media_info.dki_media_type = DK_FLOPPY; 2317 0 stevel media_info.dki_lbsize = fjp->fj_chars->fdc_sec_size; 2318 0 stevel media_info.dki_capacity = fjp->fj_chars->fdc_ncyl * 2319 7656 Sherry fjp->fj_chars->fdc_secptrack * fjp->fj_chars->fdc_nhead; 2320 0 stevel 2321 0 stevel if (ddi_copyout(&media_info, buf, sizeof (struct dk_minfo), flag)) 2322 0 stevel err = EFAULT; 2323 0 stevel return (err); 2324 0 stevel } 2325