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