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 for (tries = nfdtypes; tries; tries--) { 814 if (try_this) { 815 fjp->fj_flags &= ~FUNIT_CHAROK; 816 817 /* try reading last sector of cyl 1, head 0 */ 818 if (!(rval = fjp->fj_ops->fco_rw(fjp, unit, 819 FDREAD, 1, 0, fjp->fj_chars->fdc_secptrack, 820 (caddr_t)label, 821 sizeof (struct dk_label))) && 822 /* and last sector plus 1 of cylinder 1 */ 823 fjp->fj_ops->fco_rw(fjp, unit, FDREAD, 1, 824 0, fjp->fj_chars->fdc_secptrack + 1, 825 (caddr_t)label, 826 sizeof (struct dk_label)) && 827 /* and label sector on cylinder 0 */ 828 !(rval = fjp->fj_ops->fco_rw(fjp, unit, 829 FDREAD, 0, 0, 1, (caddr_t)label, 830 sizeof (struct dk_label)))) 831 break; 832 if (rval == ENXIO) 833 break; 834 } 835 /* 836 * try the next entry in the characteristics tbl 837 */ 838 fdp->d_curfdtype = (signed char)nexttype; 839 nexttype = (nexttype + 1) % nfdtypes; 840 if ((1 << fdp->d_curfdtype) & fdp->d_media) { 841 *fjp->fj_chars = *defchar[fdp->d_curfdtype]; 842 *fjp->fj_attr = fdtypes[fdp->d_curfdtype]; 843 bcopy(fdparts[fdp->d_curfdtype], fdp->d_part, 844 sizeof (struct partition) * NDKMAP); 845 /* 846 * check for a double_density diskette 847 * in a high_density 5.25" drive 848 */ 849 if (fjp->fj_chars->fdc_transfer_rate == 250 && 850 fjp->fj_rotspd > fjp->fj_attr->fda_rotatespd) { 851 /* 852 * yes - adjust transfer rate since we don't 853 * know if we have a 5.25" dual-speed drive 854 */ 855 fjp->fj_attr->fda_rotatespd = 360; 856 fjp->fj_chars->fdc_transfer_rate = 300; 857 fjp->fj_chars->fdc_medium = 5; 858 } 859 if ((2 * fjp->fj_chars->fdc_ncyl) == 860 defchar[fdp->d_deffdtype]->fdc_ncyl) { 861 /* yes - adjust steps per cylinder */ 862 fjp->fj_chars->fdc_steps = 2; 863 } else 864 fjp->fj_chars->fdc_steps = 1; 865 try_this = 1; 866 } else 867 try_this = 0; 868 } 869 fderrlevel = oldlvl; /* print errors again */ 870 871 if (rval) { 872 fdp->d_curfdtype = fdp->d_deffdtype; 873 goto out; /* couldn't read anything */ 874 } 875 876 FDERRPRINT(FDEP_L0, FDEM_GETL, 877 (CE_CONT, 878 "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n", 879 unit, fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_secptrack, 880 fjp->fj_chars->fdc_steps, fjp->fj_attr->fda_rotatespd, 881 fjp->fj_attr->fda_intrlv)); 882 883 /* 884 * _something_ was read - look for unixtype label 885 */ 886 if (label->dkl_magic != DKL_MAGIC || 887 label->dkl_vtoc.v_sanity != VTOC_SANE) { 888 /* not a label - no magic number */ 889 goto nolabel; /* no errors, but no label */ 890 } 891 892 count = sizeof (struct dk_label) / sizeof (short); 893 sp = (short *)label; 894 xsum = 0; 895 while (count--) 896 xsum ^= *sp++; /* should add up to 0 */ 897 if (xsum) { 898 /* not a label - checksum didn't compute */ 899 goto nolabel; /* no errors, but no label */ 900 } 901 902 /* 903 * the SunOS label overrides current diskette characteristics 904 */ 905 fjp->fj_chars->fdc_ncyl = label->dkl_pcyl; 906 fjp->fj_chars->fdc_nhead = label->dkl_nhead; 907 fjp->fj_chars->fdc_secptrack = (label->dkl_nsect * DEV_BSIZE) / 908 fjp->fj_chars->fdc_sec_size; 909 if (defchar[fdp->d_deffdtype]->fdc_ncyl == 2 * fjp->fj_chars->fdc_ncyl) 910 fjp->fj_chars->fdc_steps = 2; 911 else 912 fjp->fj_chars->fdc_steps = 1; 913 914 fjp->fj_attr->fda_rotatespd = label->dkl_rpm; 915 fjp->fj_attr->fda_intrlv = label->dkl_intrlv; 916 917 fdp->d_vtoc_version = label->dkl_vtoc.v_version; 918 bcopy(label->dkl_vtoc.v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL); 919 bcopy(label->dkl_vtoc.v_asciilabel, 920 fdp->d_vtoc_asciilabel, LEN_DKL_ASCII); 921 /* 922 * logical partitions 923 */ 924 for (i = 0; i < NDKMAP; i++) { 925 fdp->d_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag; 926 fdp->d_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag; 927 fdp->d_part[i].p_start = label->dkl_vtoc.v_part[i].p_start; 928 fdp->d_part[i].p_size = label->dkl_vtoc.v_part[i].p_size; 929 930 fdp->d_vtoc_timestamp[i] = label->dkl_vtoc.timestamp[i]; 931 } 932 933 fjp->fj_flags |= FUNIT_LABELOK; 934 goto out; 935 936 nolabel: 937 /* 938 * if not found, fill in label info from default (mark default used) 939 */ 940 if (fdp->d_media & (1<<FMT_3D)) 941 newlabel = deflabel_35; 942 else /* if (fdp->d_media & (1<<FMT_5D9)) */ 943 newlabel = deflabel_525; 944 bzero(fdp->d_vtoc_volume, LEN_DKL_VVOL); 945 (void) sprintf(fdp->d_vtoc_asciilabel, newlabel, 946 fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_nhead, 947 fjp->fj_chars->fdc_secptrack); 948 fjp->fj_flags |= FUNIT_UNLABELED; 949 950 out: 951 kmem_free(label, sizeof (struct dk_label)); 952 return (rval); 953 } 954 955 956 /*ARGSUSED*/ 957 static int 958 fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 959 { 960 struct fcu_obj *fjp = NULL; 961 struct fdisk *fdp = NULL; 962 int part, part_is_closed; 963 964 #ifdef DEBUG 965 int unit; 966 #define DEBUG_ASSIGN unit= 967 #else 968 #define DEBUG_ASSIGN (void) 969 #endif 970 971 DEBUG_ASSIGN fd_getdrive(dev, &fjp, &fdp); 972 /* 973 * Ignoring return in non DEBUG mode because success is checked by 974 * verifying fjp and fdp and returned unit value is not used. 975 */ 976 if (!fjp || !fdp) 977 return (ENXIO); 978 part = PARTITION(dev); 979 980 sema_p(&fdp->d_ocsem); 981 FDERRPRINT(FDEP_L1, FDEM_CLOS, 982 (CE_CONT, "fd_close: fd unit %d part %d otype %x\n", 983 unit, part, otyp)); 984 985 if (otyp == OTYP_LYR) { 986 if (fdp->d_lyropen[part]) 987 fdp->d_lyropen[part]--; 988 part_is_closed = (fdp->d_lyropen[part] == 0); 989 } else { 990 fdp->d_regopen[otyp] &= ~(1<<part); 991 part_is_closed = 1; 992 } 993 if (part_is_closed) { 994 if (part == 2 && fdp->d_exclmask&(1<<part)) 995 fdp->d_exclmask = 0; 996 else 997 fdp->d_exclmask &= ~(1<<part); 998 FDERRPRINT(FDEP_L0, FDEM_CLOS, 999 (CE_CONT, 1000 "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n", 1001 fdp->d_exclmask, fdp->d_regopen[otyp], 1002 fdp->d_lyropen[part])); 1003 1004 if (fd_unit_is_open(fdp) == 0) 1005 fdp->d_obj->fj_flags &= ~FUNIT_CHANGED; 1006 } 1007 sema_v(&fdp->d_ocsem); 1008 return (0); 1009 } 1010 1011 /* ARGSUSED */ 1012 static int 1013 fd_read(dev_t dev, struct uio *uio, cred_t *cred_p) 1014 { 1015 return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio)); 1016 } 1017 1018 /* ARGSUSED */ 1019 static int 1020 fd_write(dev_t dev, struct uio *uio, cred_t *cred_p) 1021 { 1022 return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio)); 1023 } 1024 1025 /* 1026 * fd_strategy 1027 * checks operation, hangs buf struct off fdcntlr, calls fdstart 1028 * if not already busy. Note that if we call start, then the operation 1029 * will already be done on return (start sleeps). 1030 */ 1031 static int 1032 fd_strategy(struct buf *bp) 1033 { 1034 struct fcu_obj *fjp; 1035 struct fdisk *fdp; 1036 struct partition *pp; 1037 1038 FDERRPRINT(FDEP_L1, FDEM_STRA, 1039 (CE_CONT, "fd_strategy: bp = 0x%p, dev = 0x%lx\n", 1040 (void *)bp, bp->b_edev)); 1041 1042 (void) fd_getdrive(bp->b_edev, &fjp, &fdp); 1043 1044 /* 1045 * Ignoring return because device exist. 1046 * Returned unit value is not used. 1047 */ 1048 pp = &fdp->d_part[PARTITION(bp->b_edev)]; 1049 1050 if (fjp->fj_chars->fdc_sec_size > NBPSCTR && (bp->b_blkno & 1)) { 1051 FDERRPRINT(FDEP_L3, FDEM_STRA, 1052 (CE_WARN, "fd%d: block %ld is not start of sector!", 1053 DRIVE(bp->b_edev), (long)bp->b_blkno)); 1054 bp->b_error = EINVAL; 1055 goto bad; 1056 } 1057 1058 if ((bp->b_blkno > pp->p_size)) { 1059 FDERRPRINT(FDEP_L3, FDEM_STRA, 1060 (CE_WARN, "fd%d: block %ld is past the end! (nblk=%ld)", 1061 DRIVE(bp->b_edev), (long)bp->b_blkno, pp->p_size)); 1062 bp->b_error = ENOSPC; 1063 goto bad; 1064 } 1065 1066 /* if at end of file, skip out now */ 1067 if (bp->b_blkno == pp->p_size) { 1068 if ((bp->b_flags & B_READ) == 0) { 1069 /* a write needs to get an error! */ 1070 bp->b_error = ENOSPC; 1071 goto bad; 1072 } 1073 bp->b_resid = bp->b_bcount; 1074 biodone(bp); 1075 return (0); 1076 } 1077 1078 /* if operation not a multiple of sector size, is error! */ 1079 if (bp->b_bcount % fjp->fj_chars->fdc_sec_size) { 1080 FDERRPRINT(FDEP_L3, FDEM_STRA, 1081 (CE_WARN, "fd%d: count %ld must be a multiple of %d", 1082 DRIVE(bp->b_edev), bp->b_bcount, 1083 fjp->fj_chars->fdc_sec_size)); 1084 bp->b_error = EINVAL; 1085 goto bad; 1086 } 1087 1088 /* 1089 * Put the buf request in the drive's queue, FIFO. 1090 */ 1091 bp->av_forw = 0; 1092 mutex_enter(&fjp->fj_lock); 1093 if (fdp->d_iostat) 1094 kstat_waitq_enter(KIOSP); 1095 if (fdp->d_actf) 1096 fdp->d_actl->av_forw = bp; 1097 else 1098 fdp->d_actf = bp; 1099 fdp->d_actl = bp; 1100 if (!(fjp->fj_flags & FUNIT_BUSY)) { 1101 fdstart(fjp); 1102 } 1103 mutex_exit(&fjp->fj_lock); 1104 return (0); 1105 1106 bad: 1107 bp->b_resid = bp->b_bcount; 1108 bp->b_flags |= B_ERROR; 1109 biodone(bp); 1110 return (0); 1111 } 1112 1113 /* 1114 * fdstart 1115 * called from fd_strategy() or from fdXXXX() to setup and 1116 * start operations of read or write only (using buf structs). 1117 * Because the chip doesn't handle crossing cylinder boundaries on 1118 * the fly, this takes care of those boundary conditions. Note that 1119 * it sleeps until the operation is done *within fdstart* - so that 1120 * when fdstart returns, the operation is already done. 1121 */ 1122 static void 1123 fdstart(struct fcu_obj *fjp) 1124 { 1125 struct buf *bp; 1126 struct fdisk *fdp = (struct fdisk *)fjp->fj_data; 1127 struct fd_char *chp; 1128 struct partition *pp; 1129 uint_t ptend; 1130 uint_t bincyl; /* (the number of the desired) block in cyl. */ 1131 uint_t blk, len, tlen; 1132 uint_t secpcyl; /* number of sectors per cylinder */ 1133 int cyl, head, sect; 1134 int sctrshft, unit; 1135 caddr_t addr; 1136 1137 ASSERT(MUTEX_HELD(&fjp->fj_lock)); 1138 fjp->fj_flags |= FUNIT_BUSY; 1139 1140 while ((bp = fdp->d_actf) != NULL) { 1141 fdp->d_actf = bp->av_forw; 1142 fdp->d_current = bp; 1143 if (fdp->d_iostat) { 1144 kstat_waitq_to_runq(KIOSP); 1145 } 1146 mutex_exit(&fjp->fj_lock); 1147 1148 FDERRPRINT(FDEP_L0, FDEM_STRT, 1149 (CE_CONT, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n", 1150 (void *)bp, (long)bp->b_blkno, bp->b_bcount)); 1151 bp->b_flags &= ~B_ERROR; 1152 bp->b_error = 0; 1153 bp->b_resid = bp->b_bcount; /* init resid */ 1154 1155 ASSERT(DRIVE(bp->b_edev) == ddi_get_instance(fjp->fj_dip)); 1156 unit = fjp->fj_unit; 1157 fjp->fj_ops->fco_select(fjp, unit, 1); 1158 1159 bp_mapin(bp); /* map in buffers */ 1160 1161 pp = &fdp->d_part[PARTITION(bp->b_edev)]; 1162 /* starting blk adjusted for the partition */ 1163 blk = bp->b_blkno + pp->p_start; 1164 ptend = pp->p_start + pp->p_size; /* end of the partition */ 1165 1166 chp = fjp->fj_chars; 1167 secpcyl = chp->fdc_nhead * chp->fdc_secptrack; 1168 switch (chp->fdc_sec_size) { 1169 /* convert logical block numbers to sector numbers */ 1170 case 1024: 1171 sctrshft = SCTRSHFT + 1; 1172 blk >>= 1; 1173 ptend >>= 1; 1174 break; 1175 default: 1176 case NBPSCTR: 1177 sctrshft = SCTRSHFT; 1178 break; 1179 case 256: 1180 sctrshft = SCTRSHFT - 1; 1181 blk <<= 1; 1182 ptend <<= 1; 1183 break; 1184 } 1185 1186 /* 1187 * If off the end, limit to actual amount that 1188 * can be transferred. 1189 */ 1190 if ((blk + (bp->b_bcount >> sctrshft)) > ptend) 1191 /* to end of partition */ 1192 len = (ptend - blk) << sctrshft; 1193 else 1194 len = bp->b_bcount; 1195 addr = bp->b_un.b_addr; /* data buffer address */ 1196 1197 /* 1198 * now we have the real start blk, addr and len for xfer op 1199 */ 1200 while (len != 0) { 1201 /* start cyl of req */ 1202 cyl = blk / secpcyl; 1203 bincyl = blk % secpcyl; 1204 /* start head of req */ 1205 head = bincyl / chp->fdc_secptrack; 1206 /* start sector of req */ 1207 sect = (bincyl % chp->fdc_secptrack) + 1; 1208 /* 1209 * If the desired block and length will go beyond the 1210 * cylinder end, then limit it to the cylinder end. 1211 */ 1212 if (bp->b_flags & B_READ) { 1213 if (len > ((secpcyl - bincyl) << sctrshft)) 1214 tlen = (secpcyl - bincyl) << sctrshft; 1215 else 1216 tlen = len; 1217 } else { 1218 if (len > 1219 ((chp->fdc_secptrack - sect + 1) << 1220 sctrshft)) 1221 tlen = 1222 (chp->fdc_secptrack - sect + 1) << 1223 sctrshft; 1224 else 1225 tlen = len; 1226 } 1227 1228 FDERRPRINT(FDEP_L0, FDEM_STRT, (CE_CONT, 1229 " blk 0x%x addr 0x%p len 0x%x " 1230 "cyl %d head %d sec %d\n resid 0x%lx, tlen %d\n", 1231 blk, (void *)addr, len, cyl, head, sect, 1232 bp->b_resid, tlen)); 1233 1234 /* 1235 * (try to) do the operation - failure returns an errno 1236 */ 1237 bp->b_error = fjp->fj_ops->fco_rw(fjp, unit, 1238 bp->b_flags & B_READ, cyl, head, sect, addr, tlen); 1239 if (bp->b_error != 0) { 1240 FDERRPRINT(FDEP_L3, FDEM_STRT, (CE_WARN, 1241 "fdstart: bad exec of bp: 0x%p, err=%d", 1242 (void *)bp, bp->b_error)); 1243 bp->b_flags |= B_ERROR; 1244 break; 1245 } 1246 blk += tlen >> sctrshft; 1247 len -= tlen; 1248 addr += tlen; 1249 bp->b_resid -= tlen; 1250 } 1251 FDERRPRINT(FDEP_L0, FDEM_STRT, 1252 (CE_CONT, "fdstart done: b_resid %lu, b_count %lu\n", 1253 bp->b_resid, bp->b_bcount)); 1254 if (fdp->d_iostat) { 1255 if (bp->b_flags & B_READ) { 1256 KIOSP->reads++; 1257 KIOSP->nread += (bp->b_bcount - bp->b_resid); 1258 } else { 1259 KIOSP->writes++; 1260 KIOSP->nwritten += (bp->b_bcount - bp->b_resid); 1261 } 1262 kstat_runq_exit(KIOSP); 1263 } 1264 bp_mapout(bp); 1265 biodone(bp); 1266 1267 fjp->fj_ops->fco_select(fjp, unit, 0); 1268 mutex_enter(&fjp->fj_lock); 1269 fdp->d_current = 0; 1270 } 1271 fjp->fj_flags ^= FUNIT_BUSY; 1272 } 1273 1274 /* ARGSUSED */ 1275 static int 1276 fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, 1277 int *rval_p) 1278 { 1279 union { 1280 struct dk_cinfo dki; 1281 struct dk_geom dkg; 1282 struct dk_allmap dka; 1283 struct fd_char fdchar; 1284 struct fd_drive drvchar; 1285 int temp; 1286 } cpy; 1287 struct vtoc vtoc; 1288 struct fcu_obj *fjp = NULL; 1289 struct fdisk *fdp = NULL; 1290 struct dk_map *dmp; 1291 struct dk_label *label; 1292 int nblks, part, unit; 1293 int rval = 0; 1294 enum dkio_state state; 1295 1296 unit = fd_getdrive(dev, &fjp, &fdp); 1297 if (!fjp || !fdp) 1298 return (ENXIO); 1299 1300 FDERRPRINT(FDEP_L1, FDEM_IOCT, 1301 (CE_CONT, "fd_ioctl fd unit %d: cmd %x, arg %lx\n", 1302 unit, cmd, arg)); 1303 1304 switch (cmd) { 1305 case DKIOCINFO: 1306 fjp->fj_ops->fco_dkinfo(fjp, &cpy.dki); 1307 cpy.dki.dki_cnum = FDCTLR(fjp->fj_unit); 1308 cpy.dki.dki_unit = FDUNIT(fjp->fj_unit); 1309 cpy.dki.dki_partition = PARTITION(dev); 1310 if (ddi_copyout(&cpy.dki, (void *)arg, sizeof (cpy.dki), flag)) 1311 rval = EFAULT; 1312 break; 1313 1314 case DKIOCG_PHYGEOM: 1315 case DKIOCG_VIRTGEOM: 1316 cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack; 1317 goto get_geom; 1318 case DKIOCGGEOM: 1319 if (fjp->fj_flags & FUNIT_LABELOK) 1320 cpy.dkg.dkg_nsect = (fjp->fj_chars->fdc_secptrack * 1321 fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 1322 else 1323 cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack; 1324 get_geom: 1325 cpy.dkg.dkg_pcyl = fjp->fj_chars->fdc_ncyl; 1326 cpy.dkg.dkg_ncyl = fjp->fj_chars->fdc_ncyl; 1327 cpy.dkg.dkg_nhead = fjp->fj_chars->fdc_nhead; 1328 cpy.dkg.dkg_intrlv = fjp->fj_attr->fda_intrlv; 1329 cpy.dkg.dkg_rpm = fjp->fj_attr->fda_rotatespd; 1330 cpy.dkg.dkg_read_reinstruct = 1331 (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000; 1332 cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct; 1333 if (ddi_copyout(&cpy.dkg, (void *)arg, sizeof (cpy.dkg), flag)) 1334 rval = EFAULT; 1335 break; 1336 1337 case DKIOCSGEOM: 1338 if (ddi_copyin((void *)arg, &cpy.dkg, 1339 sizeof (struct dk_geom), flag)) { 1340 rval = EFAULT; 1341 break; 1342 } 1343 mutex_enter(&fjp->fj_lock); 1344 fjp->fj_chars->fdc_ncyl = cpy.dkg.dkg_ncyl; 1345 fjp->fj_chars->fdc_nhead = cpy.dkg.dkg_nhead; 1346 fjp->fj_chars->fdc_secptrack = cpy.dkg.dkg_nsect; 1347 fjp->fj_attr->fda_intrlv = cpy.dkg.dkg_intrlv; 1348 fjp->fj_attr->fda_rotatespd = cpy.dkg.dkg_rpm; 1349 fdp->d_curfdtype = -1; 1350 mutex_exit(&fjp->fj_lock); 1351 break; 1352 1353 /* 1354 * return the map of all logical partitions 1355 */ 1356 case DKIOCGAPART: 1357 /* 1358 * Note the conversion from starting sector number 1359 * to starting cylinder number. 1360 * Return error if division results in a remainder. 1361 */ 1362 nblks = fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack; 1363 1364 #ifdef _MULTI_DATAMODEL 1365 switch (ddi_model_convert_from(flag & FMODELS)) { 1366 case DDI_MODEL_ILP32: 1367 { 1368 struct dk_allmap32 dka32; 1369 1370 for (part = 0; part < NDKMAP; part++) { 1371 if ((fdp->d_part[part].p_start % nblks) != 0) 1372 return (EINVAL); 1373 dka32.dka_map[part].dkl_cylno = 1374 fdp->d_part[part].p_start / nblks; 1375 dka32.dka_map[part].dkl_nblk = 1376 fdp->d_part[part].p_size; 1377 } 1378 1379 if (ddi_copyout(&dka32, (void *)arg, 1380 sizeof (struct dk_allmap32), flag)) 1381 rval = EFAULT; 1382 1383 break; 1384 } 1385 case DDI_MODEL_NONE: 1386 1387 #endif /* _MULTI_DATAMODEL */ 1388 1389 dmp = (struct dk_map *)&cpy.dka; 1390 for (part = 0; part < NDKMAP; part++) { 1391 if ((fdp->d_part[part].p_start % nblks) != 0) 1392 return (EINVAL); 1393 dmp->dkl_cylno = 1394 fdp->d_part[part].p_start / nblks; 1395 dmp->dkl_nblk = fdp->d_part[part].p_size; 1396 dmp++; 1397 } 1398 1399 if (ddi_copyout(&cpy.dka, (void *)arg, 1400 sizeof (struct dk_allmap), flag)) 1401 rval = EFAULT; 1402 #ifdef _MULTI_DATAMODEL 1403 break; 1404 1405 } 1406 #endif /* _MULTI_DATAMODEL */ 1407 1408 break; 1409 1410 /* 1411 * Set the map of all logical partitions 1412 */ 1413 case DKIOCSAPART: 1414 1415 #ifdef _MULTI_DATAMODEL 1416 switch (ddi_model_convert_from(flag & FMODELS)) { 1417 case DDI_MODEL_ILP32: 1418 { 1419 struct dk_allmap32 dka32; 1420 1421 if (ddi_copyin((void *)arg, &dka32, 1422 sizeof (dka32), flag)) { 1423 rval = EFAULT; 1424 break; 1425 } 1426 for (part = 0; part < NDKMAP; part++) { 1427 cpy.dka.dka_map[part].dkl_cylno = 1428 dka32.dka_map[part].dkl_cylno; 1429 cpy.dka.dka_map[part].dkl_nblk = 1430 dka32.dka_map[part].dkl_nblk; 1431 } 1432 break; 1433 } 1434 case DDI_MODEL_NONE: 1435 1436 #endif /* _MULTI_DATAMODEL */ 1437 if (ddi_copyin((void *)arg, &cpy.dka, sizeof (cpy.dka), flag)) 1438 rval = EFAULT; 1439 #ifdef _MULTI_DATAMODEL 1440 1441 break; 1442 } 1443 #endif /* _MULTI_DATAMODEL */ 1444 1445 if (rval != 0) 1446 break; 1447 1448 dmp = (struct dk_map *)&cpy.dka; 1449 nblks = fjp->fj_chars->fdc_nhead * 1450 fjp->fj_chars->fdc_secptrack; 1451 mutex_enter(&fjp->fj_lock); 1452 /* 1453 * Note the conversion from starting cylinder number 1454 * to starting sector number. 1455 */ 1456 for (part = 0; part < NDKMAP; part++) { 1457 fdp->d_part[part].p_start = dmp->dkl_cylno * 1458 nblks; 1459 fdp->d_part[part].p_size = dmp->dkl_nblk; 1460 dmp++; 1461 } 1462 mutex_exit(&fjp->fj_lock); 1463 1464 break; 1465 1466 case DKIOCGVTOC: 1467 mutex_enter(&fjp->fj_lock); 1468 1469 /* 1470 * Exit if the diskette has no label. 1471 * Also, get the label to make sure the correct one is 1472 * being used since the diskette may have changed 1473 */ 1474 fjp->fj_ops->fco_select(fjp, unit, 1); 1475 rval = fdgetlabel(fjp, unit); 1476 fjp->fj_ops->fco_select(fjp, unit, 0); 1477 if (rval) { 1478 mutex_exit(&fjp->fj_lock); 1479 rval = EINVAL; 1480 break; 1481 } 1482 1483 fd_build_user_vtoc(fjp, fdp, &vtoc); 1484 mutex_exit(&fjp->fj_lock); 1485 1486 #ifdef _MULTI_DATAMODEL 1487 switch (ddi_model_convert_from(flag & FMODELS)) { 1488 case DDI_MODEL_ILP32: 1489 { 1490 struct vtoc32 vtoc32; 1491 1492 vtoctovtoc32(vtoc, vtoc32); 1493 1494 if (ddi_copyout(&vtoc32, (void *)arg, 1495 sizeof (vtoc32), flag)) 1496 rval = EFAULT; 1497 1498 break; 1499 } 1500 case DDI_MODEL_NONE: 1501 1502 #endif /* _MULTI_DATAMODEL */ 1503 if (ddi_copyout(&vtoc, (void *)arg, 1504 sizeof (vtoc), flag)) 1505 rval = EFAULT; 1506 #ifdef _MULTI_DATAMODEL 1507 break; 1508 } 1509 #endif /* _MULTI_DATAMODEL */ 1510 1511 break; 1512 1513 case DKIOCSVTOC: 1514 1515 #ifdef _MULTI_DATAMODEL 1516 switch (ddi_model_convert_from(flag & FMODELS)) { 1517 case DDI_MODEL_ILP32: 1518 { 1519 struct vtoc32 vtoc32; 1520 1521 if (ddi_copyin((void *)arg, &vtoc32, 1522 sizeof (vtoc32), flag)) { 1523 rval = EFAULT; 1524 break; 1525 } 1526 1527 vtoc32tovtoc(vtoc32, vtoc); 1528 1529 break; 1530 } 1531 case DDI_MODEL_NONE: 1532 1533 #endif /* _MULTI_DATAMODEL */ 1534 if (ddi_copyin((void *)arg, &vtoc, sizeof (vtoc), flag)) 1535 rval = EFAULT; 1536 #ifdef _MULTI_DATAMODEL 1537 break; 1538 } 1539 #endif /* _MULTI_DATAMODEL */ 1540 1541 if (rval != 0) 1542 break; 1543 1544 1545 label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 1546 1547 mutex_enter(&fjp->fj_lock); 1548 1549 if ((rval = fd_build_label_vtoc(fjp, fdp, &vtoc, label)) == 0) { 1550 fjp->fj_ops->fco_select(fjp, unit, 1); 1551 rval = fjp->fj_ops->fco_rw(fjp, unit, FDWRITE, 1552 0, 0, 1, (caddr_t)label, sizeof (struct dk_label)); 1553 fjp->fj_ops->fco_select(fjp, unit, 0); 1554 } 1555 mutex_exit(&fjp->fj_lock); 1556 kmem_free(label, sizeof (struct dk_label)); 1557 break; 1558 1559 case DKIOCSTATE: 1560 FDERRPRINT(FDEP_L1, FDEM_IOCT, 1561 (CE_CONT, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit)); 1562 1563 if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) { 1564 rval = EFAULT; 1565 break; 1566 } 1567 1568 rval = fd_check_media(dev, state); 1569 1570 if (ddi_copyout(&fdp->d_media_state, (void *)arg, 1571 sizeof (int), flag)) 1572 rval = EFAULT; 1573 break; 1574 1575 case FDIOGCHAR: 1576 if (ddi_copyout(fjp->fj_chars, (void *)arg, 1577 sizeof (struct fd_char), flag)) 1578 rval = EFAULT; 1579 break; 1580 1581 case FDIOSCHAR: 1582 if (ddi_copyin((void *)arg, &cpy.fdchar, 1583 sizeof (struct fd_char), flag)) { 1584 rval = EFAULT; 1585 break; 1586 } 1587 switch (cpy.fdchar.fdc_transfer_rate) { 1588 case 417: 1589 if ((fdp->d_media & (1 << FMT_3M)) == 0) { 1590 cmn_err(CE_CONT, 1591 "fdioschar:Medium density not supported\n"); 1592 rval = EINVAL; 1593 break; 1594 } 1595 mutex_enter(&fjp->fj_lock); 1596 fjp->fj_attr->fda_rotatespd = 360; 1597 mutex_exit(&fjp->fj_lock); 1598 /* cpy.fdchar.fdc_transfer_rate = 500; */ 1599 /* FALLTHROUGH */ 1600 case 1000: 1601 case 500: 1602 case 300: 1603 case 250: 1604 mutex_enter(&fjp->fj_lock); 1605 *(fjp->fj_chars) = cpy.fdchar; 1606 fdp->d_curfdtype = -1; 1607 fjp->fj_flags &= ~FUNIT_CHAROK; 1608 mutex_exit(&fjp->fj_lock); 1609 1610 break; 1611 1612 default: 1613 FDERRPRINT(FDEP_L4, FDEM_IOCT, 1614 (CE_WARN, "fd_ioctl fd unit %d: FDIOSCHAR odd " 1615 "xfer rate %dkbs", 1616 unit, cpy.fdchar.fdc_transfer_rate)); 1617 rval = EINVAL; 1618 break; 1619 } 1620 break; 1621 1622 /* 1623 * set all characteristics and geometry to the defaults 1624 */ 1625 case FDDEFGEOCHAR: 1626 mutex_enter(&fjp->fj_lock); 1627 fdp->d_curfdtype = fdp->d_deffdtype; 1628 *fjp->fj_chars = *defchar[fdp->d_curfdtype]; 1629 *fjp->fj_attr = fdtypes[fdp->d_curfdtype]; 1630 bcopy(fdparts[fdp->d_curfdtype], 1631 fdp->d_part, sizeof (struct partition) * NDKMAP); 1632 fjp->fj_flags &= ~FUNIT_CHAROK; 1633 mutex_exit(&fjp->fj_lock); 1634 break; 1635 1636 case FDEJECT: /* eject disk */ 1637 case DKIOCEJECT: 1638 fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 1639 rval = ENOSYS; 1640 break; 1641 1642 case FDGETCHANGE: /* disk changed */ 1643 if (ddi_copyin((void *)arg, &cpy.temp, sizeof (int), flag)) { 1644 rval = EFAULT; 1645 break; 1646 } 1647 mutex_enter(&fjp->fj_lock); 1648 fjp->fj_ops->fco_select(fjp, unit, 1); 1649 1650 if (fjp->fj_flags & FUNIT_CHANGED) 1651 cpy.temp |= FDGC_HISTORY; 1652 else 1653 cpy.temp &= ~FDGC_HISTORY; 1654 fjp->fj_flags &= ~FUNIT_CHANGED; 1655 1656 if (fjp->fj_ops->fco_getchng(fjp, unit)) { 1657 cpy.temp |= FDGC_DETECTED; 1658 fjp->fj_ops->fco_resetchng(fjp, unit); 1659 /* 1660 * check diskette again only if it was removed 1661 */ 1662 if (fjp->fj_ops->fco_getchng(fjp, unit)) { 1663 /* 1664 * no diskette is present 1665 */ 1666 cpy.temp |= FDGC_CURRENT; 1667 if (fjp->fj_flags & FUNIT_CHGDET) 1668 /* 1669 * again no diskette; not a new change 1670 */ 1671 cpy.temp ^= FDGC_DETECTED; 1672 else 1673 fjp->fj_flags |= FUNIT_CHGDET; 1674 } else { 1675 /* 1676 * a new diskette is present 1677 */ 1678 cpy.temp &= ~FDGC_CURRENT; 1679 fjp->fj_flags &= ~FUNIT_CHGDET; 1680 } 1681 } else { 1682 cpy.temp &= ~(FDGC_DETECTED | FDGC_CURRENT); 1683 fjp->fj_flags &= ~FUNIT_CHGDET; 1684 } 1685 /* 1686 * also get state of write protection 1687 */ 1688 if (fjp->fj_flags & FUNIT_WPROT) { 1689 cpy.temp |= FDGC_CURWPROT; 1690 } else { 1691 cpy.temp &= ~FDGC_CURWPROT; 1692 } 1693 fjp->fj_ops->fco_select(fjp, unit, 0); 1694 mutex_exit(&fjp->fj_lock); 1695 1696 if (ddi_copyout(&cpy.temp, (void *)arg, sizeof (int), flag)) 1697 rval = EFAULT; 1698 break; 1699 1700 case FDGETDRIVECHAR: 1701 if (ddi_copyout(fjp->fj_drive, (void *)arg, 1702 sizeof (struct fd_drive), flag)) 1703 rval = EFAULT; 1704 break; 1705 1706 case FDSETDRIVECHAR: 1707 if (ddi_copyin((void *)arg, &cpy.drvchar, 1708 sizeof (struct fd_drive), flag)) { 1709 rval = EFAULT; 1710 break; 1711 } 1712 mutex_enter(&fjp->fj_lock); 1713 *(fjp->fj_drive) = cpy.drvchar; 1714 fdp->d_curfdtype = -1; 1715 fjp->fj_flags &= ~FUNIT_CHAROK; 1716 mutex_exit(&fjp->fj_lock); 1717 break; 1718 1719 case DKIOCREMOVABLE: { 1720 int i = 1; 1721 1722 /* no brainer: floppies are always removable */ 1723 if (ddi_copyout(&i, (void *)arg, sizeof (int), flag)) { 1724 rval = EFAULT; 1725 } 1726 break; 1727 } 1728 1729 case DKIOCGMEDIAINFO: 1730 rval = fd_get_media_info(fjp, (caddr_t)arg, flag); 1731 break; 1732 1733 case FDIOCMD: 1734 { 1735 struct fd_cmd fc; 1736 int cyl, head, spc, spt; 1737 1738 #ifdef _MULTI_DATAMODEL 1739 switch (ddi_model_convert_from(flag & FMODELS)) { 1740 case DDI_MODEL_ILP32: 1741 { 1742 struct fd_cmd32 fc32; 1743 1744 if (ddi_copyin((void *)arg, &fc32, 1745 sizeof (fc32), flag)) { 1746 rval = EFAULT; 1747 break; 1748 } 1749 1750 fc.fdc_cmd = fc32.fdc_cmd; 1751 fc.fdc_flags = fc32.fdc_flags; 1752 fc.fdc_blkno = fc32.fdc_blkno; 1753 fc.fdc_secnt = fc32.fdc_secnt; 1754 fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr; 1755 fc.fdc_buflen = fc32.fdc_buflen; 1756 1757 break; 1758 } 1759 case DDI_MODEL_NONE: 1760 1761 #endif /* _MULTI_DATAMODEL */ 1762 1763 if (ddi_copyin((void *)arg, &fc, sizeof (fc), flag)) { 1764 rval = EFAULT; 1765 break; 1766 } 1767 #ifdef _MULTI_DATAMODEL 1768 break; 1769 } 1770 #endif /* _MULTI_DATAMODEL */ 1771 1772 if (rval != 0) 1773 break; 1774 1775 if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) { 1776 auto struct iovec aiov; 1777 auto struct uio auio; 1778 struct uio *uio = &auio; 1779 1780 spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE; 1781 1782 bzero(&auio, sizeof (struct uio)); 1783 bzero(&aiov, sizeof (struct iovec)); 1784 aiov.iov_base = fc.fdc_bufaddr; 1785 aiov.iov_len = (uint_t)fc.fdc_secnt * 1786 fjp->fj_chars->fdc_sec_size; 1787 uio->uio_iov = &aiov; 1788 1789 uio->uio_iovcnt = 1; 1790 uio->uio_resid = aiov.iov_len; 1791 uio->uio_segflg = UIO_USERSPACE; 1792 1793 rval = physio(fd_strategy, (struct buf *)0, dev, 1794 spc, minphys, uio); 1795 break; 1796 } else if (fc.fdc_cmd == FDCMD_FORMAT_TRACK) { 1797 spt = fjp->fj_chars->fdc_secptrack; /* sec/trk */ 1798 spc = fjp->fj_chars->fdc_nhead * spt; /* sec/cyl */ 1799 cyl = fc.fdc_blkno / spc; 1800 head = (fc.fdc_blkno % spc) / spt; 1801 if ((cyl | head) == 0) 1802 fjp->fj_flags &= 1803 ~(FUNIT_LABELOK | FUNIT_UNLABELED); 1804 1805 FDERRPRINT(FDEP_L0, FDEM_FORM, 1806 (CE_CONT, "fd_format cyl %d, hd %d\n", cyl, head)); 1807 fjp->fj_ops->fco_select(fjp, unit, 1); 1808 rval = fjp->fj_ops->fco_format(fjp, unit, cyl, head, 1809 (int)fc.fdc_flags); 1810 fjp->fj_ops->fco_select(fjp, unit, 0); 1811 1812 break; 1813 } 1814 FDERRPRINT(FDEP_L4, FDEM_IOCT, 1815 (CE_WARN, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete", 1816 unit)); 1817 rval = EINVAL; 1818 break; 1819 } 1820 1821 case FDRAW: 1822 rval = fd_rawioctl(fjp, unit, (caddr_t)arg, flag); 1823 break; 1824 1825 default: 1826 FDERRPRINT(FDEP_L4, FDEM_IOCT, 1827 (CE_WARN, "fd_ioctl fd unit %d: invalid ioctl 0x%x", 1828 unit, cmd)); 1829 rval = ENOTTY; 1830 break; 1831 } 1832 return (rval); 1833 } 1834 1835 static void 1836 fd_build_user_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp) 1837 { 1838 struct partition *vpart; 1839 int i; 1840 int xblk; 1841 1842 /* 1843 * Return vtoc structure fields in the provided VTOC area, addressed 1844 * by *vtocp. 1845 * 1846 */ 1847 bzero(vtocp, sizeof (struct vtoc)); 1848 1849 bcopy(fdp->d_vtoc_bootinfo, 1850 vtocp->v_bootinfo, sizeof (vtocp->v_bootinfo)); 1851 1852 vtocp->v_sanity = VTOC_SANE; 1853 vtocp->v_version = fdp->d_vtoc_version; 1854 bcopy(fdp->d_vtoc_volume, vtocp->v_volume, LEN_DKL_VVOL); 1855 if (fjp->fj_flags & FUNIT_LABELOK) { 1856 vtocp->v_sectorsz = DEV_BSIZE; 1857 xblk = 1; 1858 } else { 1859 vtocp->v_sectorsz = fjp->fj_chars->fdc_sec_size; 1860 xblk = vtocp->v_sectorsz / DEV_BSIZE; 1861 } 1862 vtocp->v_nparts = 3; /* <= NDKMAP; */ 1863 1864 /* 1865 * Copy partitioning information. 1866 */ 1867 bcopy(fdp->d_part, vtocp->v_part, sizeof (struct partition) * NDKMAP); 1868 for (i = NDKMAP, vpart = vtocp->v_part; i && (xblk > 1); i--, vpart++) { 1869 /* correct partition info if sector size > 512 bytes */ 1870 vpart->p_start /= xblk; 1871 vpart->p_size /= xblk; 1872 } 1873 1874 bcopy(fdp->d_vtoc_timestamp, 1875 vtocp->timestamp, sizeof (fdp->d_vtoc_timestamp)); 1876 bcopy(fdp->d_vtoc_asciilabel, vtocp->v_asciilabel, LEN_DKL_ASCII); 1877 } 1878 1879 1880 static int 1881 fd_build_label_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp, 1882 struct dk_label *labelp) 1883 { 1884 struct partition *vpart; 1885 int i; 1886 int nblks; 1887 int ncyl; 1888 ushort_t sum, *sp; 1889 1890 1891 /* 1892 * Sanity-check the vtoc 1893 */ 1894 if (vtocp->v_sanity != VTOC_SANE || 1895 vtocp->v_nparts > NDKMAP || vtocp->v_nparts <= 0) { 1896 FDERRPRINT(FDEP_L3, FDEM_IOCT, 1897 (CE_WARN, "fd_build_label: sanity check on vtoc failed")); 1898 return (EINVAL); 1899 } 1900 1901 /* 1902 * before copying the vtoc, the partition information in it should be 1903 * checked against the information the driver already has on the 1904 * diskette. 1905 */ 1906 1907 nblks = (fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack * 1908 fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 1909 if (nblks == 0 || fjp->fj_chars->fdc_ncyl == 0) 1910 return (EFAULT); 1911 vpart = vtocp->v_part; 1912 1913 /* 1914 * Check the partition information in the vtoc. The starting sectors 1915 * must lie along cylinder boundaries. (NDKMAP entries are checked 1916 * to ensure that the unused entries are set to 0 if vtoc->v_nparts 1917 * is less than NDKMAP) 1918 */ 1919 for (i = NDKMAP; i; i--) { 1920 if ((vpart->p_start % nblks) != 0) { 1921 return (EINVAL); 1922 } 1923 ncyl = vpart->p_start / nblks; 1924 ncyl += vpart->p_size / nblks; 1925 if ((vpart->p_size % nblks) != 0) 1926 ncyl++; 1927 if (ncyl > (long)fjp->fj_chars->fdc_ncyl) { 1928 return (EINVAL); 1929 } 1930 vpart++; 1931 } 1932 1933 1934 bcopy(vtocp->v_bootinfo, fdp->d_vtoc_bootinfo, 1935 sizeof (vtocp->v_bootinfo)); 1936 fdp->d_vtoc_version = vtocp->v_version; 1937 bcopy(vtocp->v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL); 1938 1939 /* 1940 * Copy partitioning information. 1941 */ 1942 bcopy(vtocp->v_part, fdp->d_part, sizeof (struct partition) * NDKMAP); 1943 bcopy(vtocp->timestamp, fdp->d_vtoc_timestamp, 1944 sizeof (fdp->d_vtoc_timestamp)); 1945 bcopy(vtocp->v_asciilabel, fdp->d_vtoc_asciilabel, LEN_DKL_ASCII); 1946 1947 /* 1948 * construct the diskette label in supplied buffer 1949 */ 1950 1951 /* Put appropriate vtoc structure fields into the disk label */ 1952 labelp->dkl_vtoc.v_bootinfo[0] = (uint32_t)vtocp->v_bootinfo[0]; 1953 labelp->dkl_vtoc.v_bootinfo[1] = (uint32_t)vtocp->v_bootinfo[1]; 1954 labelp->dkl_vtoc.v_bootinfo[2] = (uint32_t)vtocp->v_bootinfo[2]; 1955 1956 labelp->dkl_vtoc.v_sanity = vtocp->v_sanity; 1957 labelp->dkl_vtoc.v_version = vtocp->v_version; 1958 1959 bcopy(vtocp->v_volume, labelp->dkl_vtoc.v_volume, LEN_DKL_VVOL); 1960 1961 labelp->dkl_vtoc.v_nparts = vtocp->v_nparts; 1962 1963 bcopy(vtocp->v_reserved, labelp->dkl_vtoc.v_reserved, 1964 sizeof (labelp->dkl_vtoc.v_reserved)); 1965 1966 for (i = 0; i < (int)vtocp->v_nparts; i++) { 1967 labelp->dkl_vtoc.v_part[i].p_tag = vtocp->v_part[i].p_tag; 1968 labelp->dkl_vtoc.v_part[i].p_flag = vtocp->v_part[i].p_flag; 1969 labelp->dkl_vtoc.v_part[i].p_start = vtocp->v_part[i].p_start; 1970 labelp->dkl_vtoc.v_part[i].p_size = vtocp->v_part[i].p_size; 1971 } 1972 1973 for (i = 0; i < NDKMAP; i++) { 1974 labelp->dkl_vtoc.v_timestamp[i] = vtocp->timestamp[i]; 1975 } 1976 bcopy(vtocp->v_asciilabel, labelp->dkl_asciilabel, LEN_DKL_ASCII); 1977 1978 1979 labelp->dkl_pcyl = fjp->fj_chars->fdc_ncyl; 1980 labelp->dkl_ncyl = fjp->fj_chars->fdc_ncyl; 1981 labelp->dkl_nhead = fjp->fj_chars->fdc_nhead; 1982 /* 1983 * The fdc_secptrack field of the fd_char structure is the number 1984 * of sectors per track where the sectors are fdc_sec_size. 1985 * The dkl_nsect field of the dk_label structure is the number of 1986 * DEV_BSIZE (512) byte sectors per track. 1987 */ 1988 labelp->dkl_nsect = (fjp->fj_chars->fdc_secptrack * 1989 fjp->fj_chars->fdc_sec_size) / DEV_BSIZE; 1990 labelp->dkl_intrlv = fjp->fj_attr->fda_intrlv; 1991 labelp->dkl_rpm = fjp->fj_attr->fda_rotatespd; 1992 labelp->dkl_read_reinstruct = 1993 (int)(labelp->dkl_nsect * labelp->dkl_rpm * 4) / 60000; 1994 labelp->dkl_write_reinstruct = labelp->dkl_read_reinstruct; 1995 1996 labelp->dkl_magic = DKL_MAGIC; 1997 1998 sum = 0; 1999 labelp->dkl_cksum = 0; 2000 sp = (ushort_t *)labelp; 2001 while (sp < &(labelp->dkl_cksum)) { 2002 sum ^= *sp++; 2003 } 2004 labelp->dkl_cksum = sum; 2005 2006 return (0); 2007 } 2008 2009 static int 2010 fd_rawioctl(struct fcu_obj *fjp, int unit, caddr_t arg, int mode) 2011 { 2012 struct fd_raw fdr; 2013 char *arg_result = NULL; 2014 int flag = B_READ; 2015 int rval = 0; 2016 caddr_t uaddr; 2017 uint_t ucount; 2018 2019 FDERRPRINT(FDEP_L1, FDEM_RAWI, 2020 (CE_CONT, "fd_rawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0])); 2021 2022 if (fjp->fj_chars->fdc_medium != 3 && fjp->fj_chars->fdc_medium != 5) { 2023 cmn_err(CE_CONT, "fd_rawioctl: Medium density not supported\n"); 2024 return (ENXIO); 2025 } 2026 2027 #ifdef _MULTI_DATAMODEL 2028 switch (ddi_model_convert_from(mode & FMODELS)) { 2029 case DDI_MODEL_ILP32: 2030 { 2031 struct fd_raw32 fdr32; 2032 2033 if (ddi_copyin(arg, &fdr32, sizeof (fdr32), mode)) 2034 return (EFAULT); 2035 2036 bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd)); 2037 fdr.fdr_cnum = fdr32.fdr_cnum; 2038 fdr.fdr_nbytes = fdr32.fdr_nbytes; 2039 fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr; 2040 arg_result = ((struct fd_raw32 *)arg)->fdr_result; 2041 2042 break; 2043 } 2044 case DDI_MODEL_NONE: 2045 #endif /* ! _MULTI_DATAMODEL */ 2046 2047 if (ddi_copyin(arg, &fdr, sizeof (fdr), mode)) 2048 return (EFAULT); 2049 2050 arg_result = ((struct fd_raw *)arg)->fdr_result; 2051 2052 #ifdef _MULTI_DATAMODEL 2053 break; 2054 } 2055 #endif /* _MULTI_DATAMODEL */ 2056 2057 2058 2059 /* 2060 * copy user address & nbytes from raw_req so that we can 2061 * put kernel address in req structure 2062 */ 2063 uaddr = fdr.fdr_addr; 2064 ucount = (uint_t)fdr.fdr_nbytes; 2065 unit &= 3; 2066 2067 switch (fdr.fdr_cmd[0] & 0x0f) { 2068 2069 case FDRAW_FORMAT: 2070 ucount += 16; 2071 fdr.fdr_addr = kmem_zalloc(ucount, KM_SLEEP); 2072 if (ddi_copyin(uaddr, fdr.fdr_addr, 2073 (size_t)fdr.fdr_nbytes, mode)) { 2074 kmem_free(fdr.fdr_addr, ucount); 2075 return (EFAULT); 2076 } 2077 if ((*fdr.fdr_addr | fdr.fdr_addr[1]) == 0) 2078 fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED); 2079 flag = B_WRITE; 2080 fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 2081 break; 2082 2083 case FDRAW_WRCMD: 2084 case FDRAW_WRITEDEL: 2085 flag = B_WRITE; 2086 /* FALLTHROUGH */ 2087 case FDRAW_RDCMD: 2088 case FDRAW_READDEL: 2089 case FDRAW_READTRACK: 2090 if (ucount) { 2091 /* 2092 * In SunOS 4.X, we used to as_fault things in. 2093 * We really cannot do this in 5.0/SVr4. Unless 2094 * someone really believes that speed is of the 2095 * essence here, it is just much simpler to do 2096 * this in kernel space and use copyin/copyout. 2097 */ 2098 fdr.fdr_addr = kmem_alloc((size_t)ucount, KM_SLEEP); 2099 if (flag == B_WRITE) { 2100 if (ddi_copyin(uaddr, fdr.fdr_addr, ucount, 2101 mode)) { 2102 kmem_free(fdr.fdr_addr, ucount); 2103 return (EFAULT); 2104 } 2105 } 2106 } else 2107 return (EINVAL); 2108 fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 2109 break; 2110 2111 case FDRAW_READID: 2112 case FDRAW_REZERO: 2113 case FDRAW_SEEK: 2114 case FDRAW_SENSE_DRV: 2115 ucount = 0; 2116 fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit; 2117 break; 2118 2119 case FDRAW_SPECIFY: 2120 fdr.fdr_cmd[2] &= 0xfe; /* keep NoDMA bit clear */ 2121 /* FALLTHROUGH */ 2122 case FDRAW_SENSE_INT: 2123 ucount = 0; 2124 break; 2125 2126 default: 2127 return (EINVAL); 2128 } 2129 2130 /* 2131 * Note that we ignore any error returns from controller 2132 * This is the way the driver has been, and it may be 2133 * that the raw ioctl senders simply don't want to 2134 * see any errors returned in this fashion. 2135 */ 2136 2137 fjp->fj_ops->fco_select(fjp, unit, 1); 2138 rval = fjp->fj_ops->fco_rwioctl(fjp, unit, (caddr_t)&fdr); 2139 2140 if (ucount && flag == B_READ && rval == 0) { 2141 if (ddi_copyout(fdr.fdr_addr, uaddr, ucount, mode)) { 2142 rval = EFAULT; 2143 } 2144 } 2145 if (ddi_copyout(fdr.fdr_result, arg_result, sizeof (fdr.fdr_cmd), mode)) 2146 rval = EFAULT; 2147 2148 fjp->fj_ops->fco_select(fjp, unit, 0); 2149 if (ucount) 2150 kmem_free(fdr.fdr_addr, ucount); 2151 2152 return (rval); 2153 } 2154 2155 /* 2156 * property operation routine. return the number of blocks for the partition 2157 * in question or forward the request to the property facilities. 2158 */ 2159 static int 2160 fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 2161 char *name, caddr_t valuep, int *lengthp) 2162 { 2163 struct fcu_obj *fjp = NULL; 2164 struct fdisk *fdp = NULL; 2165 uint64_t nblocks64; 2166 2167 FDERRPRINT(FDEP_L1, FDEM_PROP, 2168 (CE_CONT, "fd_prop_op: dip %p %s\n", (void *)dip, name)); 2169 2170 /* 2171 * Our dynamic properties are all device specific and size oriented. 2172 * Requests issued under conditions where size is valid are passed 2173 * to ddi_prop_op_nblocks with the size information, otherwise the 2174 * request is passed to ddi_prop_op. 2175 */ 2176 if (dev == DDI_DEV_T_ANY) { 2177 pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 2178 name, valuep, lengthp)); 2179 } else { 2180 /* 2181 * Ignoring return value because success is checked by 2182 * verifying fjp and fdp and returned unit value is not used. 2183 */ 2184 (void) fd_getdrive(dev, &fjp, &fdp); 2185 if (!fjp || !fdp) 2186 goto pass; 2187 2188 /* get nblocks value */ 2189 nblocks64 = (ulong_t)fdp->d_part[PARTITION(dev)].p_size; 2190 2191 return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags, 2192 name, valuep, lengthp, nblocks64)); 2193 } 2194 } 2195 2196 static void 2197 fd_media_watch(void *arg) 2198 { 2199 struct fcu_obj *fjp; 2200 struct fdisk *fdp; 2201 2202 #ifdef DEBUG 2203 int unit; 2204 #define DEBUG_ASSIGN unit= 2205 #else 2206 #define DEBUG_ASSIGN (void) 2207 #endif 2208 DEBUG_ASSIGN fd_getdrive((dev_t)arg, &fjp, &fdp); 2209 /* 2210 * Ignoring return in non DEBUG mode because device exist. 2211 * Returned unit value is not used. 2212 */ 2213 2214 FDERRPRINT(FDEP_L0, FDEM_IOCT, 2215 (CE_CONT, "fd_media_watch unit %d\n", unit)); 2216 2217 /* 2218 * fd_get_media_state() cannot be called from this timeout function 2219 * because the floppy drive has to be selected first, and that could 2220 * force this function to sleep (while waiting for the select 2221 * semaphore). 2222 * Instead, just wakeup up driver. 2223 */ 2224 mutex_enter(&fjp->fj_lock); 2225 cv_broadcast(&fdp->d_statecv); 2226 mutex_exit(&fjp->fj_lock); 2227 } 2228 2229 enum dkio_state 2230 fd_get_media_state(struct fcu_obj *fjp, int unit) 2231 { 2232 enum dkio_state state; 2233 2234 if (fjp->fj_ops->fco_getchng(fjp, unit)) { 2235 /* recheck disk only if DSKCHG "high" */ 2236 fjp->fj_ops->fco_resetchng(fjp, unit); 2237 if (fjp->fj_ops->fco_getchng(fjp, unit)) { 2238 if (fjp->fj_flags & FUNIT_CHGDET) { 2239 /* 2240 * again no diskette; not a new change 2241 */ 2242 state = DKIO_NONE; 2243 } else { 2244 /* 2245 * a new change; diskette was ejected 2246 */ 2247 fjp->fj_flags |= FUNIT_CHGDET; 2248 state = DKIO_EJECTED; 2249 } 2250 } else { 2251 fjp->fj_flags &= ~FUNIT_CHGDET; 2252 state = DKIO_INSERTED; 2253 } 2254 } else { 2255 fjp->fj_flags &= ~FUNIT_CHGDET; 2256 state = DKIO_INSERTED; 2257 } 2258 FDERRPRINT(FDEP_L0, FDEM_IOCT, 2259 (CE_CONT, "fd_get_media_state unit %d: state %x\n", unit, state)); 2260 return (state); 2261 } 2262 2263 static int 2264 fd_check_media(dev_t dev, enum dkio_state state) 2265 { 2266 struct fcu_obj *fjp; 2267 struct fdisk *fdp; 2268 int unit; 2269 int err; 2270 2271 unit = fd_getdrive(dev, &fjp, &fdp); 2272 2273 mutex_enter(&fjp->fj_lock); 2274 2275 fjp->fj_ops->fco_select(fjp, unit, 1); 2276 fdp->d_media_state = fd_get_media_state(fjp, unit); 2277 fdp->d_media_timeout = drv_usectohz(fd_check_media_time); 2278 2279 while (fdp->d_media_state == state) { 2280 /* release the controller and drive */ 2281 fjp->fj_ops->fco_select(fjp, unit, 0); 2282 2283 /* turn on timer */ 2284 fdp->d_media_timeout_id = timeout(fd_media_watch, 2285 (void *)dev, fdp->d_media_timeout); 2286 2287 if (cv_wait_sig(&fdp->d_statecv, &fjp->fj_lock) == 0) { 2288 fdp->d_media_timeout = 0; 2289 mutex_exit(&fjp->fj_lock); 2290 return (EINTR); 2291 } 2292 fjp->fj_ops->fco_select(fjp, unit, 1); 2293 fdp->d_media_state = fd_get_media_state(fjp, unit); 2294 } 2295 2296 if (fdp->d_media_state == DKIO_INSERTED) { 2297 err = fdgetlabel(fjp, unit); 2298 if (err) { 2299 fjp->fj_ops->fco_select(fjp, unit, 0); 2300 mutex_exit(&fjp->fj_lock); 2301 return (EIO); 2302 } 2303 } 2304 fjp->fj_ops->fco_select(fjp, unit, 0); 2305 mutex_exit(&fjp->fj_lock); 2306 return (0); 2307 } 2308 2309 /* 2310 * fd_get_media_info : 2311 * Collects medium information for 2312 * DKIOCGMEDIAINFO ioctl. 2313 */ 2314 2315 static int 2316 fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag) 2317 { 2318 struct dk_minfo media_info; 2319 int err = 0; 2320 2321 media_info.dki_media_type = DK_FLOPPY; 2322 media_info.dki_lbsize = fjp->fj_chars->fdc_sec_size; 2323 media_info.dki_capacity = fjp->fj_chars->fdc_ncyl * 2324 fjp->fj_chars->fdc_secptrack * fjp->fj_chars->fdc_nhead; 2325 2326 if (ddi_copyout(&media_info, buf, sizeof (struct dk_minfo), flag)) 2327 err = EFAULT; 2328 return (err); 2329 } 2330