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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright (c) 2018, Joyent, Inc.
36 * CMOS_CONF_MEM: CMOS memory contains configuration info
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
46 #include <sys/ioctl.h>
50 #include <sys/autoconf.h>
54 #include <sys/sunddi.h>
55 #include <sys/kstat.h>
57 #include <sys/ddidmareq.h>
60 #include <sys/fd_debug.h>
61 #include <sys/fdmedia.h>
62 #include <sys/debug.h>
63 #include <sys/modctl.h>
66 * Local Function Prototypes
68 static int fd_unit_is_open(struct fdisk
*);
69 static int fdgetlabel(struct fcu_obj
*, int);
70 static void fdstart(struct fcu_obj
*);
71 static int fd_build_label_vtoc(struct fcu_obj
*, struct fdisk
*,
72 struct vtoc
*, struct dk_label
*);
73 static void fd_build_user_vtoc(struct fcu_obj
*, struct fdisk
*,
75 static int fd_rawioctl(struct fcu_obj
*, int, caddr_t
, int);
76 static void fd_media_watch(void *);
78 static int fd_open(dev_t
*, int, int, cred_t
*);
79 static int fd_close(dev_t
, int, int, cred_t
*);
80 static int fd_strategy(struct buf
*);
81 static int fd_read(dev_t
, struct uio
*, cred_t
*);
82 static int fd_write(dev_t
, struct uio
*, cred_t
*);
83 static int fd_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
84 static int fd_prop_op(dev_t
, dev_info_t
*, ddi_prop_op_t
, int, char *,
86 static int fd_check_media(dev_t dev
, enum dkio_state state
);
87 static int fd_get_media_info(struct fcu_obj
*fjp
, caddr_t buf
, int flag
);
89 static struct cb_ops fd_cb_ops
= {
92 fd_strategy
, /* strategy */
102 fd_prop_op
, /* cb_prop_op */
104 D_NEW
| D_MP
/* Driver compatibility flag */
107 static int fd_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
108 static int fd_probe(dev_info_t
*);
109 static int fd_attach(dev_info_t
*, ddi_attach_cmd_t
);
110 static int fd_detach(dev_info_t
*, ddi_detach_cmd_t
);
112 static struct dev_ops fd_ops
= {
113 DEVO_REV
, /* devo_rev, */
115 fd_getinfo
, /* getinfo */
116 nulldev
, /* identify */
117 fd_probe
, /* probe */
118 fd_attach
, /* attach */
119 fd_detach
, /* detach */
121 &fd_cb_ops
, /* driver operations */
122 NULL
, /* bus operations */
124 ddi_quiesce_not_supported
, /* devo_quiesce */
131 static void *fd_state_head
; /* opaque handle top of state structs */
132 static int fd_check_media_time
= 5000000; /* 5 second state check */
138 * set fderrlevel to 1
139 * set fderrmask to 224 or 644
142 static uint_t fderrmask
= FDEM_ALL
;
144 static int fderrlevel
= 5;
146 #define KIOSP KSTAT_IO_PTR(fdp->d_iostat)
148 static struct driver_minor_data
{
156 { "a,raw", 0, S_IFCHR
},
157 { "b,raw", 1, S_IFCHR
},
158 { "c,raw", 2, S_IFCHR
},
162 static struct modldrv modldrv
= {
163 &mod_driverops
, /* Type of module. This one is a driver */
164 "Floppy Disk driver", /* Name of the module. */
165 &fd_ops
, /* driver ops */
168 static struct modlinkage modlinkage
= {
169 MODREV_1
, (void *)&modldrv
, NULL
178 if ((retval
= ddi_soft_state_init(&fd_state_head
,
179 sizeof (struct fdisk
) + sizeof (struct fd_drive
) +
180 sizeof (struct fd_char
) + sizeof (struct fdattr
), 0)) != 0)
183 if ((retval
= mod_install(&modlinkage
)) != 0)
184 ddi_soft_state_fini(&fd_state_head
);
193 if ((retval
= mod_remove(&modlinkage
)) != 0)
195 ddi_soft_state_fini(&fd_state_head
);
200 _info(struct modinfo
*modinfop
)
202 return (mod_info(&modlinkage
, modinfop
));
207 fd_getdrive(dev_t dev
, struct fcu_obj
**fjpp
, struct fdisk
**fdpp
)
210 *fdpp
= ddi_get_soft_state(fd_state_head
, DRIVE(dev
));
212 *fjpp
= (*fdpp
)->d_obj
;
214 return ((*fjpp
)->fj_unit
);
222 fd_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
224 dev_t dev
= (dev_t
)arg
;
225 struct fcu_obj
*fjp
= NULL
;
226 struct fdisk
*fdp
= NULL
;
230 case DDI_INFO_DEVT2DEVINFO
:
231 (void) fd_getdrive(dev
, &fjp
, &fdp
);
233 * Ignoring return value because success is checked by
234 * verifying fjp and fdp and returned unit value is not used.
237 *result
= fjp
->fj_dip
;
242 case DDI_INFO_DEVT2INSTANCE
:
243 *result
= (void *)(uintptr_t)DRIVE(dev
);
253 #define CMOS_ADDR 0x70
254 #define CMOS_DATA 0x71
255 #define CMOS_FDRV 0x10
256 #endif /* CMOS_CONF_MEM */
259 fd_probe(dev_info_t
*dip
)
264 #endif /* CMOS_CONF_MEM */
271 len
= sizeof (debug
);
272 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
273 DDI_PROP_DONTPASS
, "debug", (caddr_t
)debug
, &len
) ==
275 fderrlevel
= debug
[0];
277 fderrmask
= (uint_t
)debug
[1];
280 len
= sizeof (unit_num
);
281 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
282 DDI_PROP_DONTPASS
, "unit", (caddr_t
)&unit_num
, &len
) !=
284 FDERRPRINT(FDEP_L3
, FDEM_ATTA
,
285 (CE_WARN
, "fd_probe failed: dip %p", (void *)dip
));
286 return (DDI_PROBE_FAILURE
);
290 /* get the cmos memory values quick and dirty */
291 outb(CMOS_ADDR
, CMOS_FDRV
);
292 cmos
= drive_type
= (int)inb(CMOS_DATA
);
293 #endif /* CMOS_CONF_MEM */
298 drive_type
= drive_type
>> 4;
301 if (cmos
&& (drive_type
& 0x0F)) {
305 * Some enhanced floppy-disk controller adaptor cards
306 * require NO drives defined in the CMOS configuration
310 #endif /* CMOS_CONF_MEM */
312 default: /* need to check conf file */
313 len
= sizeof (density
);
314 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
315 DDI_PROP_DONTPASS
, "density", (caddr_t
)&density
, &len
) !=
317 FDERRPRINT(FDEP_L3
, FDEM_ATTA
,
319 "fd_probe failed density: dip %p unit %d",
320 (void *)dip
, unit_num
));
321 return (DDI_PROBE_FAILURE
);
323 len
= sizeof (drive_size
);
324 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
325 DDI_PROP_DONTPASS
, "size", (caddr_t
)&drive_size
, &len
) !=
327 FDERRPRINT(FDEP_L3
, FDEM_ATTA
,
328 (CE_WARN
, "fd_probe failed size: dip %p unit %d",
329 (void *)dip
, unit_num
));
330 return (DDI_PROBE_FAILURE
);
333 FDERRPRINT(FDEP_L3
, FDEM_ATTA
,
334 (CE_WARN
, "fd_probe dip %p unit %d", (void *)dip
, unit_num
));
335 return (DDI_PROBE_SUCCESS
);
341 fd_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
345 struct driver_minor_data
*dmdp
;
347 int drive_num
, drive_size
, drive_type
;
350 #endif /* CMOS_CONF_MEM */
354 char name
[MAXNAMELEN
];
358 len
= sizeof (unit_num
);
359 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
360 DDI_PROP_DONTPASS
, "unit", (caddr_t
)&unit_num
, &len
) !=
362 FDERRPRINT(FDEP_L3
, FDEM_ATTA
,
363 (CE_WARN
, "fd_attach failed: dip %p", (void *)dip
));
364 return (DDI_FAILURE
);
368 outb(CMOS_ADDR
, CMOS_FDRV
);
369 cmos
= drive_type
= (int)inb(CMOS_DATA
);
370 #endif /* CMOS_CONF_MEM */
375 drive_type
= drive_type
>> 4;
378 drive_type
= drive_type
& 0x0F;
382 * Some enhanced floppy-disk controller adaptor cards
383 * require NO drives defined in the CMOS configuration
387 #endif /* CMOS_CONF_MEM */
389 default: /* need to check .conf file */
391 len
= sizeof (density
);
392 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
,
393 PROP_LEN_AND_VAL_BUF
, DDI_PROP_DONTPASS
, "density",
394 (caddr_t
)&density
, &len
) != DDI_PROP_SUCCESS
)
396 len
= sizeof (drive_size
);
397 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
,
398 PROP_LEN_AND_VAL_BUF
, DDI_PROP_DONTPASS
, "size",
399 (caddr_t
)&drive_size
, &len
) != DDI_PROP_SUCCESS
)
401 if (strcmp(density
, "DSDD") == 0) {
404 else if (drive_size
== 3)
406 } else if (strcmp(density
, "DSHD") == 0) {
409 else if (drive_size
== 3)
411 } else if (strcmp(density
, "DSED") == 0 &&
417 if (drive_type
== 0) {
418 FDERRPRINT(FDEP_L3
, FDEM_ATTA
,
419 (CE_WARN
, "fd_attach failed type: dip %p unit %d",
420 (void *)dip
, unit_num
));
421 return (DDI_FAILURE
);
424 drive_num
= ddi_get_instance(dip
);
425 if (ddi_soft_state_zalloc(fd_state_head
, drive_num
) != 0)
426 return (DDI_FAILURE
);
427 fdp
= ddi_get_soft_state(fd_state_head
, drive_num
);
428 fjp
= fdp
->d_obj
= ddi_get_driver_private(dip
);
430 mutex_init(&fjp
->fj_lock
, NULL
, MUTEX_DRIVER
, *fjp
->fj_iblock
);
431 sema_init(&fdp
->d_ocsem
, 1, NULL
, SEMA_DRIVER
, NULL
);
433 fjp
->fj_drive
= (struct fd_drive
*)(fdp
+ 1);
434 fjp
->fj_chars
= (struct fd_char
*)(fjp
->fj_drive
+ 1);
435 fjp
->fj_attr
= (struct fdattr
*)(fjp
->fj_chars
+ 1);
438 * set default floppy drive characteristics & geometry
440 switch (drive_type
) { /* assume doubled sided */
441 case 2: /* 5.25 high density */
442 *fjp
->fj_drive
= dfd_525HD
;
443 fdp
->d_media
= 1<<FMT_5H
| 1<<FMT_5D9
| 1<<FMT_5D8
|
444 1<<FMT_5D4
| 1<<FMT_5D16
;
445 fdp
->d_deffdtype
= fdp
->d_curfdtype
= FMT_5H
;
447 case 4: /* 3.5 high density */
448 *fjp
->fj_drive
= dfd_350HD
;
449 fdp
->d_media
= 1<<FMT_3H
| 1<<FMT_3I
| 1<<FMT_3D
;
450 len
= sizeof (mode_3D
);
451 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
,
452 PROP_LEN_AND_VAL_BUF
, DDI_PROP_DONTPASS
, "mode_3D",
453 (caddr_t
)&mode_3D
, &len
) != DDI_PROP_SUCCESS
)
455 if (mode_3D
&& (fjp
->fj_fdc
->c_flags
& FCFLG_3DMODE
))
457 * 3D mode should be enabled only if a dual-
458 * speed 3.5" high-density drive and a
459 * supported floppy controller are installed.
461 fdp
->d_media
|= 1 << FMT_3M
;
462 fdp
->d_deffdtype
= fdp
->d_curfdtype
= FMT_3H
;
464 case 1: /* 5.25 double density */
465 *fjp
->fj_drive
= dfd_525DD
;
466 fdp
->d_media
= 1<<FMT_5D9
| 1<<FMT_5D8
| 1<<FMT_5D4
|
468 fdp
->d_deffdtype
= fdp
->d_curfdtype
= FMT_5D9
;
470 case 3: /* 3.5 double density */
471 *fjp
->fj_drive
= dfd_350HD
;
472 fdp
->d_media
= 1<<FMT_3D
;
473 fdp
->d_deffdtype
= fdp
->d_curfdtype
= FMT_3D
;
475 case 5: /* 3.5 extended density */
478 *fjp
->fj_drive
= dfd_350ED
;
479 fdp
->d_media
= 1<<FMT_3E
| 1<<FMT_3H
| 1<<FMT_3I
|
481 fdp
->d_deffdtype
= fdp
->d_curfdtype
= FMT_3E
;
483 case 0: /* no drive defined */
487 *fjp
->fj_chars
= *defchar
[fdp
->d_deffdtype
];
488 *fjp
->fj_attr
= fdtypes
[fdp
->d_deffdtype
];
489 bcopy(fdparts
[fdp
->d_deffdtype
], fdp
->d_part
,
490 sizeof (struct partition
) * NDKMAP
);
491 fjp
->fj_rotspd
= fdtypes
[fdp
->d_deffdtype
].fda_rotatespd
;
493 sig_minor
= drive_num
<< 3;
494 for (dmdp
= fd_minor
; dmdp
->name
!= NULL
; dmdp
++) {
495 if (ddi_create_minor_node(dip
, dmdp
->name
, dmdp
->type
,
496 sig_minor
| dmdp
->minor
, DDI_NT_FD
, 0)
498 ddi_remove_minor_node(dip
, NULL
);
503 FDERRPRINT(FDEP_L3
, FDEM_ATTA
,
504 (CE_WARN
, "fd_attach: dip %p unit %d",
505 (void *)dip
, unit_num
));
506 (void) sprintf(name
, "fd%d", drive_num
);
507 fdp
->d_iostat
= kstat_create("fd", drive_num
, name
, "disk",
508 KSTAT_TYPE_IO
, 1, KSTAT_FLAG_PERSISTENT
);
510 fdp
->d_iostat
->ks_lock
= &fjp
->fj_lock
;
511 kstat_install(fdp
->d_iostat
);
514 fjp
->fj_data
= (caddr_t
)fdp
;
515 fjp
->fj_flags
|= FUNIT_DRVATCH
;
518 * Add a zero-length attribute to tell the world we support
519 * kernel ioctls (for layered drivers)
521 (void) ddi_prop_create(DDI_DEV_T_NONE
, dip
, DDI_PROP_CANSLEEP
,
522 DDI_KERNEL_IOCTL
, NULL
, 0);
525 * We want to get suspend/resume events, so that we can
526 * refuse to suspend when pcfs is mounted.
528 (void) ddi_prop_update_string(DDI_DEV_T_NONE
, dip
,
529 "pm-hardware-state", "needs-suspend-resume");
532 * Ignoring return value because, for passed arguments, only
533 * DDI_SUCCESS is returned.
536 return (DDI_SUCCESS
);
539 /* nothing for us to do */
540 return (DDI_SUCCESS
);
543 return (DDI_FAILURE
);
546 fjp
->fj_drive
= NULL
;
547 fjp
->fj_chars
= 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
);
561 fd_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
566 int rval
= DDI_SUCCESS
;
568 FDERRPRINT(FDEP_L3
, FDEM_ATTA
, (CE_WARN
, "fd_detach dip %p",
571 drive_num
= ddi_get_instance(dip
);
572 if (!(fdp
= ddi_get_soft_state(fd_state_head
, drive_num
)))
577 if (fd_unit_is_open(fdp
)) {
581 kstat_delete(fdp
->d_iostat
);
582 fdp
->d_iostat
= NULL
;
583 fjp
= (struct fcu_obj
*)fdp
->d_obj
;
584 fjp
->fj_flags
&= ~FUNIT_DRVATCH
;
586 fjp
->fj_drive
= NULL
;
587 fjp
->fj_chars
= NULL
;
589 ddi_prop_remove_all(dip
);
590 mutex_destroy(&fjp
->fj_lock
);
591 sema_destroy(&fdp
->d_ocsem
);
592 ddi_soft_state_free(fd_state_head
, drive_num
);
597 * Bad, bad, bad things will happen if someone
598 * *changes* the disk in the drive while it is mounted
599 * and the system is suspended. We have no way to
600 * detect that. (Undetected filesystem corruption.
601 * Its akin to changing the boot disk while the system
602 * is suspended. Don't do it!)
604 * So we refuse to suspend if there is a mounted filesystem.
605 * (We guess this by looking for a block open. Character
606 * opens are fine.) This limits some of the usability of
607 * suspend/resume, but it certainly avoids this
608 * potential filesystem corruption from pilot error.
609 * Given the decreasing popularity of floppy media, we
610 * don't see this as much of a limitation.
612 if (fdp
->d_regopen
[OTYP_BLK
]) {
614 "Unable to suspend while floppy is in use.");
628 fd_part_is_open(struct fdisk
*fdp
, int part
)
632 for (i
= 0; i
< (OTYPCNT
- 1); i
++)
633 if (fdp
->d_regopen
[i
] & (1 << part
))
639 fd_unit_is_open(struct fdisk
*fdp
)
643 for (i
= 0; i
< NDKMAP
; i
++)
644 if (fdp
->d_lyropen
[i
])
646 for (i
= 0; i
< (OTYPCNT
- 1); i
++)
647 if (fdp
->d_regopen
[i
])
654 fd_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
656 struct fcu_obj
*fjp
= NULL
;
657 struct fdisk
*fdp
= NULL
;
658 struct partition
*pp
;
666 unit
= fd_getdrive(dev
, &fjp
, &fdp
);
669 part
= PARTITION(dev
);
671 pp
= &fdp
->d_part
[part
];
674 * Serialize opens/closes
676 sema_p(&fdp
->d_ocsem
);
677 FDERRPRINT(FDEP_L1
, FDEM_OPEN
,
678 (CE_CONT
, "fd_open: fd%d part %d flag %x otype %x\n", DRIVE(dev
),
682 * Check for previous exclusive open, or trying to exclusive open
683 * An "exclusive open" on any partition is not guaranteed to
684 * protect against opens on another partition that overlaps it.
686 if (otyp
== OTYP_LYR
) {
687 part_is_open
= (fdp
->d_lyropen
[part
] != 0);
689 part_is_open
= fd_part_is_open(fdp
, part
);
691 if ((fdp
->d_exclmask
& pbit
) || ((flag
& FEXCL
) && part_is_open
)) {
692 FDERRPRINT(FDEP_L0
, FDEM_OPEN
, (CE_CONT
,
693 "fd_open: exclparts %lx openparts %lx lyrcnt %lx pbit %x\n",
694 fdp
->d_exclmask
, fdp
->d_regopen
[otyp
], fdp
->d_lyropen
[part
],
696 sema_v(&fdp
->d_ocsem
);
701 * Ensure that drive is recalibrated on first open of new diskette.
703 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
704 if (fjp
->fj_ops
->fco_getchng(fjp
, unit
) != 0) {
705 if (fjp
->fj_ops
->fco_rcseek(fjp
, unit
, -1, 0)) {
706 FDERRPRINT(FDEP_L2
, FDEM_OPEN
,
707 (CE_NOTE
, "fd_open fd%d: not ready", DRIVE(dev
)));
708 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
709 sema_v(&fdp
->d_ocsem
);
712 fjp
->fj_flags
&= ~(FUNIT_LABELOK
| FUNIT_UNLABELED
);
714 if (flag
& (FNDELAY
| FNONBLOCK
)) {
715 /* don't attempt access, just return successfully */
716 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
721 * auto-sense the density/format of the diskette
723 rval
= fdgetlabel(fjp
, unit
);
724 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
726 /* didn't find label (couldn't read anything) */
727 FDERRPRINT(FDEP_L2
, FDEM_OPEN
,
728 (CE_NOTE
, "fd%d: drive not ready", DRIVE(dev
)));
729 sema_v(&fdp
->d_ocsem
);
732 /* check partition */
733 if (pp
->p_size
== 0) {
734 sema_v(&fdp
->d_ocsem
);
738 * if opening for writing, check write protect on diskette
740 if ((flag
& FWRITE
) && (fdp
->d_obj
->fj_flags
& FUNIT_WPROT
)) {
741 sema_v(&fdp
->d_ocsem
);
747 * mark open as having succeeded
750 fdp
->d_exclmask
|= pbit
;
751 if (otyp
== OTYP_LYR
)
752 fdp
->d_lyropen
[part
]++;
754 fdp
->d_regopen
[otyp
] |= 1 << part
;
756 sema_v(&fdp
->d_ocsem
);
761 * fdgetlabel - read the SunOS label off the diskette
762 * if it can read a valid label it does so, else it will use a
763 * default. If it can`t read the diskette - that is an error.
765 * RETURNS: 0 for ok - meaning that it could at least read the device,
766 * !0 for error XXX TBD NYD error codes
769 fdgetlabel(struct fcu_obj
*fjp
, int unit
)
771 struct dk_label
*label
;
783 FDERRPRINT(FDEP_L0
, FDEM_GETL
,
784 (CE_CONT
, "fdgetlabel fd unit %d\n", unit
));
785 fdp
= (struct fdisk
*)fjp
->fj_data
;
786 fjp
->fj_flags
&= ~(FUNIT_UNLABELED
);
789 * get some space to play with the label
791 label
= kmem_zalloc(sizeof (struct dk_label
), KM_SLEEP
);
792 FDERRPRINT(FDEP_L0
, FDEM_GETL
, (CE_CONT
,
793 "fdgetlabel fd unit %d kmem_zalloc: ptr = %p, size = %lx\n",
794 unit
, (void *)label
, (size_t)sizeof (struct dk_label
)));
797 * read block 0 (0/0/1) to find the label
798 * (disk is potentially not present or unformatted)
800 /* noerrprint since this is a private cmd */
802 fderrlevel
= FDEP_LMAX
;
804 * try different characteristics (ie densities)
806 * if fdp->d_curfdtype is -1 then the current characteristics
807 * were set by ioctl and need to try it as well as everything
810 nexttype
= fdp
->d_deffdtype
;
811 try_this
= 1; /* always try the current characteristics */
813 for (tries
= nfdtypes
; tries
; tries
--) {
815 fjp
->fj_flags
&= ~FUNIT_CHAROK
;
817 /* try reading last sector of cyl 1, head 0 */
818 if (!(rval
= fjp
->fj_ops
->fco_rw(fjp
, unit
,
819 FDREAD
, 1, 0, fjp
->fj_chars
->fdc_secptrack
,
821 sizeof (struct dk_label
))) &&
822 /* and last sector plus 1 of cylinder 1 */
823 fjp
->fj_ops
->fco_rw(fjp
, unit
, FDREAD
, 1,
824 0, fjp
->fj_chars
->fdc_secptrack
+ 1,
826 sizeof (struct dk_label
)) &&
827 /* and label sector on cylinder 0 */
828 !(rval
= fjp
->fj_ops
->fco_rw(fjp
, unit
,
829 FDREAD
, 0, 0, 1, (caddr_t
)label
,
830 sizeof (struct dk_label
))))
836 * try the next entry in the characteristics tbl
838 fdp
->d_curfdtype
= (signed char)nexttype
;
839 nexttype
= (nexttype
+ 1) % nfdtypes
;
840 if ((1 << fdp
->d_curfdtype
) & fdp
->d_media
) {
841 *fjp
->fj_chars
= *defchar
[fdp
->d_curfdtype
];
842 *fjp
->fj_attr
= fdtypes
[fdp
->d_curfdtype
];
843 bcopy(fdparts
[fdp
->d_curfdtype
], fdp
->d_part
,
844 sizeof (struct partition
) * NDKMAP
);
846 * check for a double_density diskette
847 * in a high_density 5.25" drive
849 if (fjp
->fj_chars
->fdc_transfer_rate
== 250 &&
850 fjp
->fj_rotspd
> fjp
->fj_attr
->fda_rotatespd
) {
852 * yes - adjust transfer rate since we don't
853 * know if we have a 5.25" dual-speed drive
855 fjp
->fj_attr
->fda_rotatespd
= 360;
856 fjp
->fj_chars
->fdc_transfer_rate
= 300;
857 fjp
->fj_chars
->fdc_medium
= 5;
859 if ((2 * fjp
->fj_chars
->fdc_ncyl
) ==
860 defchar
[fdp
->d_deffdtype
]->fdc_ncyl
) {
861 /* yes - adjust steps per cylinder */
862 fjp
->fj_chars
->fdc_steps
= 2;
864 fjp
->fj_chars
->fdc_steps
= 1;
869 fderrlevel
= oldlvl
; /* print errors again */
872 fdp
->d_curfdtype
= fdp
->d_deffdtype
;
873 goto out
; /* couldn't read anything */
876 FDERRPRINT(FDEP_L0
, FDEM_GETL
,
878 "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n",
879 unit
, fjp
->fj_chars
->fdc_ncyl
, fjp
->fj_chars
->fdc_secptrack
,
880 fjp
->fj_chars
->fdc_steps
, fjp
->fj_attr
->fda_rotatespd
,
881 fjp
->fj_attr
->fda_intrlv
));
884 * _something_ was read - look for unixtype label
886 if (label
->dkl_magic
!= DKL_MAGIC
||
887 label
->dkl_vtoc
.v_sanity
!= VTOC_SANE
) {
888 /* not a label - no magic number */
889 goto nolabel
; /* no errors, but no label */
892 count
= sizeof (struct dk_label
) / sizeof (short);
896 xsum
^= *sp
++; /* should add up to 0 */
898 /* not a label - checksum didn't compute */
899 goto nolabel
; /* no errors, but no label */
903 * the SunOS label overrides current diskette characteristics
905 fjp
->fj_chars
->fdc_ncyl
= label
->dkl_pcyl
;
906 fjp
->fj_chars
->fdc_nhead
= label
->dkl_nhead
;
907 fjp
->fj_chars
->fdc_secptrack
= (label
->dkl_nsect
* DEV_BSIZE
) /
908 fjp
->fj_chars
->fdc_sec_size
;
909 if (defchar
[fdp
->d_deffdtype
]->fdc_ncyl
== 2 * fjp
->fj_chars
->fdc_ncyl
)
910 fjp
->fj_chars
->fdc_steps
= 2;
912 fjp
->fj_chars
->fdc_steps
= 1;
914 fjp
->fj_attr
->fda_rotatespd
= label
->dkl_rpm
;
915 fjp
->fj_attr
->fda_intrlv
= label
->dkl_intrlv
;
917 fdp
->d_vtoc_version
= label
->dkl_vtoc
.v_version
;
918 bcopy(label
->dkl_vtoc
.v_volume
, fdp
->d_vtoc_volume
, LEN_DKL_VVOL
);
919 bcopy(label
->dkl_vtoc
.v_asciilabel
,
920 fdp
->d_vtoc_asciilabel
, LEN_DKL_ASCII
);
924 for (i
= 0; i
< NDKMAP
; i
++) {
925 fdp
->d_part
[i
].p_tag
= label
->dkl_vtoc
.v_part
[i
].p_tag
;
926 fdp
->d_part
[i
].p_flag
= label
->dkl_vtoc
.v_part
[i
].p_flag
;
927 fdp
->d_part
[i
].p_start
= label
->dkl_vtoc
.v_part
[i
].p_start
;
928 fdp
->d_part
[i
].p_size
= label
->dkl_vtoc
.v_part
[i
].p_size
;
930 fdp
->d_vtoc_timestamp
[i
] = label
->dkl_vtoc
.timestamp
[i
];
933 fjp
->fj_flags
|= FUNIT_LABELOK
;
938 * if not found, fill in label info from default (mark default used)
940 if (fdp
->d_media
& (1<<FMT_3D
))
941 newlabel
= deflabel_35
;
942 else /* if (fdp->d_media & (1<<FMT_5D9)) */
943 newlabel
= deflabel_525
;
944 bzero(fdp
->d_vtoc_volume
, LEN_DKL_VVOL
);
945 (void) sprintf(fdp
->d_vtoc_asciilabel
, newlabel
,
946 fjp
->fj_chars
->fdc_ncyl
, fjp
->fj_chars
->fdc_nhead
,
947 fjp
->fj_chars
->fdc_secptrack
);
948 fjp
->fj_flags
|= FUNIT_UNLABELED
;
951 kmem_free(label
, sizeof (struct dk_label
));
958 fd_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred_p
)
960 struct fcu_obj
*fjp
= NULL
;
961 struct fdisk
*fdp
= NULL
;
962 int part
, part_is_closed
;
966 #define DEBUG_ASSIGN unit=
968 #define DEBUG_ASSIGN (void)
971 DEBUG_ASSIGN
fd_getdrive(dev
, &fjp
, &fdp
);
973 * Ignoring return in non DEBUG mode because success is checked by
974 * verifying fjp and fdp and returned unit value is not used.
978 part
= PARTITION(dev
);
980 sema_p(&fdp
->d_ocsem
);
981 FDERRPRINT(FDEP_L1
, FDEM_CLOS
,
982 (CE_CONT
, "fd_close: fd unit %d part %d otype %x\n",
985 if (otyp
== OTYP_LYR
) {
986 if (fdp
->d_lyropen
[part
])
987 fdp
->d_lyropen
[part
]--;
988 part_is_closed
= (fdp
->d_lyropen
[part
] == 0);
990 fdp
->d_regopen
[otyp
] &= ~(1<<part
);
993 if (part_is_closed
) {
994 if (part
== 2 && fdp
->d_exclmask
&(1<<part
))
997 fdp
->d_exclmask
&= ~(1<<part
);
998 FDERRPRINT(FDEP_L0
, FDEM_CLOS
,
1000 "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n",
1001 fdp
->d_exclmask
, fdp
->d_regopen
[otyp
],
1002 fdp
->d_lyropen
[part
]));
1004 if (fd_unit_is_open(fdp
) == 0)
1005 fdp
->d_obj
->fj_flags
&= ~FUNIT_CHANGED
;
1007 sema_v(&fdp
->d_ocsem
);
1013 fd_read(dev_t dev
, struct uio
*uio
, cred_t
*cred_p
)
1015 return (physio(fd_strategy
, NULL
, dev
, B_READ
, minphys
, uio
));
1020 fd_write(dev_t dev
, struct uio
*uio
, cred_t
*cred_p
)
1022 return (physio(fd_strategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));
1027 * checks operation, hangs buf struct off fdcntlr, calls fdstart
1028 * if not already busy. Note that if we call start, then the operation
1029 * will already be done on return (start sleeps).
1032 fd_strategy(struct buf
*bp
)
1034 struct fcu_obj
*fjp
;
1036 struct partition
*pp
;
1038 FDERRPRINT(FDEP_L1
, FDEM_STRA
,
1039 (CE_CONT
, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
1040 (void *)bp
, bp
->b_edev
));
1042 (void) fd_getdrive(bp
->b_edev
, &fjp
, &fdp
);
1045 * Ignoring return because device exist.
1046 * Returned unit value is not used.
1048 pp
= &fdp
->d_part
[PARTITION(bp
->b_edev
)];
1050 if (fjp
->fj_chars
->fdc_sec_size
> NBPSCTR
&& (bp
->b_blkno
& 1)) {
1051 FDERRPRINT(FDEP_L3
, FDEM_STRA
,
1052 (CE_WARN
, "fd%d: block %ld is not start of sector!",
1053 DRIVE(bp
->b_edev
), (long)bp
->b_blkno
));
1054 bp
->b_error
= EINVAL
;
1058 if ((bp
->b_blkno
> pp
->p_size
)) {
1059 FDERRPRINT(FDEP_L3
, FDEM_STRA
,
1060 (CE_WARN
, "fd%d: block %ld is past the end! (nblk=%ld)",
1061 DRIVE(bp
->b_edev
), (long)bp
->b_blkno
, pp
->p_size
));
1062 bp
->b_error
= ENOSPC
;
1066 /* if at end of file, skip out now */
1067 if (bp
->b_blkno
== pp
->p_size
) {
1068 if ((bp
->b_flags
& B_READ
) == 0) {
1069 /* a write needs to get an error! */
1070 bp
->b_error
= ENOSPC
;
1073 bp
->b_resid
= bp
->b_bcount
;
1078 /* if operation not a multiple of sector size, is error! */
1079 if (bp
->b_bcount
% fjp
->fj_chars
->fdc_sec_size
) {
1080 FDERRPRINT(FDEP_L3
, FDEM_STRA
,
1081 (CE_WARN
, "fd%d: count %ld must be a multiple of %d",
1082 DRIVE(bp
->b_edev
), bp
->b_bcount
,
1083 fjp
->fj_chars
->fdc_sec_size
));
1084 bp
->b_error
= EINVAL
;
1089 * Put the buf request in the drive's queue, FIFO.
1092 mutex_enter(&fjp
->fj_lock
);
1094 kstat_waitq_enter(KIOSP
);
1096 fdp
->d_actl
->av_forw
= bp
;
1100 if (!(fjp
->fj_flags
& FUNIT_BUSY
)) {
1103 mutex_exit(&fjp
->fj_lock
);
1107 bp
->b_resid
= bp
->b_bcount
;
1108 bp
->b_flags
|= B_ERROR
;
1115 * called from fd_strategy() or from fdXXXX() to setup and
1116 * start operations of read or write only (using buf structs).
1117 * Because the chip doesn't handle crossing cylinder boundaries on
1118 * the fly, this takes care of those boundary conditions. Note that
1119 * it sleeps until the operation is done *within fdstart* - so that
1120 * when fdstart returns, the operation is already done.
1123 fdstart(struct fcu_obj
*fjp
)
1126 struct fdisk
*fdp
= (struct fdisk
*)fjp
->fj_data
;
1127 struct fd_char
*chp
;
1128 struct partition
*pp
;
1130 uint_t bincyl
; /* (the number of the desired) block in cyl. */
1131 uint_t blk
, len
, tlen
;
1132 uint_t secpcyl
; /* number of sectors per cylinder */
1133 int cyl
, head
, sect
;
1137 ASSERT(MUTEX_HELD(&fjp
->fj_lock
));
1138 fjp
->fj_flags
|= FUNIT_BUSY
;
1140 while ((bp
= fdp
->d_actf
) != NULL
) {
1141 fdp
->d_actf
= bp
->av_forw
;
1142 fdp
->d_current
= bp
;
1143 if (fdp
->d_iostat
) {
1144 kstat_waitq_to_runq(KIOSP
);
1146 mutex_exit(&fjp
->fj_lock
);
1148 FDERRPRINT(FDEP_L0
, FDEM_STRT
,
1149 (CE_CONT
, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n",
1150 (void *)bp
, (long)bp
->b_blkno
, bp
->b_bcount
));
1151 bp
->b_flags
&= ~B_ERROR
;
1153 bp
->b_resid
= bp
->b_bcount
; /* init resid */
1155 ASSERT(DRIVE(bp
->b_edev
) == ddi_get_instance(fjp
->fj_dip
));
1156 unit
= fjp
->fj_unit
;
1157 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
1159 bp_mapin(bp
); /* map in buffers */
1161 pp
= &fdp
->d_part
[PARTITION(bp
->b_edev
)];
1162 /* starting blk adjusted for the partition */
1163 blk
= bp
->b_blkno
+ pp
->p_start
;
1164 ptend
= pp
->p_start
+ pp
->p_size
; /* end of the partition */
1166 chp
= fjp
->fj_chars
;
1167 secpcyl
= chp
->fdc_nhead
* chp
->fdc_secptrack
;
1168 switch (chp
->fdc_sec_size
) {
1169 /* convert logical block numbers to sector numbers */
1171 sctrshft
= SCTRSHFT
+ 1;
1177 sctrshft
= SCTRSHFT
;
1180 sctrshft
= SCTRSHFT
- 1;
1187 * If off the end, limit to actual amount that
1188 * can be transferred.
1190 if ((blk
+ (bp
->b_bcount
>> sctrshft
)) > ptend
)
1191 /* to end of partition */
1192 len
= (ptend
- blk
) << sctrshft
;
1195 addr
= bp
->b_un
.b_addr
; /* data buffer address */
1198 * now we have the real start blk, addr and len for xfer op
1201 /* start cyl of req */
1202 cyl
= blk
/ secpcyl
;
1203 bincyl
= blk
% secpcyl
;
1204 /* start head of req */
1205 head
= bincyl
/ chp
->fdc_secptrack
;
1206 /* start sector of req */
1207 sect
= (bincyl
% chp
->fdc_secptrack
) + 1;
1209 * If the desired block and length will go beyond the
1210 * cylinder end, then limit it to the cylinder end.
1212 if (bp
->b_flags
& B_READ
) {
1213 if (len
> ((secpcyl
- bincyl
) << sctrshft
))
1214 tlen
= (secpcyl
- bincyl
) << sctrshft
;
1219 ((chp
->fdc_secptrack
- sect
+ 1) <<
1222 (chp
->fdc_secptrack
- sect
+ 1) <<
1228 FDERRPRINT(FDEP_L0
, FDEM_STRT
, (CE_CONT
,
1229 " blk 0x%x addr 0x%p len 0x%x "
1230 "cyl %d head %d sec %d\n resid 0x%lx, tlen %d\n",
1231 blk
, (void *)addr
, len
, cyl
, head
, sect
,
1232 bp
->b_resid
, tlen
));
1235 * (try to) do the operation - failure returns an errno
1237 bp
->b_error
= fjp
->fj_ops
->fco_rw(fjp
, unit
,
1238 bp
->b_flags
& B_READ
, cyl
, head
, sect
, addr
, tlen
);
1239 if (bp
->b_error
!= 0) {
1240 FDERRPRINT(FDEP_L3
, FDEM_STRT
, (CE_WARN
,
1241 "fdstart: bad exec of bp: 0x%p, err=%d",
1242 (void *)bp
, bp
->b_error
));
1243 bp
->b_flags
|= B_ERROR
;
1246 blk
+= tlen
>> sctrshft
;
1249 bp
->b_resid
-= tlen
;
1251 FDERRPRINT(FDEP_L0
, FDEM_STRT
,
1252 (CE_CONT
, "fdstart done: b_resid %lu, b_count %lu\n",
1253 bp
->b_resid
, bp
->b_bcount
));
1254 if (fdp
->d_iostat
) {
1255 if (bp
->b_flags
& B_READ
) {
1257 KIOSP
->nread
+= (bp
->b_bcount
- bp
->b_resid
);
1260 KIOSP
->nwritten
+= (bp
->b_bcount
- bp
->b_resid
);
1262 kstat_runq_exit(KIOSP
);
1267 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
1268 mutex_enter(&fjp
->fj_lock
);
1271 fjp
->fj_flags
^= FUNIT_BUSY
;
1276 fd_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int flag
, cred_t
*cred_p
,
1280 struct dk_cinfo dki
;
1282 struct dk_allmap dka
;
1283 struct fd_char fdchar
;
1284 struct fd_drive drvchar
;
1288 struct fcu_obj
*fjp
= NULL
;
1289 struct fdisk
*fdp
= NULL
;
1291 struct dk_label
*label
;
1292 int nblks
, part
, unit
;
1294 enum dkio_state state
;
1296 unit
= fd_getdrive(dev
, &fjp
, &fdp
);
1300 FDERRPRINT(FDEP_L1
, FDEM_IOCT
,
1301 (CE_CONT
, "fd_ioctl fd unit %d: cmd %x, arg %lx\n",
1306 fjp
->fj_ops
->fco_dkinfo(fjp
, &cpy
.dki
);
1307 cpy
.dki
.dki_cnum
= FDCTLR(fjp
->fj_unit
);
1308 cpy
.dki
.dki_unit
= FDUNIT(fjp
->fj_unit
);
1309 cpy
.dki
.dki_partition
= PARTITION(dev
);
1310 if (ddi_copyout(&cpy
.dki
, (void *)arg
, sizeof (cpy
.dki
), flag
))
1314 case DKIOCG_PHYGEOM
:
1315 case DKIOCG_VIRTGEOM
:
1316 cpy
.dkg
.dkg_nsect
= fjp
->fj_chars
->fdc_secptrack
;
1319 if (fjp
->fj_flags
& FUNIT_LABELOK
)
1320 cpy
.dkg
.dkg_nsect
= (fjp
->fj_chars
->fdc_secptrack
*
1321 fjp
->fj_chars
->fdc_sec_size
) / DEV_BSIZE
;
1323 cpy
.dkg
.dkg_nsect
= fjp
->fj_chars
->fdc_secptrack
;
1325 cpy
.dkg
.dkg_pcyl
= fjp
->fj_chars
->fdc_ncyl
;
1326 cpy
.dkg
.dkg_ncyl
= fjp
->fj_chars
->fdc_ncyl
;
1327 cpy
.dkg
.dkg_nhead
= fjp
->fj_chars
->fdc_nhead
;
1328 cpy
.dkg
.dkg_intrlv
= fjp
->fj_attr
->fda_intrlv
;
1329 cpy
.dkg
.dkg_rpm
= fjp
->fj_attr
->fda_rotatespd
;
1330 cpy
.dkg
.dkg_read_reinstruct
=
1331 (int)(cpy
.dkg
.dkg_nsect
* cpy
.dkg
.dkg_rpm
* 4) / 60000;
1332 cpy
.dkg
.dkg_write_reinstruct
= cpy
.dkg
.dkg_read_reinstruct
;
1333 if (ddi_copyout(&cpy
.dkg
, (void *)arg
, sizeof (cpy
.dkg
), flag
))
1338 if (ddi_copyin((void *)arg
, &cpy
.dkg
,
1339 sizeof (struct dk_geom
), flag
)) {
1343 mutex_enter(&fjp
->fj_lock
);
1344 fjp
->fj_chars
->fdc_ncyl
= cpy
.dkg
.dkg_ncyl
;
1345 fjp
->fj_chars
->fdc_nhead
= cpy
.dkg
.dkg_nhead
;
1346 fjp
->fj_chars
->fdc_secptrack
= cpy
.dkg
.dkg_nsect
;
1347 fjp
->fj_attr
->fda_intrlv
= cpy
.dkg
.dkg_intrlv
;
1348 fjp
->fj_attr
->fda_rotatespd
= cpy
.dkg
.dkg_rpm
;
1349 fdp
->d_curfdtype
= -1;
1350 mutex_exit(&fjp
->fj_lock
);
1354 * return the map of all logical partitions
1358 * Note the conversion from starting sector number
1359 * to starting cylinder number.
1360 * Return error if division results in a remainder.
1362 nblks
= fjp
->fj_chars
->fdc_nhead
* fjp
->fj_chars
->fdc_secptrack
;
1364 #ifdef _MULTI_DATAMODEL
1365 switch (ddi_model_convert_from(flag
& FMODELS
)) {
1366 case DDI_MODEL_ILP32
:
1368 struct dk_allmap32 dka32
;
1370 for (part
= 0; part
< NDKMAP
; part
++) {
1371 if ((fdp
->d_part
[part
].p_start
% nblks
) != 0)
1373 dka32
.dka_map
[part
].dkl_cylno
=
1374 fdp
->d_part
[part
].p_start
/ nblks
;
1375 dka32
.dka_map
[part
].dkl_nblk
=
1376 fdp
->d_part
[part
].p_size
;
1379 if (ddi_copyout(&dka32
, (void *)arg
,
1380 sizeof (struct dk_allmap32
), flag
))
1385 case DDI_MODEL_NONE
:
1387 #endif /* _MULTI_DATAMODEL */
1389 dmp
= (struct dk_map
*)&cpy
.dka
;
1390 for (part
= 0; part
< NDKMAP
; part
++) {
1391 if ((fdp
->d_part
[part
].p_start
% nblks
) != 0)
1394 fdp
->d_part
[part
].p_start
/ nblks
;
1395 dmp
->dkl_nblk
= fdp
->d_part
[part
].p_size
;
1399 if (ddi_copyout(&cpy
.dka
, (void *)arg
,
1400 sizeof (struct dk_allmap
), flag
))
1402 #ifdef _MULTI_DATAMODEL
1406 #endif /* _MULTI_DATAMODEL */
1411 * Set the map of all logical partitions
1415 #ifdef _MULTI_DATAMODEL
1416 switch (ddi_model_convert_from(flag
& FMODELS
)) {
1417 case DDI_MODEL_ILP32
:
1419 struct dk_allmap32 dka32
;
1421 if (ddi_copyin((void *)arg
, &dka32
,
1422 sizeof (dka32
), flag
)) {
1426 for (part
= 0; part
< NDKMAP
; part
++) {
1427 cpy
.dka
.dka_map
[part
].dkl_cylno
=
1428 dka32
.dka_map
[part
].dkl_cylno
;
1429 cpy
.dka
.dka_map
[part
].dkl_nblk
=
1430 dka32
.dka_map
[part
].dkl_nblk
;
1434 case DDI_MODEL_NONE
:
1436 #endif /* _MULTI_DATAMODEL */
1437 if (ddi_copyin((void *)arg
, &cpy
.dka
, sizeof (cpy
.dka
), flag
))
1439 #ifdef _MULTI_DATAMODEL
1443 #endif /* _MULTI_DATAMODEL */
1448 dmp
= (struct dk_map
*)&cpy
.dka
;
1449 nblks
= fjp
->fj_chars
->fdc_nhead
*
1450 fjp
->fj_chars
->fdc_secptrack
;
1451 mutex_enter(&fjp
->fj_lock
);
1453 * Note the conversion from starting cylinder number
1454 * to starting sector number.
1456 for (part
= 0; part
< NDKMAP
; part
++) {
1457 fdp
->d_part
[part
].p_start
= dmp
->dkl_cylno
*
1459 fdp
->d_part
[part
].p_size
= dmp
->dkl_nblk
;
1462 mutex_exit(&fjp
->fj_lock
);
1467 mutex_enter(&fjp
->fj_lock
);
1470 * Exit if the diskette has no label.
1471 * Also, get the label to make sure the correct one is
1472 * being used since the diskette may have changed
1474 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
1475 rval
= fdgetlabel(fjp
, unit
);
1476 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
1478 mutex_exit(&fjp
->fj_lock
);
1483 fd_build_user_vtoc(fjp
, fdp
, &vtoc
);
1484 mutex_exit(&fjp
->fj_lock
);
1486 #ifdef _MULTI_DATAMODEL
1487 switch (ddi_model_convert_from(flag
& FMODELS
)) {
1488 case DDI_MODEL_ILP32
:
1490 struct vtoc32 vtoc32
;
1492 vtoctovtoc32(vtoc
, vtoc32
);
1494 if (ddi_copyout(&vtoc32
, (void *)arg
,
1495 sizeof (vtoc32
), flag
))
1500 case DDI_MODEL_NONE
:
1502 #endif /* _MULTI_DATAMODEL */
1503 if (ddi_copyout(&vtoc
, (void *)arg
,
1504 sizeof (vtoc
), flag
))
1506 #ifdef _MULTI_DATAMODEL
1509 #endif /* _MULTI_DATAMODEL */
1515 #ifdef _MULTI_DATAMODEL
1516 switch (ddi_model_convert_from(flag
& FMODELS
)) {
1517 case DDI_MODEL_ILP32
:
1519 struct vtoc32 vtoc32
;
1521 if (ddi_copyin((void *)arg
, &vtoc32
,
1522 sizeof (vtoc32
), flag
)) {
1527 vtoc32tovtoc(vtoc32
, vtoc
);
1531 case DDI_MODEL_NONE
:
1533 #endif /* _MULTI_DATAMODEL */
1534 if (ddi_copyin((void *)arg
, &vtoc
, sizeof (vtoc
), flag
))
1536 #ifdef _MULTI_DATAMODEL
1539 #endif /* _MULTI_DATAMODEL */
1545 label
= kmem_zalloc(sizeof (struct dk_label
), KM_SLEEP
);
1547 mutex_enter(&fjp
->fj_lock
);
1549 if ((rval
= fd_build_label_vtoc(fjp
, fdp
, &vtoc
, label
)) == 0) {
1550 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
1551 rval
= fjp
->fj_ops
->fco_rw(fjp
, unit
, FDWRITE
,
1552 0, 0, 1, (caddr_t
)label
, sizeof (struct dk_label
));
1553 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
1555 mutex_exit(&fjp
->fj_lock
);
1556 kmem_free(label
, sizeof (struct dk_label
));
1560 FDERRPRINT(FDEP_L1
, FDEM_IOCT
,
1561 (CE_CONT
, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit
));
1563 if (ddi_copyin((void *)arg
, &state
, sizeof (int), flag
)) {
1568 rval
= fd_check_media(dev
, state
);
1570 if (ddi_copyout(&fdp
->d_media_state
, (void *)arg
,
1571 sizeof (int), flag
))
1576 if (ddi_copyout(fjp
->fj_chars
, (void *)arg
,
1577 sizeof (struct fd_char
), flag
))
1582 if (ddi_copyin((void *)arg
, &cpy
.fdchar
,
1583 sizeof (struct fd_char
), flag
)) {
1587 switch (cpy
.fdchar
.fdc_transfer_rate
) {
1589 if ((fdp
->d_media
& (1 << FMT_3M
)) == 0) {
1591 "fdioschar:Medium density not supported\n");
1595 mutex_enter(&fjp
->fj_lock
);
1596 fjp
->fj_attr
->fda_rotatespd
= 360;
1597 mutex_exit(&fjp
->fj_lock
);
1598 /* cpy.fdchar.fdc_transfer_rate = 500; */
1604 mutex_enter(&fjp
->fj_lock
);
1605 *(fjp
->fj_chars
) = cpy
.fdchar
;
1606 fdp
->d_curfdtype
= -1;
1607 fjp
->fj_flags
&= ~FUNIT_CHAROK
;
1608 mutex_exit(&fjp
->fj_lock
);
1613 FDERRPRINT(FDEP_L4
, FDEM_IOCT
,
1614 (CE_WARN
, "fd_ioctl fd unit %d: FDIOSCHAR odd "
1616 unit
, cpy
.fdchar
.fdc_transfer_rate
));
1623 * set all characteristics and geometry to the defaults
1626 mutex_enter(&fjp
->fj_lock
);
1627 fdp
->d_curfdtype
= fdp
->d_deffdtype
;
1628 *fjp
->fj_chars
= *defchar
[fdp
->d_curfdtype
];
1629 *fjp
->fj_attr
= fdtypes
[fdp
->d_curfdtype
];
1630 bcopy(fdparts
[fdp
->d_curfdtype
],
1631 fdp
->d_part
, sizeof (struct partition
) * NDKMAP
);
1632 fjp
->fj_flags
&= ~FUNIT_CHAROK
;
1633 mutex_exit(&fjp
->fj_lock
);
1636 case FDEJECT
: /* eject disk */
1638 fjp
->fj_flags
&= ~(FUNIT_LABELOK
| FUNIT_UNLABELED
);
1642 case FDGETCHANGE
: /* disk changed */
1643 if (ddi_copyin((void *)arg
, &cpy
.temp
, sizeof (int), flag
)) {
1647 mutex_enter(&fjp
->fj_lock
);
1648 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
1650 if (fjp
->fj_flags
& FUNIT_CHANGED
)
1651 cpy
.temp
|= FDGC_HISTORY
;
1653 cpy
.temp
&= ~FDGC_HISTORY
;
1654 fjp
->fj_flags
&= ~FUNIT_CHANGED
;
1656 if (fjp
->fj_ops
->fco_getchng(fjp
, unit
)) {
1657 cpy
.temp
|= FDGC_DETECTED
;
1658 fjp
->fj_ops
->fco_resetchng(fjp
, unit
);
1660 * check diskette again only if it was removed
1662 if (fjp
->fj_ops
->fco_getchng(fjp
, unit
)) {
1664 * no diskette is present
1666 cpy
.temp
|= FDGC_CURRENT
;
1667 if (fjp
->fj_flags
& FUNIT_CHGDET
)
1669 * again no diskette; not a new change
1671 cpy
.temp
^= FDGC_DETECTED
;
1673 fjp
->fj_flags
|= FUNIT_CHGDET
;
1676 * a new diskette is present
1678 cpy
.temp
&= ~FDGC_CURRENT
;
1679 fjp
->fj_flags
&= ~FUNIT_CHGDET
;
1682 cpy
.temp
&= ~(FDGC_DETECTED
| FDGC_CURRENT
);
1683 fjp
->fj_flags
&= ~FUNIT_CHGDET
;
1686 * also get state of write protection
1688 if (fjp
->fj_flags
& FUNIT_WPROT
) {
1689 cpy
.temp
|= FDGC_CURWPROT
;
1691 cpy
.temp
&= ~FDGC_CURWPROT
;
1693 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
1694 mutex_exit(&fjp
->fj_lock
);
1696 if (ddi_copyout(&cpy
.temp
, (void *)arg
, sizeof (int), flag
))
1700 case FDGETDRIVECHAR
:
1701 if (ddi_copyout(fjp
->fj_drive
, (void *)arg
,
1702 sizeof (struct fd_drive
), flag
))
1706 case FDSETDRIVECHAR
:
1707 if (ddi_copyin((void *)arg
, &cpy
.drvchar
,
1708 sizeof (struct fd_drive
), flag
)) {
1712 mutex_enter(&fjp
->fj_lock
);
1713 *(fjp
->fj_drive
) = cpy
.drvchar
;
1714 fdp
->d_curfdtype
= -1;
1715 fjp
->fj_flags
&= ~FUNIT_CHAROK
;
1716 mutex_exit(&fjp
->fj_lock
);
1719 case DKIOCREMOVABLE
: {
1722 /* no brainer: floppies are always removable */
1723 if (ddi_copyout(&i
, (void *)arg
, sizeof (int), flag
)) {
1729 case DKIOCGMEDIAINFO
:
1730 rval
= fd_get_media_info(fjp
, (caddr_t
)arg
, flag
);
1736 int cyl
, head
, spc
, spt
;
1738 #ifdef _MULTI_DATAMODEL
1739 switch (ddi_model_convert_from(flag
& FMODELS
)) {
1740 case DDI_MODEL_ILP32
:
1742 struct fd_cmd32 fc32
;
1744 if (ddi_copyin((void *)arg
, &fc32
,
1745 sizeof (fc32
), flag
)) {
1750 fc
.fdc_cmd
= fc32
.fdc_cmd
;
1751 fc
.fdc_flags
= fc32
.fdc_flags
;
1752 fc
.fdc_blkno
= fc32
.fdc_blkno
;
1753 fc
.fdc_secnt
= fc32
.fdc_secnt
;
1754 fc
.fdc_bufaddr
= (caddr_t
)(uintptr_t)fc32
.fdc_bufaddr
;
1755 fc
.fdc_buflen
= fc32
.fdc_buflen
;
1759 case DDI_MODEL_NONE
:
1761 #endif /* _MULTI_DATAMODEL */
1763 if (ddi_copyin((void *)arg
, &fc
, sizeof (fc
), flag
)) {
1767 #ifdef _MULTI_DATAMODEL
1770 #endif /* _MULTI_DATAMODEL */
1775 if (fc
.fdc_cmd
== FDCMD_READ
|| fc
.fdc_cmd
== FDCMD_WRITE
) {
1776 auto struct iovec aiov
;
1777 auto struct uio auio
;
1778 struct uio
*uio
= &auio
;
1780 spc
= (fc
.fdc_cmd
== FDCMD_READ
)? B_READ
: B_WRITE
;
1782 bzero(&auio
, sizeof (struct uio
));
1783 bzero(&aiov
, sizeof (struct iovec
));
1784 aiov
.iov_base
= fc
.fdc_bufaddr
;
1785 aiov
.iov_len
= (uint_t
)fc
.fdc_secnt
*
1786 fjp
->fj_chars
->fdc_sec_size
;
1787 uio
->uio_iov
= &aiov
;
1789 uio
->uio_iovcnt
= 1;
1790 uio
->uio_resid
= aiov
.iov_len
;
1791 uio
->uio_segflg
= UIO_USERSPACE
;
1793 rval
= physio(fd_strategy
, NULL
, dev
,
1796 } else if (fc
.fdc_cmd
== FDCMD_FORMAT_TRACK
) {
1797 spt
= fjp
->fj_chars
->fdc_secptrack
; /* sec/trk */
1798 spc
= fjp
->fj_chars
->fdc_nhead
* spt
; /* sec/cyl */
1799 cyl
= fc
.fdc_blkno
/ spc
;
1800 head
= (fc
.fdc_blkno
% spc
) / spt
;
1801 if ((cyl
| head
) == 0)
1803 ~(FUNIT_LABELOK
| FUNIT_UNLABELED
);
1805 FDERRPRINT(FDEP_L0
, FDEM_FORM
,
1806 (CE_CONT
, "fd_format cyl %d, hd %d\n", cyl
, head
));
1807 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
1808 rval
= fjp
->fj_ops
->fco_format(fjp
, unit
, cyl
, head
,
1810 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
1814 FDERRPRINT(FDEP_L4
, FDEM_IOCT
,
1815 (CE_WARN
, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete",
1822 rval
= fd_rawioctl(fjp
, unit
, (caddr_t
)arg
, flag
);
1826 FDERRPRINT(FDEP_L4
, FDEM_IOCT
,
1827 (CE_WARN
, "fd_ioctl fd unit %d: invalid ioctl 0x%x",
1836 fd_build_user_vtoc(struct fcu_obj
*fjp
, struct fdisk
*fdp
, struct vtoc
*vtocp
)
1838 struct partition
*vpart
;
1843 * Return vtoc structure fields in the provided VTOC area, addressed
1847 bzero(vtocp
, sizeof (struct vtoc
));
1849 bcopy(fdp
->d_vtoc_bootinfo
,
1850 vtocp
->v_bootinfo
, sizeof (vtocp
->v_bootinfo
));
1852 vtocp
->v_sanity
= VTOC_SANE
;
1853 vtocp
->v_version
= fdp
->d_vtoc_version
;
1854 bcopy(fdp
->d_vtoc_volume
, vtocp
->v_volume
, LEN_DKL_VVOL
);
1855 if (fjp
->fj_flags
& FUNIT_LABELOK
) {
1856 vtocp
->v_sectorsz
= DEV_BSIZE
;
1859 vtocp
->v_sectorsz
= fjp
->fj_chars
->fdc_sec_size
;
1860 xblk
= vtocp
->v_sectorsz
/ DEV_BSIZE
;
1862 vtocp
->v_nparts
= 3; /* <= NDKMAP; */
1865 * Copy partitioning information.
1867 bcopy(fdp
->d_part
, vtocp
->v_part
, sizeof (struct partition
) * NDKMAP
);
1868 for (i
= NDKMAP
, vpart
= vtocp
->v_part
; i
&& (xblk
> 1); i
--, vpart
++) {
1869 /* correct partition info if sector size > 512 bytes */
1870 vpart
->p_start
/= xblk
;
1871 vpart
->p_size
/= xblk
;
1874 bcopy(fdp
->d_vtoc_timestamp
,
1875 vtocp
->timestamp
, sizeof (fdp
->d_vtoc_timestamp
));
1876 bcopy(fdp
->d_vtoc_asciilabel
, vtocp
->v_asciilabel
, LEN_DKL_ASCII
);
1881 fd_build_label_vtoc(struct fcu_obj
*fjp
, struct fdisk
*fdp
, struct vtoc
*vtocp
,
1882 struct dk_label
*labelp
)
1884 struct partition
*vpart
;
1892 * Sanity-check the vtoc
1894 if (vtocp
->v_sanity
!= VTOC_SANE
||
1895 vtocp
->v_nparts
> NDKMAP
|| vtocp
->v_nparts
<= 0) {
1896 FDERRPRINT(FDEP_L3
, FDEM_IOCT
,
1897 (CE_WARN
, "fd_build_label: sanity check on vtoc failed"));
1902 * before copying the vtoc, the partition information in it should be
1903 * checked against the information the driver already has on the
1907 nblks
= (fjp
->fj_chars
->fdc_nhead
* fjp
->fj_chars
->fdc_secptrack
*
1908 fjp
->fj_chars
->fdc_sec_size
) / DEV_BSIZE
;
1909 if (nblks
== 0 || fjp
->fj_chars
->fdc_ncyl
== 0)
1911 vpart
= vtocp
->v_part
;
1914 * Check the partition information in the vtoc. The starting sectors
1915 * must lie along cylinder boundaries. (NDKMAP entries are checked
1916 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
1917 * is less than NDKMAP)
1919 for (i
= NDKMAP
; i
; i
--) {
1920 if ((vpart
->p_start
% nblks
) != 0) {
1923 ncyl
= vpart
->p_start
/ nblks
;
1924 ncyl
+= vpart
->p_size
/ nblks
;
1925 if ((vpart
->p_size
% nblks
) != 0)
1927 if (ncyl
> (long)fjp
->fj_chars
->fdc_ncyl
) {
1934 bcopy(vtocp
->v_bootinfo
, fdp
->d_vtoc_bootinfo
,
1935 sizeof (vtocp
->v_bootinfo
));
1936 fdp
->d_vtoc_version
= vtocp
->v_version
;
1937 bcopy(vtocp
->v_volume
, fdp
->d_vtoc_volume
, LEN_DKL_VVOL
);
1940 * Copy partitioning information.
1942 bcopy(vtocp
->v_part
, fdp
->d_part
, sizeof (struct partition
) * NDKMAP
);
1943 bcopy(vtocp
->timestamp
, fdp
->d_vtoc_timestamp
,
1944 sizeof (fdp
->d_vtoc_timestamp
));
1945 bcopy(vtocp
->v_asciilabel
, fdp
->d_vtoc_asciilabel
, LEN_DKL_ASCII
);
1948 * construct the diskette label in supplied buffer
1951 /* Put appropriate vtoc structure fields into the disk label */
1952 labelp
->dkl_vtoc
.v_bootinfo
[0] = (uint32_t)vtocp
->v_bootinfo
[0];
1953 labelp
->dkl_vtoc
.v_bootinfo
[1] = (uint32_t)vtocp
->v_bootinfo
[1];
1954 labelp
->dkl_vtoc
.v_bootinfo
[2] = (uint32_t)vtocp
->v_bootinfo
[2];
1956 labelp
->dkl_vtoc
.v_sanity
= vtocp
->v_sanity
;
1957 labelp
->dkl_vtoc
.v_version
= vtocp
->v_version
;
1959 bcopy(vtocp
->v_volume
, labelp
->dkl_vtoc
.v_volume
, LEN_DKL_VVOL
);
1961 labelp
->dkl_vtoc
.v_nparts
= vtocp
->v_nparts
;
1963 bcopy(vtocp
->v_reserved
, labelp
->dkl_vtoc
.v_reserved
,
1964 sizeof (labelp
->dkl_vtoc
.v_reserved
));
1966 for (i
= 0; i
< (int)vtocp
->v_nparts
; i
++) {
1967 labelp
->dkl_vtoc
.v_part
[i
].p_tag
= vtocp
->v_part
[i
].p_tag
;
1968 labelp
->dkl_vtoc
.v_part
[i
].p_flag
= vtocp
->v_part
[i
].p_flag
;
1969 labelp
->dkl_vtoc
.v_part
[i
].p_start
= vtocp
->v_part
[i
].p_start
;
1970 labelp
->dkl_vtoc
.v_part
[i
].p_size
= vtocp
->v_part
[i
].p_size
;
1973 for (i
= 0; i
< NDKMAP
; i
++) {
1974 labelp
->dkl_vtoc
.v_timestamp
[i
] = vtocp
->timestamp
[i
];
1976 bcopy(vtocp
->v_asciilabel
, labelp
->dkl_asciilabel
, LEN_DKL_ASCII
);
1979 labelp
->dkl_pcyl
= fjp
->fj_chars
->fdc_ncyl
;
1980 labelp
->dkl_ncyl
= fjp
->fj_chars
->fdc_ncyl
;
1981 labelp
->dkl_nhead
= fjp
->fj_chars
->fdc_nhead
;
1983 * The fdc_secptrack field of the fd_char structure is the number
1984 * of sectors per track where the sectors are fdc_sec_size.
1985 * The dkl_nsect field of the dk_label structure is the number of
1986 * DEV_BSIZE (512) byte sectors per track.
1988 labelp
->dkl_nsect
= (fjp
->fj_chars
->fdc_secptrack
*
1989 fjp
->fj_chars
->fdc_sec_size
) / DEV_BSIZE
;
1990 labelp
->dkl_intrlv
= fjp
->fj_attr
->fda_intrlv
;
1991 labelp
->dkl_rpm
= fjp
->fj_attr
->fda_rotatespd
;
1992 labelp
->dkl_read_reinstruct
=
1993 (int)(labelp
->dkl_nsect
* labelp
->dkl_rpm
* 4) / 60000;
1994 labelp
->dkl_write_reinstruct
= labelp
->dkl_read_reinstruct
;
1996 labelp
->dkl_magic
= DKL_MAGIC
;
1999 labelp
->dkl_cksum
= 0;
2000 sp
= (ushort_t
*)labelp
;
2001 while (sp
< &(labelp
->dkl_cksum
)) {
2004 labelp
->dkl_cksum
= sum
;
2010 fd_rawioctl(struct fcu_obj
*fjp
, int unit
, caddr_t arg
, int mode
)
2013 char *arg_result
= NULL
;
2019 FDERRPRINT(FDEP_L1
, FDEM_RAWI
,
2020 (CE_CONT
, "fd_rawioctl: cmd[0]=0x%x\n", fdr
.fdr_cmd
[0]));
2022 if (fjp
->fj_chars
->fdc_medium
!= 3 && fjp
->fj_chars
->fdc_medium
!= 5) {
2023 cmn_err(CE_CONT
, "fd_rawioctl: Medium density not supported\n");
2027 #ifdef _MULTI_DATAMODEL
2028 switch (ddi_model_convert_from(mode
& FMODELS
)) {
2029 case DDI_MODEL_ILP32
:
2031 struct fd_raw32 fdr32
;
2033 if (ddi_copyin(arg
, &fdr32
, sizeof (fdr32
), mode
))
2036 bcopy(fdr32
.fdr_cmd
, fdr
.fdr_cmd
, sizeof (fdr
.fdr_cmd
));
2037 fdr
.fdr_cnum
= fdr32
.fdr_cnum
;
2038 fdr
.fdr_nbytes
= fdr32
.fdr_nbytes
;
2039 fdr
.fdr_addr
= (caddr_t
)(uintptr_t)fdr32
.fdr_addr
;
2040 arg_result
= ((struct fd_raw32
*)arg
)->fdr_result
;
2044 case DDI_MODEL_NONE
:
2045 #endif /* ! _MULTI_DATAMODEL */
2047 if (ddi_copyin(arg
, &fdr
, sizeof (fdr
), mode
))
2050 arg_result
= ((struct fd_raw
*)arg
)->fdr_result
;
2052 #ifdef _MULTI_DATAMODEL
2055 #endif /* _MULTI_DATAMODEL */
2060 * copy user address & nbytes from raw_req so that we can
2061 * put kernel address in req structure
2063 uaddr
= fdr
.fdr_addr
;
2064 ucount
= (uint_t
)fdr
.fdr_nbytes
;
2067 switch (fdr
.fdr_cmd
[0] & 0x0f) {
2071 fdr
.fdr_addr
= kmem_zalloc(ucount
, KM_SLEEP
);
2072 if (ddi_copyin(uaddr
, fdr
.fdr_addr
,
2073 (size_t)fdr
.fdr_nbytes
, mode
)) {
2074 kmem_free(fdr
.fdr_addr
, ucount
);
2077 if ((*fdr
.fdr_addr
| fdr
.fdr_addr
[1]) == 0)
2078 fjp
->fj_flags
&= ~(FUNIT_LABELOK
| FUNIT_UNLABELED
);
2080 fdr
.fdr_cmd
[1] = (fdr
.fdr_cmd
[1] & ~3) | unit
;
2084 case FDRAW_WRITEDEL
:
2089 case FDRAW_READTRACK
:
2092 * In SunOS 4.X, we used to as_fault things in.
2093 * We really cannot do this in 5.0/SVr4. Unless
2094 * someone really believes that speed is of the
2095 * essence here, it is just much simpler to do
2096 * this in kernel space and use copyin/copyout.
2098 fdr
.fdr_addr
= kmem_alloc((size_t)ucount
, KM_SLEEP
);
2099 if (flag
== B_WRITE
) {
2100 if (ddi_copyin(uaddr
, fdr
.fdr_addr
, ucount
,
2102 kmem_free(fdr
.fdr_addr
, ucount
);
2108 fdr
.fdr_cmd
[1] = (fdr
.fdr_cmd
[1] & ~3) | unit
;
2114 case FDRAW_SENSE_DRV
:
2116 fdr
.fdr_cmd
[1] = (fdr
.fdr_cmd
[1] & ~3) | unit
;
2120 fdr
.fdr_cmd
[2] &= 0xfe; /* keep NoDMA bit clear */
2122 case FDRAW_SENSE_INT
:
2131 * Note that we ignore any error returns from controller
2132 * This is the way the driver has been, and it may be
2133 * that the raw ioctl senders simply don't want to
2134 * see any errors returned in this fashion.
2137 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
2138 rval
= fjp
->fj_ops
->fco_rwioctl(fjp
, unit
, (caddr_t
)&fdr
);
2140 if (ucount
&& flag
== B_READ
&& rval
== 0) {
2141 if (ddi_copyout(fdr
.fdr_addr
, uaddr
, ucount
, mode
)) {
2145 if (ddi_copyout(fdr
.fdr_result
, arg_result
, sizeof (fdr
.fdr_cmd
), mode
))
2148 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
2150 kmem_free(fdr
.fdr_addr
, ucount
);
2156 * property operation routine. return the number of blocks for the partition
2157 * in question or forward the request to the property facilities.
2160 fd_prop_op(dev_t dev
, dev_info_t
*dip
, ddi_prop_op_t prop_op
, int mod_flags
,
2161 char *name
, caddr_t valuep
, int *lengthp
)
2163 struct fcu_obj
*fjp
= NULL
;
2164 struct fdisk
*fdp
= NULL
;
2167 FDERRPRINT(FDEP_L1
, FDEM_PROP
,
2168 (CE_CONT
, "fd_prop_op: dip %p %s\n", (void *)dip
, name
));
2171 * Our dynamic properties are all device specific and size oriented.
2172 * Requests issued under conditions where size is valid are passed
2173 * to ddi_prop_op_nblocks with the size information, otherwise the
2174 * request is passed to ddi_prop_op.
2176 if (dev
== DDI_DEV_T_ANY
) {
2177 pass
: return (ddi_prop_op(dev
, dip
, prop_op
, mod_flags
,
2178 name
, valuep
, lengthp
));
2181 * Ignoring return value because success is checked by
2182 * verifying fjp and fdp and returned unit value is not used.
2184 (void) fd_getdrive(dev
, &fjp
, &fdp
);
2188 /* get nblocks value */
2189 nblocks64
= (ulong_t
)fdp
->d_part
[PARTITION(dev
)].p_size
;
2191 return (ddi_prop_op_nblocks(dev
, dip
, prop_op
, mod_flags
,
2192 name
, valuep
, lengthp
, nblocks64
));
2197 fd_media_watch(void *arg
)
2199 struct fcu_obj
*fjp
;
2204 #define DEBUG_ASSIGN unit=
2206 #define DEBUG_ASSIGN (void)
2208 DEBUG_ASSIGN
fd_getdrive((dev_t
)arg
, &fjp
, &fdp
);
2210 * Ignoring return in non DEBUG mode because device exist.
2211 * Returned unit value is not used.
2214 FDERRPRINT(FDEP_L0
, FDEM_IOCT
,
2215 (CE_CONT
, "fd_media_watch unit %d\n", unit
));
2218 * fd_get_media_state() cannot be called from this timeout function
2219 * because the floppy drive has to be selected first, and that could
2220 * force this function to sleep (while waiting for the select
2222 * Instead, just wakeup up driver.
2224 mutex_enter(&fjp
->fj_lock
);
2225 cv_broadcast(&fdp
->d_statecv
);
2226 mutex_exit(&fjp
->fj_lock
);
2230 fd_get_media_state(struct fcu_obj
*fjp
, int unit
)
2232 enum dkio_state state
;
2234 if (fjp
->fj_ops
->fco_getchng(fjp
, unit
)) {
2235 /* recheck disk only if DSKCHG "high" */
2236 fjp
->fj_ops
->fco_resetchng(fjp
, unit
);
2237 if (fjp
->fj_ops
->fco_getchng(fjp
, unit
)) {
2238 if (fjp
->fj_flags
& FUNIT_CHGDET
) {
2240 * again no diskette; not a new change
2245 * a new change; diskette was ejected
2247 fjp
->fj_flags
|= FUNIT_CHGDET
;
2248 state
= DKIO_EJECTED
;
2251 fjp
->fj_flags
&= ~FUNIT_CHGDET
;
2252 state
= DKIO_INSERTED
;
2255 fjp
->fj_flags
&= ~FUNIT_CHGDET
;
2256 state
= DKIO_INSERTED
;
2258 FDERRPRINT(FDEP_L0
, FDEM_IOCT
,
2259 (CE_CONT
, "fd_get_media_state unit %d: state %x\n", unit
, state
));
2264 fd_check_media(dev_t dev
, enum dkio_state state
)
2266 struct fcu_obj
*fjp
;
2271 unit
= fd_getdrive(dev
, &fjp
, &fdp
);
2273 mutex_enter(&fjp
->fj_lock
);
2275 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
2276 fdp
->d_media_state
= fd_get_media_state(fjp
, unit
);
2277 fdp
->d_media_timeout
= drv_usectohz(fd_check_media_time
);
2279 while (fdp
->d_media_state
== state
) {
2280 /* release the controller and drive */
2281 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
2284 fdp
->d_media_timeout_id
= timeout(fd_media_watch
,
2285 (void *)dev
, fdp
->d_media_timeout
);
2287 if (cv_wait_sig(&fdp
->d_statecv
, &fjp
->fj_lock
) == 0) {
2288 fdp
->d_media_timeout
= 0;
2289 mutex_exit(&fjp
->fj_lock
);
2292 fjp
->fj_ops
->fco_select(fjp
, unit
, 1);
2293 fdp
->d_media_state
= fd_get_media_state(fjp
, unit
);
2296 if (fdp
->d_media_state
== DKIO_INSERTED
) {
2297 err
= fdgetlabel(fjp
, unit
);
2299 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
2300 mutex_exit(&fjp
->fj_lock
);
2304 fjp
->fj_ops
->fco_select(fjp
, unit
, 0);
2305 mutex_exit(&fjp
->fj_lock
);
2310 * fd_get_media_info :
2311 * Collects medium information for
2312 * DKIOCGMEDIAINFO ioctl.
2316 fd_get_media_info(struct fcu_obj
*fjp
, caddr_t buf
, int flag
)
2318 struct dk_minfo media_info
;
2321 media_info
.dki_media_type
= DK_FLOPPY
;
2322 media_info
.dki_lbsize
= fjp
->fj_chars
->fdc_sec_size
;
2323 media_info
.dki_capacity
= fjp
->fj_chars
->fdc_ncyl
*
2324 fjp
->fj_chars
->fdc_secptrack
* fjp
->fj_chars
->fdc_nhead
;
2326 if (ddi_copyout(&media_info
, buf
, sizeof (struct dk_minfo
), flag
))