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