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