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