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.
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
31 * Floppy Disk Controller Driver
33 * for the standard PC architecture using the Intel 8272A fdc.
34 * Note that motor control and drive select use a latch external
37 * This driver is EISA capable, and uses DMA buffer chaining if available.
38 * If this driver is attached to the ISA bus nexus (or if the EISA bus driver
39 * does not support DMA buffer chaining), then the bus driver must ensure
40 * that dma mapping (breakup) and dma engine requests are properly degraded.
44 * hack for bugid 1160621:
45 * workaround compiler optimization bug by turning on DEBUG
51 #include <sys/param.h>
53 #include <sys/ioctl.h>
58 #include <sys/cmn_err.h>
60 #include <sys/debug.h>
64 #include <sys/autoconf.h>
67 #include <sys/kstat.h>
71 #include <sys/i8272A.h>
72 #include <sys/fd_debug.h>
73 #include <sys/promif.h>
75 #include <sys/sunddi.h>
78 * bss (uninitialized data)
80 static void *fdc_state_head
; /* opaque handle top of state structs */
81 static ddi_dma_attr_t fdc_dma_attr
;
82 static ddi_device_acc_attr_t fdc_accattr
= {DDI_DEVICE_ATTR_V0
,
83 DDI_STRUCTURE_LE_ACC
, DDI_STRICTORDER_ACC
};
88 #define OURUN_TRIES 12
89 static uchar_t rwretry
= 4;
90 static uchar_t skretry
= 3;
91 static uchar_t configurecmd
[4] = {FO_CNFG
, 0, 0x0F, 0};
92 static uchar_t recalcmd
[2] = {FO_RECAL
, 0};
93 static uchar_t senseintcmd
= FO_SINT
;
98 * for debugging, set rwretry and skretry = 1
100 * set fcerrmask to 224 or 644
102 * after debug, set rwretry to 4, skretry to 3, and fcerrlevel to 5
103 * set fcerrmask to FDEM_ALL
104 * or remove the define DEBUG
106 static uint_t fcerrmask
= FDEM_ALL
;
107 static int fcerrlevel
= 6;
109 #define KIOIP KSTAT_INTR_PTR(fcp->c_intrstat)
112 static xlate_tbl_t drate_mfm
[] = {
121 static xlate_tbl_t sector_size
[] = {
128 static xlate_tbl_t motor_onbits
[] = {
136 static xlate_tbl_t step_rate
[] = {
137 { 10, 0xF0}, /* for 500K data rate */
157 static xlate_tbl_t head_unld
[] = {
158 { 16, 0x1}, /* for 500K data rate */
178 static struct fdcmdinfo
{
179 char *cmdname
; /* command name */
180 uchar_t ncmdbytes
; /* number of bytes of command */
181 uchar_t nrsltbytes
; /* number of bytes in result */
182 uchar_t cmdtype
; /* characteristics */
186 "read_track", 9, 7, 1, /* 2 */
187 "specify", 3, 0, 3, /* 3 */
188 "sense_drv_status", 2, 1, 3, /* 4 */
189 "write", 9, 7, 1, /* 5 */
190 "read", 9, 7, 1, /* 6 */
191 "recalibrate", 2, 0, 2, /* 7 */
192 "sense_int_status", 1, 2, 3, /* 8 */
193 "write_del", 9, 7, 1, /* 9 */
194 "read_id", 2, 7, 2, /* A */
196 "read_del", 9, 7, 1, /* C */
197 "format_track", 10, 7, 1, /* D */
198 "dump_reg", 1, 10, 4, /* E */
199 "seek", 3, 0, 2, /* F */
200 "version", 1, 1, 3, /* 10 */
202 "perp_mode", 2, 0, 3, /* 12 */
203 "configure", 4, 0, 4, /* 13 */
209 fdc_bus_ctl(dev_info_t
*, dev_info_t
*, ddi_ctl_enum_t
, void *, void *);
210 static int get_ioaddr(dev_info_t
*dip
, int *ioaddr
);
211 static int get_unit(dev_info_t
*dip
, int *cntrl_num
);
213 struct bus_ops fdc_bus_ops
= {
216 0, /* ddi_intrspec_t (*bus_get_intrspec)(); */
217 0, /* int (*bus_add_intrspec)(); */
218 0, /* void (*bus_remove_intrspec)(); */
232 static int fdc_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
233 static int fdc_probe(dev_info_t
*);
234 static int fdc_attach(dev_info_t
*, ddi_attach_cmd_t
);
235 static int fdc_detach(dev_info_t
*, ddi_detach_cmd_t
);
236 static int fdc_quiesce(dev_info_t
*);
237 static int fdc_enhance_probe(struct fdcntlr
*fcp
);
239 struct dev_ops fdc_ops
= {
240 DEVO_REV
, /* devo_rev, */
242 fdc_getinfo
, /* getinfo */
243 nulldev
, /* identify */
244 fdc_probe
, /* probe */
245 fdc_attach
, /* attach */
246 fdc_detach
, /* detach */
248 (struct cb_ops
*)0, /* driver operations */
249 &fdc_bus_ops
, /* bus operations */
251 fdc_quiesce
, /* quiesce */
255 * This is the loadable module wrapper.
257 #include <sys/modctl.h>
259 extern struct mod_ops mod_driverops
;
261 static struct modldrv modldrv
= {
262 &mod_driverops
, /* Type of module. This one is a driver */
263 "Floppy Controller", /* Name of the module. */
264 &fdc_ops
, /* Driver ops vector */
267 static struct modlinkage modlinkage
= {
268 MODREV_1
, (void *)&modldrv
, NULL
276 if ((retval
= ddi_soft_state_init(&fdc_state_head
,
277 sizeof (struct fdcntlr
) + NFDUN
* sizeof (struct fcu_obj
), 0)) != 0)
280 if ((retval
= mod_install(&modlinkage
)) != 0)
281 ddi_soft_state_fini(&fdc_state_head
);
290 if ((retval
= mod_remove(&modlinkage
)) != 0)
292 ddi_soft_state_fini(&fdc_state_head
);
297 _info(struct modinfo
*modinfop
)
299 return (mod_info(&modlinkage
, modinfop
));
303 int fdc_abort(struct fcu_obj
*);
304 int fdc_dkinfo(struct fcu_obj
*, struct dk_cinfo
*);
305 int fdc_select(struct fcu_obj
*, int, int);
306 int fdgetchng(struct fcu_obj
*, int);
307 int fdresetchng(struct fcu_obj
*, int);
308 int fdrecalseek(struct fcu_obj
*, int, int, int);
309 int fdrw(struct fcu_obj
*, int, int, int, int, int, caddr_t
, uint_t
);
310 int fdtrkformat(struct fcu_obj
*, int, int, int, int);
311 int fdrawioctl(struct fcu_obj
*, int, caddr_t
);
313 static struct fcobjops fdc_iops
= {
314 fdc_abort
, /* controller abort */
315 fdc_dkinfo
, /* get disk controller info */
317 fdc_select
, /* select / deselect unit */
318 fdgetchng
, /* get media change */
319 fdresetchng
, /* reset media change */
320 fdrecalseek
, /* recal / seek */
321 NULL
, /* read /write request (UNUSED) */
322 fdrw
, /* read /write sector */
323 fdtrkformat
, /* format track */
324 fdrawioctl
/* raw ioctl */
329 * Function prototypes
331 void encode(xlate_tbl_t
*tablep
, int val
, uchar_t
*rcode
);
332 int decode(xlate_tbl_t
*, int, int *);
333 static int fdc_propinit1(struct fdcntlr
*, int);
334 static void fdc_propinit2(struct fdcntlr
*);
335 void fdcquiesce(struct fdcntlr
*);
336 int fdcsense_chng(struct fdcntlr
*, int);
337 int fdcsense_drv(struct fdcntlr
*, int);
338 int fdcsense_int(struct fdcntlr
*, int *, int *);
339 int fdcspecify(struct fdcntlr
*, int, int, int);
340 int fdcspdchange(struct fdcntlr
*, struct fcu_obj
*, int);
341 static int fdc_exec(struct fdcntlr
*, int, int);
342 int fdcheckdisk(struct fdcntlr
*, int);
343 static uint_t
fdc_intr(caddr_t arg
);
344 static void fdwatch(void *arg
);
345 static void fdmotort(void *arg
);
346 static int fdrecover(struct fdcntlr
*);
347 static int fdc_motorsm(struct fcu_obj
*, int, int);
348 static int fdc_statemach(struct fdcntlr
*);
349 int fdc_docmd(struct fdcntlr
*, uchar_t
*, uchar_t
);
350 int fdc_result(struct fdcntlr
*, uchar_t
*, uchar_t
);
354 fdc_bus_ctl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_ctl_enum_t ctlop
,
355 void *arg
, void *result
)
360 _NOTE(ARGUNUSED(result
));
362 FCERRPRINT(FDEP_L0
, FDEM_ATTA
,
363 (CE_CONT
, "fdc_bus_ctl: cmd= %x\n", ctlop
));
365 if ((fcp
= ddi_get_driver_private(dip
)) == NULL
)
366 return (DDI_FAILURE
);
370 case DDI_CTLOPS_REPORTDEV
:
371 cmn_err(CE_CONT
, "?%s%d at %s%d\n",
372 ddi_get_name(rdip
), ddi_get_instance(rdip
),
373 ddi_get_name(dip
), ddi_get_instance(dip
));
374 FCERRPRINT(FDEP_L3
, FDEM_ATTA
,
375 (CE_WARN
, "fdc_bus_ctl: report %s%d at %s%d",
376 ddi_get_name(rdip
), ddi_get_instance(rdip
),
377 ddi_get_name(dip
), ddi_get_instance(dip
)));
378 return (DDI_SUCCESS
);
380 case DDI_CTLOPS_INITCHILD
:
382 dev_info_t
*udip
= (dev_info_t
*)arg
;
386 char name
[MAXNAMELEN
];
388 FCERRPRINT(FDEP_L3
, FDEM_ATTA
,
389 (CE_WARN
, "fdc_bus_ctl: init child 0x%p", (void*)udip
));
390 cntlr
= fcp
->c_number
;
393 if (ddi_prop_op(DDI_DEV_T_ANY
, udip
, PROP_LEN_AND_VAL_BUF
,
394 DDI_PROP_DONTPASS
, "unit", (caddr_t
)&unit
, &len
)
395 != DDI_PROP_SUCCESS
||
396 cntlr
!= FDCTLR(unit
) ||
397 (fcp
->c_unit
[FDUNIT(unit
)])->fj_dip
)
398 return (DDI_NOT_WELL_FORMED
);
400 (void) sprintf(name
, "%d,%d", cntlr
, FDUNIT(unit
));
401 ddi_set_name_addr(udip
, name
);
403 fjp
= fcp
->c_unit
[FDUNIT(unit
)];
406 fjp
->fj_ops
= &fdc_iops
;
408 fjp
->fj_iblock
= &fcp
->c_iblock
;
410 ddi_set_driver_private(udip
, fjp
);
412 return (DDI_SUCCESS
);
414 case DDI_CTLOPS_UNINITCHILD
:
416 dev_info_t
*udip
= (dev_info_t
*)arg
;
418 FCERRPRINT(FDEP_L3
, FDEM_ATTA
,
419 (CE_WARN
, "fdc_bus_ctl: uninit child 0x%p", (void *)udip
));
420 fjp
= ddi_get_driver_private(udip
);
421 ddi_set_driver_private(udip
, NULL
);
423 ddi_set_name_addr(udip
, NULL
);
424 return (DDI_SUCCESS
);
427 return (DDI_FAILURE
);
432 fdc_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
437 _NOTE(ARGUNUSED(dip
));
440 case DDI_INFO_DEVT2DEVINFO
:
441 if (fcp
= ddi_get_soft_state(fdc_state_head
, (dev_t
)arg
)) {
442 *result
= fcp
->c_dip
;
449 case DDI_INFO_DEVT2INSTANCE
:
450 *result
= (void *)(uintptr_t)getminor((dev_t
)arg
);
460 fdc_probe(dev_info_t
*dip
)
467 len
= sizeof (debug
);
468 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
469 DDI_PROP_DONTPASS
, "debug", (caddr_t
)debug
, &len
) ==
471 fcerrlevel
= debug
[0];
472 fcerrmask
= (uint_t
)debug
[1];
475 FCERRPRINT(FDEP_L3
, FDEM_ATTA
, (CE_WARN
, "fdc_probe: dip %p",
478 if (get_ioaddr(dip
, &ioaddr
) != DDI_SUCCESS
)
479 return (DDI_PROBE_FAILURE
);
481 stat
= inb(ioaddr
+ FCR_MSR
);
482 if ((stat
& (MS_RQM
| MS_DIO
| MS_CB
)) != MS_RQM
&&
483 (stat
& ~MS_DIO
) != MS_CB
)
484 return (DDI_PROBE_FAILURE
);
486 return (DDI_PROBE_SUCCESS
);
490 fdc_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
494 int cntlr_num
, ctlr
, unit
;
497 char name
[MAXNAMELEN
];
499 FCERRPRINT(FDEP_L3
, FDEM_ATTA
, (CE_WARN
, "fdc_attach: dip %p",
505 (DDI_DEV_T_ANY
, dip
, 0, "ignore-hardware-nodes", 0)) {
506 len
= sizeof (cntlr_num
);
507 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
,
508 PROP_LEN_AND_VAL_BUF
, DDI_PROP_DONTPASS
, "unit",
509 (caddr_t
)&cntlr_num
, &len
) != DDI_PROP_SUCCESS
) {
510 FCERRPRINT(FDEP_L3
, FDEM_ATTA
, (CE_WARN
,
511 "fdc_attach failed: dip %p", (void*)dip
));
512 return (DDI_FAILURE
);
515 if (get_unit(dip
, &cntlr_num
) != DDI_SUCCESS
)
516 return (DDI_FAILURE
);
519 ctlr
= ddi_get_instance(dip
);
520 if (ddi_soft_state_zalloc(fdc_state_head
, ctlr
) != 0)
521 return (DDI_FAILURE
);
522 fcp
= ddi_get_soft_state(fdc_state_head
, ctlr
);
524 for (unit
= 0, fjp
= (struct fcu_obj
*)(fcp
+1);
525 unit
< NFDUN
; unit
++) {
526 fcp
->c_unit
[unit
] = fjp
++;
530 if (fdc_propinit1(fcp
, cntlr_num
) != DDI_SUCCESS
)
533 /* get iblock cookie to initialize mutex used in the ISR */
534 if (ddi_get_iblock_cookie(dip
, (uint_t
)0, &fcp
->c_iblock
) !=
537 "fdc_attach: cannot get iblock cookie");
540 mutex_init(&fcp
->c_lock
, NULL
, MUTEX_DRIVER
, fcp
->c_iblock
);
543 /* setup interrupt handler */
544 if (ddi_add_intr(dip
, (uint_t
)0, NULL
,
545 (ddi_idevice_cookie_t
*)0, fdc_intr
, (caddr_t
)fcp
) !=
547 cmn_err(CE_WARN
, "fdc: cannot add intr");
553 * acquire the DMA channel
554 * this assumes that the chnl is not shared; else allocate
555 * and free the chnl with each fdc request
557 if (ddi_dmae_alloc(dip
, fcp
->c_dmachan
, DDI_DMA_DONTWAIT
, NULL
)
559 cmn_err(CE_WARN
, "fdc: cannot acquire dma%d",
563 (void) ddi_dmae_getattr(dip
, &fdc_dma_attr
);
564 fdc_dma_attr
.dma_attr_align
= MMU_PAGESIZE
;
566 mutex_init(&fcp
->c_dorlock
, NULL
, MUTEX_DRIVER
, fcp
->c_iblock
);
567 cv_init(&fcp
->c_iocv
, NULL
, CV_DRIVER
, fcp
->c_iblock
);
568 sema_init(&fcp
->c_selsem
, 1, NULL
, SEMA_DRIVER
, NULL
);
570 (void) sprintf(name
, "fdc%d", ctlr
);
571 fcp
->c_intrstat
= kstat_create("fdc", ctlr
, name
,
572 "controller", KSTAT_TYPE_INTR
, 1, KSTAT_FLAG_PERSISTENT
);
573 if (fcp
->c_intrstat
) {
574 kstat_install(fcp
->c_intrstat
);
577 ddi_set_driver_private(dip
, fcp
);
580 * reset the controller
582 sema_p(&fcp
->c_selsem
);
583 mutex_enter(&fcp
->c_lock
);
584 fcp
->c_csb
.csb_xstate
= FXS_RESET
;
585 fcp
->c_flags
|= FCFLG_WAITING
;
588 /* first test for mode == Model 30 */
589 fcp
->c_mode
= (inb(fcp
->c_regbase
+ FCR_SRB
) & 0x1c) ?
590 FDCMODE_AT
: FDCMODE_30
;
592 while (fcp
->c_flags
& FCFLG_WAITING
) {
593 cv_wait(&fcp
->c_iocv
, &fcp
->c_lock
);
595 mutex_exit(&fcp
->c_lock
);
596 sema_v(&fcp
->c_selsem
);
601 return (DDI_SUCCESS
);
605 fcp
= ddi_get_driver_private(dip
);
607 mutex_enter(&fcp
->c_lock
);
608 fcp
->c_suspended
= B_FALSE
;
609 fcp
->c_csb
.csb_xstate
= FXS_RESET
;
610 fcp
->c_flags
|= FCFLG_WAITING
;
613 while (fcp
->c_flags
& FCFLG_WAITING
) {
614 cv_wait(&fcp
->c_iocv
, &fcp
->c_lock
);
616 mutex_exit(&fcp
->c_lock
);
618 /* should be good to go now */
619 sema_v(&fcp
->c_selsem
);
621 return (DDI_SUCCESS
);
625 return (DDI_FAILURE
);
631 ddi_remove_intr(dip
, 0, fcp
->c_iblock
);
632 mutex_destroy(&fcp
->c_lock
);
634 ddi_soft_state_free(fdc_state_head
, cntlr_num
);
635 return (DDI_FAILURE
);
639 fdc_propinit1(struct fdcntlr
*fcp
, int cntlr
)
646 len
= sizeof (value
);
648 if (get_ioaddr(dip
, &value
) != DDI_SUCCESS
)
649 return (DDI_FAILURE
);
651 fcp
->c_regbase
= (ushort_t
)value
;
653 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
654 DDI_PROP_DONTPASS
, "dma-channels", (caddr_t
)&value
, &len
)
655 != DDI_PROP_SUCCESS
) {
657 "fdc_attach: Error, could not find a dma channel");
658 return (DDI_FAILURE
);
660 fcp
->c_dmachan
= (ushort_t
)value
;
661 fcp
->c_number
= cntlr
;
662 return (DDI_SUCCESS
);
666 fdc_propinit2(struct fdcntlr
*fcp
)
674 len
= sizeof (value
);
676 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN_AND_VAL_BUF
,
677 DDI_PROP_DONTPASS
, "chip", (caddr_t
)&value
, &len
)
681 static uchar_t perpindcmd
[2] = {FO_PERP
, 0};
682 static uchar_t versioncmd
= FO_VRSN
;
685 fcp
->c_chip
= i8272A
;
686 (void) fdc_docmd(fcp
, &versioncmd
, 1);
688 * Ignored return. If failed, warning was issued by fdc_docmd.
689 * fdc_results retrieves the controller/drive status
691 if (!fdc_result(fcp
, &result
, 1) && result
== 0x90) {
693 * try a perpendicular_mode cmd to ensure
694 * that we really have an enhanced controller
696 if (fdc_docmd(fcp
, perpindcmd
, 2) ||
697 fdc_docmd(fcp
, configurecmd
, 4))
699 * perpindicular_mode will be rejected by
700 * older controllers; make sure we don't hang.
702 (void) fdc_result(fcp
, &result
, 1);
704 * Ignored return. If failed, warning was
705 * issued by fdc_result.
708 /* enhanced type controller */
710 if ((fcp
->c_chip
= fdc_enhance_probe(fcp
)) == 0)
711 /* default enhanced cntlr */
712 fcp
->c_chip
= i82077
;
714 (void) ddi_prop_update_int(DDI_DEV_T_NONE
, dip
,
715 "chip", fcp
->c_chip
);
717 * Ignoring return value because, for passed arguments, only
718 * DDI_SUCCESS is returned.
721 if (fcp
->c_chip
>= i82077
&& fcp
->c_mode
== FDCMODE_30
&&
722 (inb(fcp
->c_regbase
+ FCR_DIR
) & 0x70) == 0)
723 for (ccr
= 0; ccr
<= (FCC_NOPREC
| FCC_DRATE
); ccr
++) {
725 * run through all the combinations of NOPREC and
726 * datarate selection, and see if they show up in the
729 outb(fcp
->c_regbase
+ FCR_CCR
, ccr
);
731 if ((inb(fcp
->c_regbase
+ FCR_DIR
) &
732 (FCC_NOPREC
| FCC_DRATE
)) != ccr
) {
733 fcp
->c_mode
= FDCMODE_AT
;
738 fcp
->c_mode
= FDCMODE_AT
;
739 outb(fcp
->c_regbase
+ FCR_CCR
, 0);
743 fdc_enhance_probe(struct fdcntlr
*fcp
)
745 static uchar_t nsccmd
= FO_NSC
;
752 * Try to identify the enhanced floppy controller.
753 * This is required so that we can program the DENSEL output to
754 * control 3D mode (1.0 MB, 1.6 MB and 2.0 MB unformatted capacity,
755 * 720 KB, 1.2 MB, and 1.44 MB formatted capacity) 3.5" dual-speed
756 * floppy drives. Refer to bugid 1195155.
759 (void) fdc_docmd(fcp
, &nsccmd
, 1);
761 * Ignored return. If failed, warning was issued by fdc_docmd.
762 * fdc_results retrieves the controller/drive status
764 if (!fdc_result(fcp
, &result
, 1) && result
!= S0_IVCMD
) {
766 * only enhanced National Semi PC8477 core
767 * should respond to this command
769 if ((result
& 0xf0) == 0x70) {
770 /* low 4 bits may change */
771 fcp
->c_flags
|= FCFLG_3DMODE
;
775 "?fdc: unidentified, enhanced, National Semiconductor cntlr %x\n", result
);
777 save
= inb(fcp
->c_regbase
+ FCR_SRA
);
780 /* probe for motherboard version of SMC cntlr */
782 /* try to enable configuration mode */
783 ddic
= ddi_enter_critical();
784 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_ENA5
);
785 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_ENA5
);
786 ddi_exit_critical(ddic
);
788 outb(fcp
->c_regbase
+ FCR_SRA
, 0x0F);
789 if (inb(fcp
->c_regbase
+ FCR_SRB
) != 0x00)
790 /* always expect 0 from config reg F */
792 outb(fcp
->c_regbase
+ FCR_SRA
, 0x0D);
793 if (inb(fcp
->c_regbase
+ FCR_SRB
) != 0x65)
794 /* expect 0x65 from config reg D */
796 outb(fcp
->c_regbase
+ FCR_SRA
, 0x0E);
797 result
= inb(fcp
->c_regbase
+ FCR_SRB
);
798 if (result
!= 0x02) {
799 /* expect revision level 2 from config reg E */
801 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result
);
804 fcp
->c_flags
|= FCFLG_3DMODE
;
806 } while (retcode
== 0);
807 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_DISB
);
809 while (retcode
== 0) {
810 /* probe for adapter version of SMC cntlr */
811 ddic
= ddi_enter_critical();
812 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_ENA6
);
813 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_ENA6
);
814 ddi_exit_critical(ddic
);
816 outb(fcp
->c_regbase
+ FCR_SRA
, 0x0F);
817 if (inb(fcp
->c_regbase
+ FCR_SRB
) != 0x00)
818 /* always expect 0 from config reg F */
820 outb(fcp
->c_regbase
+ FCR_SRA
, 0x0D);
821 if (inb(fcp
->c_regbase
+ FCR_SRB
) != 0x66)
822 /* expect 0x66 from config reg D */
824 outb(fcp
->c_regbase
+ FCR_SRA
, 0x0E);
825 result
= inb(fcp
->c_regbase
+ FCR_SRB
);
826 if (result
!= 0x02) {
827 /* expect revision level 2 from config reg E */
829 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result
);
832 fcp
->c_flags
|= FCFLG_3DMODE
;
835 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_DISB
);
838 outb(fcp
->c_regbase
+ FCR_SRA
, save
);
844 fdc_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
850 FCERRPRINT(FDEP_L3
, FDEM_ATTA
, (CE_WARN
, "fdc_detach: dip %p",
853 fcp
= ddi_get_driver_private(dip
);
857 for (unit
= 0; unit
< NFDUN
; unit
++)
858 if ((fcp
->c_unit
[unit
])->fj_dip
) {
862 kstat_delete(fcp
->c_intrstat
);
863 fcp
->c_intrstat
= NULL
;
864 ddi_remove_intr(fcp
->c_dip
, 0, fcp
->c_iblock
);
865 if (ddi_dmae_release(fcp
->c_dip
, fcp
->c_dmachan
) !=
867 cmn_err(CE_WARN
, "fdc_detach: dma release failed, "
868 "dip %p, dmachan %x",
869 (void*)fcp
->c_dip
, fcp
->c_dmachan
);
870 ddi_prop_remove_all(fcp
->c_dip
);
871 ddi_set_driver_private(fcp
->c_dip
, NULL
);
873 mutex_destroy(&fcp
->c_lock
);
874 mutex_destroy(&fcp
->c_dorlock
);
875 cv_destroy(&fcp
->c_iocv
);
876 sema_destroy(&fcp
->c_selsem
);
877 ddi_soft_state_free(fdc_state_head
, ddi_get_instance(dip
));
882 * For suspend, we just use the semaphore to
883 * keep any child devices from accessing any of our
884 * hardware routines, and then shutdown the hardware.
886 * On resume, we'll reinit the hardware and release the
889 sema_p(&fcp
->c_selsem
);
891 if (ddi_dmae_disable(fcp
->c_dip
, fcp
->c_dmachan
) !=
893 cmn_err(CE_WARN
, "fdc_suspend: dma disable failed, "
894 "dip %p, dmachan %x", (void *)fcp
->c_dip
,
896 /* give it back on failure */
897 sema_v(&fcp
->c_selsem
);
898 return (DDI_FAILURE
);
901 mutex_enter(&fcp
->c_lock
);
902 fcp
->c_suspended
= B_TRUE
;
903 mutex_exit(&fcp
->c_lock
);
917 fdc_abort(struct fcu_obj
*fjp
)
919 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
920 int unit
= fjp
->fj_unit
& 3;
922 FCERRPRINT(FDEP_L3
, FDEM_RESE
, (CE_WARN
, "fdc_abort"));
923 if (fcp
->c_curunit
== unit
) {
924 mutex_enter(&fcp
->c_lock
);
925 if (fcp
->c_flags
& FCFLG_WAITING
) {
927 * this can cause data corruption !
930 fcp
->c_csb
.csb_xstate
= FXS_RESET
;
931 fcp
->c_flags
|= FCFLG_TIMEOUT
;
932 if (ddi_dmae_stop(fcp
->c_dip
, fcp
->c_dmachan
) !=
935 "fdc_detach: dma release failed, "
936 "dip %p, dmachan %x",
937 (void*)fcp
->c_dip
, fcp
->c_dmachan
);
939 mutex_exit(&fcp
->c_lock
);
941 return (DDI_SUCCESS
);
943 return (DDI_FAILURE
);
947 fdc_dkinfo(struct fcu_obj
*fjp
, struct dk_cinfo
*dcp
)
949 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
951 (void) strncpy((char *)&dcp
->dki_cname
, ddi_get_name(fcp
->c_dip
),
953 dcp
->dki_ctype
= DKC_UNKNOWN
; /* no code for generic PC/AT fdc */
954 dcp
->dki_flags
= DKI_FMTTRK
;
955 dcp
->dki_addr
= fcp
->c_regbase
;
957 dcp
->dki_prio
= fcp
->c_intprio
;
958 dcp
->dki_vec
= fcp
->c_intvec
;
959 (void) strncpy((char *)&dcp
->dki_dname
, ddi_driver_name(fjp
->fj_dip
),
961 dcp
->dki_slave
= fjp
->fj_unit
& 3;
962 dcp
->dki_maxtransfer
= maxphys
/ DEV_BSIZE
;
963 return (DDI_SUCCESS
);
967 * on=> non-zero = select, 0 = de-select
970 fdc_select(struct fcu_obj
*fjp
, int funit
, int on
)
972 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
973 int unit
= funit
& 3;
976 /* possess controller */
977 sema_p(&fcp
->c_selsem
);
978 FCERRPRINT(FDEP_L2
, FDEM_DSEL
,
979 (CE_NOTE
, "fdc_select unit %d: on", funit
));
981 if (fcp
->c_curunit
!= unit
|| !(fjp
->fj_flags
& FUNIT_CHAROK
)) {
982 fcp
->c_curunit
= unit
;
983 fjp
->fj_flags
|= FUNIT_CHAROK
;
985 fjp
->fj_chars
->fdc_transfer_rate
,
986 fjp
->fj_drive
->fdd_steprate
, 40))
988 "fdc_select: controller setup rejected "
989 "fdcntrl %p transfer rate %x step rate %x"
990 " head load time 40", (void*)fcp
,
991 fjp
->fj_chars
->fdc_transfer_rate
,
992 fjp
->fj_drive
->fdd_steprate
);
995 mutex_enter(&fcp
->c_dorlock
);
997 /* make sure drive is not selected in case we change speed */
998 fcp
->c_digout
= (fcp
->c_digout
& ~FD_DRSEL
) |
1000 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1002 (void) fdc_motorsm(fjp
, FMI_STARTCMD
,
1003 fjp
->fj_drive
->fdd_motoron
);
1005 * Return value ignored - fdcmotort deals with failure.
1007 if (fdcspdchange(fcp
, fjp
, fjp
->fj_attr
->fda_rotatespd
)) {
1008 /* 3D drive requires 500 ms for speed change */
1009 (void) fdc_motorsm(fjp
, FMI_RSTARTCMD
, 5);
1011 * Return value ignored - fdcmotort deals with failure.
1015 fcp
->c_digout
= (fcp
->c_digout
& ~FD_DRSEL
) | (unit
& FD_DRSEL
);
1016 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1018 mutex_exit(&fcp
->c_dorlock
);
1019 fcp
->c_csb
.csb_drive
= (uchar_t
)unit
;
1021 FCERRPRINT(FDEP_L2
, FDEM_DSEL
,
1022 (CE_NOTE
, "fdc_select unit %d: off", funit
));
1024 mutex_enter(&fcp
->c_dorlock
);
1026 fcp
->c_digout
|= FD_DRSEL
;
1027 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1028 (void) fdc_motorsm(fjp
, FMI_IDLECMD
,
1029 fjp
->fj_drive
->fdd_motoroff
);
1031 * Return value ignored - fdcmotort deals with failure.
1034 mutex_exit(&fcp
->c_dorlock
);
1036 /* give up controller */
1037 sema_v(&fcp
->c_selsem
);
1044 fdgetchng(struct fcu_obj
*fjp
, int funit
)
1046 if (fdcsense_drv(fjp
->fj_fdc
, funit
& 3))
1047 cmn_err(CE_WARN
, "fdgetchng: write protect check failed");
1048 return (fdcsense_chng(fjp
->fj_fdc
, funit
& 3));
1053 fdresetchng(struct fcu_obj
*fjp
, int funit
)
1055 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
1056 int unit
= funit
& 3;
1057 int newcyl
; /* where to seek for reset of DSKCHG */
1059 FCERRPRINT(FDEP_L2
, FDEM_CHEK
, (CE_NOTE
, "fdmediachng unit %d", funit
));
1061 if (fcp
->c_curpcyl
[unit
])
1062 newcyl
= fcp
->c_curpcyl
[unit
] - 1;
1065 return (fdrecalseek(fjp
, funit
, newcyl
, 0));
1073 fdrecalseek(struct fcu_obj
*fjp
, int funit
, int arg
, int execflg
)
1075 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
1077 int unit
= funit
& 3;
1080 FCERRPRINT(FDEP_L2
, FDEM_RECA
, (CE_NOTE
, "fdrecalseek unit %d to %d",
1084 csb
->csb_cmd
[1] = (uchar_t
)unit
;
1085 if (arg
< 0) { /* is recal... */
1086 *csb
->csb_cmd
= FO_RECAL
;
1088 csb
->csb_timer
= 28;
1090 *csb
->csb_cmd
= FO_SEEK
;
1091 csb
->csb_cmd
[2] = (uchar_t
)arg
;
1093 csb
->csb_timer
= 10;
1095 csb
->csb_nrslts
= 2; /* 2 for SENSE INTERRUPTS */
1096 csb
->csb_opflags
= CSB_OFINRPT
;
1097 csb
->csb_maxretry
= skretry
;
1098 csb
->csb_dmahandle
= NULL
;
1099 csb
->csb_handle_bound
= 0;
1100 csb
->csb_dmacookiecnt
= 0;
1101 csb
->csb_dmacurrcookie
= 0;
1102 csb
->csb_dmawincnt
= 0;
1103 csb
->csb_dmacurrwin
= 0;
1105 /* send cmd off to fdc_exec */
1106 if (rval
= fdc_exec(fcp
, 1, execflg
))
1109 if (!(*csb
->csb_rslt
& S0_SEKEND
) ||
1110 (*csb
->csb_rslt
& S0_ICMASK
) ||
1111 ((*csb
->csb_rslt
& S0_ECHK
) && arg
< 0) ||
1115 if (fdcsense_drv(fcp
, unit
))
1116 cmn_err(CE_WARN
, "fdgetchng: write protect check failed");
1123 * fdrw- used only for read/writing sectors into/from kernel buffers.
1126 fdrw(struct fcu_obj
*fjp
, int funit
, int rw
, int cyl
, int head
,
1127 int sector
, caddr_t bufp
, uint_t len
)
1129 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
1131 uint_t dmar_flags
= 0;
1132 int unit
= funit
& 3;
1134 ddi_acc_handle_t mem_handle
= NULL
;
1135 caddr_t aligned_buf
;
1138 FCERRPRINT(FDEP_L1
, FDEM_RW
, (CE_CONT
, "fdrw unit %d\n", funit
));
1142 dmar_flags
= DDI_DMA_READ
;
1143 csb
->csb_opflags
= CSB_OFDMARD
| CSB_OFINRPT
;
1144 *csb
->csb_cmd
= FO_MT
| FO_MFM
| FO_SK
| FO_RDDAT
;
1145 } else { /* write */
1146 dmar_flags
= DDI_DMA_WRITE
;
1147 csb
->csb_opflags
= CSB_OFDMAWT
| CSB_OFINRPT
;
1148 *csb
->csb_cmd
= FO_MT
| FO_MFM
| FO_WRDAT
;
1150 csb
->csb_cmd
[1] = (uchar_t
)(unit
| ((head
& 0x1) << 2));
1151 csb
->csb_cmd
[2] = (uchar_t
)cyl
;
1152 csb
->csb_cmd
[3] = (uchar_t
)head
;
1153 csb
->csb_cmd
[4] = (uchar_t
)sector
;
1154 encode(sector_size
, fjp
->fj_chars
->fdc_sec_size
,
1156 csb
->csb_cmd
[6] = (uchar_t
)max(fjp
->fj_chars
->fdc_secptrack
, sector
);
1157 csb
->csb_cmd
[7] = fjp
->fj_attr
->fda_gapl
;
1158 csb
->csb_cmd
[8] = 0xFF;
1161 csb
->csb_nrslts
= 7;
1162 csb
->csb_timer
= 36;
1164 csb
->csb_maxretry
= 1;
1166 csb
->csb_maxretry
= rwretry
;
1168 csb
->csb_dmahandle
= NULL
;
1169 csb
->csb_handle_bound
= 0;
1170 csb
->csb_dmacookiecnt
= 0;
1171 csb
->csb_dmacurrcookie
= 0;
1172 csb
->csb_dmawincnt
= 0;
1173 csb
->csb_dmacurrwin
= 0;
1174 dmar_flags
|= (DDI_DMA_STREAMING
| DDI_DMA_PARTIAL
);
1176 if (ddi_dma_alloc_handle(fcp
->c_dip
, &fdc_dma_attr
, DDI_DMA_SLEEP
,
1177 0, &csb
->csb_dmahandle
) != DDI_SUCCESS
) {
1183 * allocate a page aligned buffer to dma to/from. This way we can
1184 * ensure the cookie is a whole multiple of granularity and avoids
1185 * any alignment issues.
1187 rval
= ddi_dma_mem_alloc(csb
->csb_dmahandle
, len
, &fdc_accattr
,
1188 DDI_DMA_CONSISTENT
, DDI_DMA_SLEEP
, NULL
, &aligned_buf
,
1189 &real_size
, &mem_handle
);
1190 if (rval
!= DDI_SUCCESS
) {
1195 if (dmar_flags
& DDI_DMA_WRITE
) {
1196 bcopy(bufp
, aligned_buf
, len
);
1199 rval
= ddi_dma_addr_bind_handle(csb
->csb_dmahandle
, NULL
, aligned_buf
,
1200 len
, dmar_flags
, DDI_DMA_SLEEP
, 0, &csb
->csb_dmacookie
,
1201 &csb
->csb_dmacookiecnt
);
1203 if (rval
== DDI_DMA_MAPPED
) {
1204 csb
->csb_dmawincnt
= 1;
1205 csb
->csb_handle_bound
= 1;
1206 } else if (rval
== DDI_DMA_PARTIAL_MAP
) {
1207 csb
->csb_handle_bound
= 1;
1208 if (ddi_dma_numwin(csb
->csb_dmahandle
, &csb
->csb_dmawincnt
) !=
1210 cmn_err(CE_WARN
, "fdrw: dma numwin failed");
1216 "fdrw: dma addr bind handle failed, rval = %d", rval
);
1220 rval
= fdc_exec(fcp
, 1, 1);
1222 if (dmar_flags
& DDI_DMA_READ
) {
1223 bcopy(aligned_buf
, bufp
, len
);
1227 if (csb
->csb_dmahandle
) {
1228 if (csb
->csb_handle_bound
) {
1229 if (ddi_dma_unbind_handle(csb
->csb_dmahandle
) !=
1231 cmn_err(CE_WARN
, "fdrw: "
1232 "dma unbind handle failed");
1233 csb
->csb_handle_bound
= 0;
1235 if (mem_handle
!= NULL
) {
1236 ddi_dma_mem_free(&mem_handle
);
1238 ddi_dma_free_handle(&csb
->csb_dmahandle
);
1239 csb
->csb_dmahandle
= NULL
;
1246 fdtrkformat(struct fcu_obj
*fjp
, int funit
, int cyl
, int head
, int filldata
)
1248 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
1250 int unit
= funit
& 3;
1251 int fmdatlen
, lsector
, lstart
;
1252 int interleave
, numsctr
, offset
, psector
;
1255 ddi_acc_handle_t mem_handle
= NULL
;
1256 caddr_t aligned_buf
;
1259 FCERRPRINT(FDEP_L2
, FDEM_FORM
,
1260 (CE_NOTE
, "fdformattrk unit %d cyl=%d, hd=%d", funit
, cyl
, head
));
1264 csb
->csb_opflags
= CSB_OFDMAWT
| CSB_OFINRPT
;
1266 *csb
->csb_cmd
= FO_FRMT
| FO_MFM
;
1267 csb
->csb_cmd
[1] = (head
<< 2) | unit
;
1268 encode(sector_size
, fjp
->fj_chars
->fdc_sec_size
,
1270 csb
->csb_cmd
[3] = numsctr
= fjp
->fj_chars
->fdc_secptrack
;
1271 csb
->csb_cmd
[4] = fjp
->fj_attr
->fda_gapf
;
1272 csb
->csb_cmd
[5] = (uchar_t
)filldata
;
1274 csb
->csb_npcyl
= (uchar_t
)(cyl
* fjp
->fj_chars
->fdc_steps
);
1276 csb
->csb_dmahandle
= NULL
;
1277 csb
->csb_handle_bound
= 0;
1278 csb
->csb_dmacookiecnt
= 0;
1279 csb
->csb_dmacurrcookie
= 0;
1280 csb
->csb_dmawincnt
= 0;
1281 csb
->csb_dmacurrwin
= 0;
1283 csb
->csb_nrslts
= 7;
1284 csb
->csb_timer
= 32;
1285 csb
->csb_maxretry
= rwretry
;
1288 * alloc space for format track cmd
1291 * NOTE: have to add size of fifo also - for dummy format action
1293 fmdatlen
= 4 * numsctr
;
1295 if (ddi_dma_alloc_handle(fcp
->c_dip
, &fdc_dma_attr
, DDI_DMA_SLEEP
,
1296 0, &csb
->csb_dmahandle
) != DDI_SUCCESS
) {
1302 * allocate a page aligned buffer to dma to/from. This way we can
1303 * ensure the cookie is a whole multiple of granularity and avoids
1304 * any alignment issues.
1306 rval
= ddi_dma_mem_alloc(csb
->csb_dmahandle
, fmdatlen
, &fdc_accattr
,
1307 DDI_DMA_CONSISTENT
, DDI_DMA_SLEEP
, NULL
, &aligned_buf
,
1308 &real_size
, &mem_handle
);
1309 if (rval
!= DDI_SUCCESS
) {
1313 dp
= (uchar_t
*)aligned_buf
;
1315 interleave
= fjp
->fj_attr
->fda_intrlv
;
1316 offset
= (numsctr
+ interleave
- 1) / interleave
;
1317 for (psector
= lstart
= 1;
1318 psector
<= numsctr
; psector
+= interleave
, lstart
++) {
1319 for (lsector
= lstart
; lsector
<= numsctr
; lsector
+= offset
) {
1320 *dp
++ = (uchar_t
)cyl
;
1321 *dp
++ = (uchar_t
)head
;
1322 *dp
++ = (uchar_t
)lsector
;
1323 *dp
++ = csb
->csb_cmd
[2];
1327 rval
= ddi_dma_addr_bind_handle(csb
->csb_dmahandle
, NULL
, aligned_buf
,
1328 fmdatlen
, DDI_DMA_WRITE
| DDI_DMA_STREAMING
| DDI_DMA_PARTIAL
,
1329 DDI_DMA_SLEEP
, 0, &csb
->csb_dmacookie
, &csb
->csb_dmacookiecnt
);
1331 if (rval
== DDI_DMA_MAPPED
) {
1332 csb
->csb_dmawincnt
= 1;
1333 csb
->csb_handle_bound
= 1;
1334 } else if (rval
== DDI_DMA_PARTIAL_MAP
) {
1335 csb
->csb_handle_bound
= 1;
1336 if (ddi_dma_numwin(csb
->csb_dmahandle
, &csb
->csb_dmawincnt
) !=
1338 cmn_err(CE_WARN
, "fdtrkformat: dma numwin failed");
1344 "fdtrkformat: dma buf bind handle failed, rval = %d",
1350 rval
= fdc_exec(fcp
, 1, 1);
1352 if (csb
->csb_dmahandle
) {
1353 if (csb
->csb_handle_bound
) {
1354 if (ddi_dma_unbind_handle(csb
->csb_dmahandle
) !=
1356 cmn_err(CE_WARN
, "fdtrkformat: "
1357 "dma unbind handle failed");
1358 csb
->csb_handle_bound
= 0;
1360 if (mem_handle
!= NULL
) {
1361 ddi_dma_mem_free(&mem_handle
);
1363 ddi_dma_free_handle(&csb
->csb_dmahandle
);
1364 csb
->csb_dmahandle
= NULL
;
1370 fdrawioctl(struct fcu_obj
*fjp
, int funit
, caddr_t arg
)
1372 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
1373 struct fd_raw
*fdrp
= (struct fd_raw
*)arg
;
1375 uint_t dmar_flags
= 0;
1381 ddi_acc_handle_t mem_handle
= NULL
;
1382 caddr_t aligned_buf
;
1385 _NOTE(ARGUNUSED(funit
));
1387 FCERRPRINT(FDEP_L2
, FDEM_RAWI
,
1388 (CE_NOTE
, "fdrawioctl: cmd[0]=0x%x", fdrp
->fdr_cmd
[0]));
1392 /* copy cmd bytes into csb */
1393 for (i
= 0; i
<= fdrp
->fdr_cnum
; i
++)
1394 csb
->csb_cmd
[i
] = fdrp
->fdr_cmd
[i
];
1395 csb
->csb_ncmds
= (uchar_t
)fdrp
->fdr_cnum
;
1397 csb
->csb_maxretry
= 0; /* let the application deal with errors */
1398 csb
->csb_opflags
= CSB_OFRAWIOCTL
;
1399 csb
->csb_nrslts
= 0;
1400 csb
->csb_timer
= 50;
1402 switch (fdrp
->fdr_cmd
[0] & 0x0f) {
1408 csb
->csb_opflags
|= CSB_OFINRPT
;
1412 csb
->csb_npcyl
= *(uchar_t
*)(fdrp
->fdr_addr
) *
1413 fjp
->fj_chars
->fdc_steps
;
1417 csb
->csb_opflags
|= CSB_OFDMAWT
| CSB_OFRESLT
| CSB_OFINRPT
;
1418 csb
->csb_nrslts
= 7;
1419 if (fdrp
->fdr_nbytes
== 0)
1421 dmar_flags
= DDI_DMA_WRITE
;
1427 csb
->csb_opflags
|= CSB_OFDMARD
| CSB_OFRESLT
| CSB_OFINRPT
;
1428 csb
->csb_nrslts
= 7;
1429 dmar_flags
= DDI_DMA_READ
;
1433 csb
->csb_opflags
|= CSB_OFRESLT
| CSB_OFINRPT
;
1434 csb
->csb_nrslts
= 7;
1439 csb
->csb_nrslts
= 1;
1445 csb
->csb_nrslts
= 2;
1457 csb
->csb_dmahandle
= NULL
;
1458 csb
->csb_handle_bound
= 0;
1459 csb
->csb_dmacookiecnt
= 0;
1460 csb
->csb_dmacurrcookie
= 0;
1461 csb
->csb_dmawincnt
= 0;
1462 csb
->csb_dmacurrwin
= 0;
1464 if (csb
->csb_opflags
& (CSB_OFDMARD
| CSB_OFDMAWT
)) {
1465 if (ddi_dma_alloc_handle(fcp
->c_dip
, &fdc_dma_attr
,
1466 DDI_DMA_SLEEP
, 0, &csb
->csb_dmahandle
) != DDI_SUCCESS
) {
1472 * allocate a page aligned buffer to dma to/from. This way we
1473 * can ensure the cookie is a whole multiple of granularity and
1474 * avoids any alignment issues.
1476 rval
= ddi_dma_mem_alloc(csb
->csb_dmahandle
,
1477 (uint_t
)fdrp
->fdr_nbytes
, &fdc_accattr
, DDI_DMA_CONSISTENT
,
1478 DDI_DMA_SLEEP
, NULL
, &aligned_buf
, &real_size
, &mem_handle
);
1479 if (rval
!= DDI_SUCCESS
) {
1484 if (dmar_flags
& DDI_DMA_WRITE
) {
1485 bcopy(fdrp
->fdr_addr
, aligned_buf
,
1486 (uint_t
)fdrp
->fdr_nbytes
);
1489 dmar_flags
|= (DDI_DMA_STREAMING
| DDI_DMA_PARTIAL
);
1490 rval
= ddi_dma_addr_bind_handle(csb
->csb_dmahandle
, NULL
,
1491 aligned_buf
, (uint_t
)fdrp
->fdr_nbytes
, dmar_flags
,
1492 DDI_DMA_SLEEP
, 0, &csb
->csb_dmacookie
,
1493 &csb
->csb_dmacookiecnt
);
1495 if (rval
== DDI_DMA_MAPPED
) {
1496 csb
->csb_dmawincnt
= 1;
1497 csb
->csb_handle_bound
= 1;
1498 } else if (rval
== DDI_DMA_PARTIAL_MAP
) {
1499 csb
->csb_handle_bound
= 1;
1500 if (ddi_dma_numwin(csb
->csb_dmahandle
,
1501 &csb
->csb_dmawincnt
) != DDI_SUCCESS
) {
1503 "fdrawioctl: dma numwin failed");
1508 cmn_err(CE_WARN
, "fdrawioctl: "
1509 "dma buf bind handle failed, rval = %d", rval
);
1515 FCERRPRINT(FDEP_L1
, FDEM_RAWI
,
1516 (CE_CONT
, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb
->csb_cmd
[0],
1517 csb
->csb_cmd
[1], csb
->csb_cmd
[2], csb
->csb_cmd
[3],
1518 csb
->csb_cmd
[4], csb
->csb_cmd
[5], csb
->csb_cmd
[6],
1519 csb
->csb_cmd
[7], csb
->csb_cmd
[8], csb
->csb_cmd
[9]));
1520 FCERRPRINT(FDEP_L1
, FDEM_RAWI
,
1521 (CE_CONT
, "nbytes: %x, opflags: %x, addr: %p, len: %x\n",
1522 csb
->csb_ncmds
, csb
->csb_opflags
, (void *)fdrp
->fdr_addr
,
1526 * Note that we ignore any error returns from fdexec.
1527 * This is the way the driver has been, and it may be
1528 * that the raw ioctl senders simply don't want to
1529 * see any errors returned in this fashion.
1533 * VP/ix sense drive ioctl call checks for the error return.
1536 rval_exec
= fdc_exec(fcp
, sleep
, change
);
1538 if (dmar_flags
& DDI_DMA_READ
) {
1539 bcopy(aligned_buf
, fdrp
->fdr_addr
, (uint_t
)fdrp
->fdr_nbytes
);
1542 FCERRPRINT(FDEP_L1
, FDEM_RAWI
,
1543 (CE_CONT
, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb
->csb_rslt
[0],
1544 csb
->csb_rslt
[1], csb
->csb_rslt
[2], csb
->csb_rslt
[3],
1545 csb
->csb_rslt
[4], csb
->csb_rslt
[5], csb
->csb_rslt
[6],
1546 csb
->csb_rslt
[7], csb
->csb_rslt
[8], csb
->csb_rslt
[9]));
1548 /* copy results into fdr */
1549 for (i
= 0; i
<= (int)csb
->csb_nrslts
; i
++)
1550 fdrp
->fdr_result
[i
] = csb
->csb_rslt
[i
];
1551 /* fdrp->fdr_nbytes = fdc->c_csb.csb_rlen; return resid */
1554 if (csb
->csb_dmahandle
) {
1555 if (csb
->csb_handle_bound
) {
1556 if (ddi_dma_unbind_handle(csb
->csb_dmahandle
) !=
1558 cmn_err(CE_WARN
, "fdrawioctl: "
1559 "dma unbind handle failed");
1560 csb
->csb_handle_bound
= 0;
1562 if (mem_handle
!= NULL
) {
1563 ddi_dma_mem_free(&mem_handle
);
1565 ddi_dma_free_handle(&csb
->csb_dmahandle
);
1566 csb
->csb_dmahandle
= NULL
;
1568 if ((fdrp
->fdr_cmd
[0] & 0x0f) == FO_SDRV
) {
1575 encode(xlate_tbl_t
*tablep
, int val
, uchar_t
*rcode
)
1578 if (tablep
->value
>= val
) {
1579 *rcode
= tablep
->code
;
1582 } while ((++tablep
)->value
);
1583 *rcode
= tablep
->code
;
1584 cmn_err(CE_WARN
, "fdc encode failed, table %p val %x code %x",
1585 (void *)tablep
, val
, (uint_t
)*rcode
);
1589 decode(xlate_tbl_t
*tablep
, int kode
, int *rvalue
)
1592 if (tablep
->code
== kode
) {
1593 *rvalue
= tablep
->value
;
1596 } while ((++tablep
)->value
);
1601 * quiesce(9E) entry point.
1603 * This function is called when the system is single-threaded at high
1604 * PIL with preemption disabled. Therefore, this function must not be
1607 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
1608 * DDI_FAILURE indicates an error condition and should almost never happen.
1611 fdc_quiesce(dev_info_t
*dip
)
1613 struct fdcntlr
*fcp
;
1614 int ctlr
= ddi_get_instance(dip
);
1617 fcp
= ddi_get_soft_state(fdc_state_head
, ctlr
);
1620 return (DDI_FAILURE
);
1623 * If no FD units are attached, there is no need to quiesce.
1625 for (unit
= 0; unit
< NFDUN
; unit
++) {
1626 struct fcu_obj
*fjp
= fcp
->c_unit
[unit
];
1627 if (fjp
->fj_flags
& FUNIT_DRVATCH
) {
1633 return (DDI_SUCCESS
);
1635 (void) ddi_dmae_disable(fcp
->c_dip
, fcp
->c_dmachan
);
1637 fcp
->c_digout
= (fcp
->c_digout
& (FD_DMTREN
| FD_DRSEL
)) | FD_ENABLE
;
1638 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1640 fcp
->c_digout
|= FD_RSETZ
;
1641 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1643 if (fcp
->c_chip
>= i82077
) {
1645 uchar_t
*oplistp
= configurecmd
;
1647 int ntries
= FDC_RQM_RETRY
;
1649 if ((inb(fcp
->c_regbase
+ FCR_MSR
) &
1650 (MS_RQM
|MS_DIO
)) == MS_RQM
)
1658 outb(fcp
->c_regbase
+ FCR_DATA
, *oplistp
++);
1659 drv_usecwait(16); /* See comment in fdc_result() */
1663 return (DDI_SUCCESS
);
1667 fdcquiesce(struct fdcntlr
*fcp
)
1671 FCERRPRINT(FDEP_L2
, FDEM_RESE
, (CE_NOTE
, "fdcquiesce fcp %p",
1674 ASSERT(MUTEX_HELD(&fcp
->c_lock
));
1675 mutex_enter(&fcp
->c_dorlock
);
1677 if (ddi_dmae_stop(fcp
->c_dip
, fcp
->c_dmachan
) != DDI_SUCCESS
)
1678 cmn_err(CE_WARN
, "fdcquiesce: dmae stop failed, "
1679 "dip %p, dmachan %x",
1680 (void*)fcp
->c_dip
, fcp
->c_dmachan
);
1682 fcp
->c_digout
= (fcp
->c_digout
& (FD_DMTREN
| FD_DRSEL
)) | FD_ENABLE
;
1683 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1685 fcp
->c_digout
|= FD_RSETZ
;
1686 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1688 mutex_exit(&fcp
->c_dorlock
);
1691 fcp
->fdstats
.reset
++;
1692 fcp
->c_curunit
= -1;
1693 for (unit
= 0; unit
< NFDUN
; unit
++)
1694 fcp
->c_curpcyl
[unit
] = -1;
1696 if (fcp
->c_chip
>= i82077
) {
1697 (void) fdc_docmd(fcp
, configurecmd
, 4);
1699 * Ignored return. If failed, warning was issued by fdc_docmd.
1705 fdcreadid(struct fdcntlr
*fcp
, struct fdcsb
*csb
)
1707 static uchar_t readidcmd
[2] = {FO_RDID
| FO_MFM
, 0};
1709 readidcmd
[1] = csb
->csb_cmd
[1];
1710 (void) fdc_docmd(fcp
, readidcmd
, 2);
1714 fdcseek(struct fdcntlr
*fcp
, int unit
, int cyl
)
1716 static uchar_t seekabscmd
[3] = {FO_SEEK
, 0, 0};
1718 FCERRPRINT(FDEP_L0
, FDEM_RECA
, (CE_CONT
, "fdcseek unit %d to cyl %d\n",
1720 seekabscmd
[1] = (uchar_t
)unit
;
1721 seekabscmd
[2] = (uchar_t
)cyl
;
1722 return (fdc_docmd(fcp
, seekabscmd
, 3));
1726 * Returns status of disk change line of selected drive.
1727 * = 0 means diskette is present
1728 * != 0 means diskette was removed and current state is unknown
1731 fdcsense_chng(struct fdcntlr
*fcp
, int unit
)
1735 FCERRPRINT(FDEP_L0
, FDEM_SCHG
,
1736 (CE_CONT
, "fdcsense_chng unit %d\n", unit
));
1737 digital_input
= inb(fcp
->c_regbase
+ FCR_DIR
);
1738 if (fcp
->c_mode
== FDCMODE_30
)
1739 digital_input
^= FDI_DKCHG
;
1740 return (digital_input
& FDI_DKCHG
);
1744 fdcsense_drv(struct fdcntlr
*fcp
, int unit
)
1746 static uchar_t sensedrvcmd
[2] = {FO_SDRV
, 0};
1750 sensedrvcmd
[1] = (uchar_t
)unit
;
1751 (void) fdc_docmd(fcp
, sensedrvcmd
, 2);
1753 * Ignored return. If failed, warning was issued by fdc_docmd.
1754 * fdc_results retrieves the controller/drive status
1756 if (rval
= fdc_result(fcp
, &senser
, 1))
1758 if (senser
& S3_WPROT
)
1759 fcp
->c_unit
[unit
]->fj_flags
|= FUNIT_WPROT
;
1761 fcp
->c_unit
[unit
]->fj_flags
&= ~FUNIT_WPROT
;
1767 fdcsense_int(struct fdcntlr
*fcp
, int *unitp
, int *cylp
)
1772 (void) fdc_docmd(fcp
, &senseintcmd
, 1);
1774 * Ignored return. If failed, warning was issued by fdc_docmd.
1775 * fdc_results retrieves the controller/drive status
1778 if (!(rval
= fdc_result(fcp
, senser
, 2))) {
1779 if ((*senser
& (S0_IVCMD
| S0_SEKEND
| S0_ECHK
)) != S0_SEKEND
)
1782 *unitp
= *senser
& 3;
1790 fdcspecify(struct fdcntlr
*fcp
, int xferrate
, int steprate
, int hlt
)
1792 static uchar_t perpindcmd
[2] = {FO_PERP
, 0};
1793 static uchar_t specifycmd
[3] = {FO_SPEC
, 0, 0};
1795 encode(drate_mfm
, xferrate
, &fcp
->c_config
);
1796 outb(fcp
->c_regbase
+ FCR_CCR
, fcp
->c_config
);
1798 if (fcp
->c_chip
>= i82077
) {
1800 * Use old style perpendicular mode command of 82077.
1802 if (xferrate
== 1000) {
1803 /* Set GAP and WGATE */
1805 /* double step rate because xlate table is for 500Kb */
1810 (void) fdc_docmd(fcp
, perpindcmd
, 2);
1812 * Ignored return. If failed, warning was issued by fdc_docmd.
1815 encode(step_rate
, steprate
, &fcp
->c_hutsrt
);
1816 specifycmd
[1] = fcp
->c_hutsrt
|= 0x0F; /* use max head unload time */
1817 hlt
= (hlt
>= 256) ? 0 : (hlt
>> 1); /* encode head load time */
1818 specifycmd
[2] = fcp
->c_hlt
= hlt
<< 1; /* make room for DMA bit */
1819 return (fdc_docmd(fcp
, specifycmd
, 3));
1823 fdcspdchange(struct fdcntlr
*fcp
, struct fcu_obj
*fjp
, int rpm
)
1827 uchar_t deselect
= 0;
1829 uchar_t enable_code
;
1832 if (((fcp
->c_flags
& FCFLG_DSOUT
) == 0 && rpm
<= fjp
->fj_rotspd
) ||
1833 ((fcp
->c_flags
& FCFLG_DSOUT
) && (fjp
->fj_flags
& FUNIT_3DMODE
) &&
1834 rpm
> fjp
->fj_rotspd
)) {
1838 FCERRPRINT(FDEP_L1
, FDEM_SCHG
,
1839 (CE_CONT
, "fdcspdchange: %d rpm\n", rpm
));
1840 ASSERT(MUTEX_HELD(&fcp
->c_dorlock
));
1842 switch (fcp
->c_chip
) {
1850 uchar_t nscmodecmd
[5] = {FO_MODE
, 0x02, 0x00, 0xC8, 0x00};
1852 if (rpm
> fjp
->fj_rotspd
) {
1853 nscmodecmd
[3] ^= 0xC0;
1854 retcode
= (fcp
->c_flags
^ FCFLG_DSOUT
) ||
1855 (fjp
->fj_flags
^ FUNIT_3DMODE
);
1856 fcp
->c_flags
|= FCFLG_DSOUT
;
1857 fjp
->fj_flags
|= FUNIT_3DMODE
;
1859 /* program DENSEL to default output */
1860 fcp
->c_flags
&= ~FCFLG_DSOUT
;
1861 retcode
= fjp
->fj_flags
& FUNIT_3DMODE
;
1862 fjp
->fj_flags
&= ~FUNIT_3DMODE
;
1864 if (retcode
&& (fcp
->c_digout
& FD_DRSEL
) == fcp
->c_curunit
) {
1865 /* de-select drive while changing speed */
1866 deselect
= fcp
->c_digout
^ FD_DRSEL
;
1867 outb(fcp
->c_regbase
+ FCR_DOR
, deselect
);
1870 (void) fdc_docmd(fcp
, nscmodecmd
, 5);
1872 * Ignored return. If failed, warning was issued by fdc_docmd.
1878 enable_code
= FSA_ENA5
;
1882 enable_code
= FSA_ENA6
;
1884 if (rpm
> fjp
->fj_rotspd
) {
1885 /* force DENSEL output to active LOW */
1887 retcode
= (fcp
->c_flags
^ FCFLG_DSOUT
) ||
1888 (fjp
->fj_flags
^ FUNIT_3DMODE
);
1889 fcp
->c_flags
|= FCFLG_DSOUT
;
1890 fjp
->fj_flags
|= FUNIT_3DMODE
;
1892 /* program DENSEL to default output */
1894 fcp
->c_flags
&= ~FCFLG_DSOUT
;
1895 retcode
= fjp
->fj_flags
& FUNIT_3DMODE
;
1896 fjp
->fj_flags
&= ~FUNIT_3DMODE
;
1898 if (retcode
&& (fcp
->c_digout
& FD_DRSEL
) == fcp
->c_curunit
) {
1899 /* de-select drive while changing speed */
1900 deselect
= fcp
->c_digout
^ FD_DRSEL
;
1901 outb(fcp
->c_regbase
+ FCR_DOR
, deselect
);
1903 save
= inb(fcp
->c_regbase
+ FCR_SRA
);
1905 /* enter configuration mode */
1906 ddic
= ddi_enter_critical();
1907 outb(fcp
->c_regbase
+ FCR_SRA
, enable_code
);
1908 outb(fcp
->c_regbase
+ FCR_SRA
, enable_code
);
1909 ddi_exit_critical(ddic
);
1911 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_CR5
);
1912 enable_code
= inb(fcp
->c_regbase
+ FCR_SRB
) & FSB_DSDEF
;
1913 /* update DENSEL mode bits */
1914 outb(fcp
->c_regbase
+ FCR_SRB
, enable_code
| ds_code
);
1916 /* exit configuration mode */
1917 outb(fcp
->c_regbase
+ FCR_SRA
, FSA_DISB
);
1919 outb(fcp
->c_regbase
+ FCR_SRA
, save
);
1923 /* reselect drive */
1924 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1929 fdc_motorsm(struct fcu_obj
*fjp
, int input
, int timeval
)
1931 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
1932 int unit
= fjp
->fj_unit
& 3;
1937 ASSERT(MUTEX_HELD(&fcp
->c_dorlock
));
1938 old_mstate
= fcp
->c_mtrstate
[unit
];
1939 encode(motor_onbits
, unit
, &motorbit
);
1942 case FMI_TIMER
: /* timer expired */
1943 fcp
->c_motort
[unit
] = 0;
1944 switch (old_mstate
) {
1947 fcp
->c_mtrstate
[unit
] = FMS_ON
;
1950 fcp
->c_motort
[unit
] = timeout(fdmotort
, (void *)fjp
,
1951 drv_usectohz(1000000));
1952 fcp
->c_mtrstate
[unit
] = FMS_IDLE
;
1955 fcp
->c_digout
&= ~motorbit
;
1956 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1957 fcp
->c_mtrstate
[unit
] = FMS_OFF
;
1958 fjp
->fj_flags
&= ~FUNIT_3DMODE
;
1970 case FMI_STARTCMD
: /* start command */
1971 switch (old_mstate
) {
1973 fcp
->c_mtrstate
[unit
] = 86;
1974 mutex_exit(&fcp
->c_dorlock
);
1975 (void) untimeout(fcp
->c_motort
[unit
]);
1976 mutex_enter(&fcp
->c_dorlock
);
1977 fcp
->c_motort
[unit
] = 0;
1978 fcp
->c_mtrstate
[unit
] = FMS_ON
;
1981 fcp
->c_digout
|= motorbit
;
1982 outb(fcp
->c_regbase
+ FCR_DOR
, fcp
->c_digout
);
1984 /* start motor_spinup_timer */
1985 ASSERT(timeval
> 0);
1986 fcp
->c_motort
[unit
] = timeout(fdmotort
, (void *)fjp
,
1987 drv_usectohz(100000 * timeval
));
1990 fcp
->c_mtrstate
[unit
] = FMS_START
;
1997 case FMI_RSTARTCMD
: /* restart command */
1998 if (fcp
->c_motort
[unit
] != 0) {
1999 fcp
->c_mtrstate
[unit
] = 86;
2000 mutex_exit(&fcp
->c_dorlock
);
2001 (void) untimeout(fcp
->c_motort
[unit
]);
2002 mutex_enter(&fcp
->c_dorlock
);
2004 ASSERT(timeval
> 0);
2005 fcp
->c_motort
[unit
] = timeout(fdmotort
, (void *)fjp
,
2006 drv_usectohz(100000 * timeval
));
2007 fcp
->c_mtrstate
[unit
] = FMS_START
;
2010 case FMI_DELAYCMD
: /* delay command */
2011 if (fcp
->c_motort
[unit
] == 0)
2012 fcp
->c_motort
[unit
] = timeout(fdmotort
, (void *)fjp
,
2013 drv_usectohz(15000));
2014 fcp
->c_mtrstate
[unit
] = FMS_DELAY
;
2017 case FMI_IDLECMD
: /* idle command */
2018 switch (old_mstate
) {
2020 fcp
->c_mtrstate
[unit
] = 86;
2021 mutex_exit(&fcp
->c_dorlock
);
2022 (void) untimeout(fcp
->c_motort
[unit
]);
2023 mutex_enter(&fcp
->c_dorlock
);
2026 ASSERT(timeval
> 0);
2027 fcp
->c_motort
[unit
] = timeout(fdmotort
, (void *)fjp
,
2028 drv_usectohz(100000 * timeval
));
2029 fcp
->c_mtrstate
[unit
] = FMS_IDLE
;
2032 fcp
->c_mtrstate
[unit
] = FMS_KILLST
;
2043 FCERRPRINT(FDEP_L4
, FDEM_EXEC
, (CE_WARN
,
2044 "fdc_motorsm: unit %d bad input %d or bad state %d",
2045 (int)fjp
->fj_unit
, input
, old_mstate
));
2048 "fdc_motorsm: unit %d bad input %d or bad state %d",
2049 (int)fjp
->fj_unit
, input
, old_mstate
);
2050 fcp
->c_mtrstate
[unit
] = FMS_OFF
;
2051 if (fcp
->c_motort
[unit
] != 0) {
2052 mutex_exit(&fcp
->c_dorlock
);
2053 (void) untimeout(fcp
->c_motort
[unit
]);
2054 mutex_enter(&fcp
->c_dorlock
);
2055 fcp
->c_motort
[unit
] = 0;
2059 FCERRPRINT(FDEP_L0
, FDEM_EXEC
,
2060 (CE_CONT
, "fdc_motorsm unit %d: input %d, %d -> %d\n",
2061 (int)fjp
->fj_unit
, input
, old_mstate
,
2062 fcp
->c_mtrstate
[unit
]));
2068 * is called from timeout() when a motor timer has expired.
2073 struct fcu_obj
*fjp
= (struct fcu_obj
*)arg
;
2074 struct fdcntlr
*fcp
= fjp
->fj_fdc
;
2075 struct fdcsb
*csb
= &fcp
->c_csb
;
2076 int unit
= fjp
->fj_unit
& 3;
2080 mutex_enter(&fcp
->c_dorlock
);
2081 mval
= fdc_motorsm(fjp
, FMI_TIMER
, 0);
2082 mutex_exit(&fcp
->c_dorlock
);
2086 mutex_enter(&fcp
->c_lock
);
2088 if ((fcp
->c_flags
& FCFLG_WAITING
) &&
2089 fcp
->c_mtrstate
[unit
] == FMS_ON
&&
2090 (csb
->csb_xstate
== FXS_MTRON
|| csb
->csb_xstate
== FXS_HDST
||
2091 csb
->csb_xstate
== FXS_DKCHGX
))
2092 newxstate
= fdc_statemach(fcp
);
2093 if (newxstate
== -1) {
2094 FCERRPRINT(FDEP_L3
, FDEM_EXEC
,
2096 "fdc_motort unit %d: motor ready but bad xstate",
2097 (int)fjp
->fj_unit
));
2098 fcp
->c_csb
.csb_cmdstat
= EIO
;
2100 if (newxstate
== -1 || newxstate
== FXS_END
) {
2101 fcp
->c_flags
^= FCFLG_WAITING
;
2102 cv_signal(&fcp
->c_iocv
);
2104 mutex_exit(&fcp
->c_lock
);
2108 * DMA interrupt service routine
2110 * Called by EISA dma interrupt service routine when buffer chaining
2115 fdc_dmae_isr(struct fdcntlr
*fcp
)
2117 struct fdcsb
*csb
= &fcp
->c_csb
;
2121 if (csb
->csb_dmahandle
&& !csb
->csb_cmdstat
) {
2122 if (++csb
->csb_dmacurrcookie
< csb
->csb_dmacookiecnt
) {
2123 ddi_dma_nextcookie(csb
->csb_dmahandle
,
2124 &csb
->csb_dmacookie
);
2125 return (&csb
->csb_dmacookie
);
2126 } else if (++csb
->csb_dmacurrwin
< csb
->csb_dmawincnt
) {
2127 if (ddi_dma_getwin(csb
->csb_dmahandle
,
2128 csb
->csb_dmacurrwin
, &off
, &len
,
2129 &csb
->csb_dmacookie
,
2130 &csb
->csb_dmacookiecnt
) != DDI_SUCCESS
) {
2133 csb
->csb_dmacurrcookie
= 0;
2134 return (&csb
->csb_dmacookie
);
2137 cmn_err(CE_WARN
, "fdc: unsolicited DMA interrupt");
2145 * ENXIO - diskette not in drive
2146 * ETIMEDOUT - for immediate operations that timed out
2147 * EBUSY - if stupid chip is locked busy???
2148 * ENOEXEC - for timeout during sending cmds to chip
2150 * to sleep: set sleep
2151 * to check for disk changed: set change
2154 fdc_exec(struct fdcntlr
*fcp
, int sleep
, int change
)
2156 struct ddi_dmae_req dmaereq
;
2157 struct fcu_obj
*fjp
;
2163 mutex_enter(&fcp
->c_lock
);
2164 FCERRPRINT(FDEP_L0
, FDEM_EXEC
,
2165 (CE_CONT
, "fdc_exec: sleep %x change %x\n", sleep
, change
));
2167 unit
= csb
->csb_drive
;
2168 fjp
= fcp
->c_unit
[unit
];
2170 if (csb
->csb_opflags
& CSB_OFINRPT
) {
2171 if (*csb
->csb_cmd
== FO_RECAL
)
2173 else if ((*csb
->csb_cmd
& ~FO_MFM
) != FO_FRMT
)
2175 csb
->csb_cmd
[2] * fjp
->fj_chars
->fdc_steps
;
2176 csb
->csb_xstate
= FXS_START
;
2178 csb
->csb_xstate
= FXS_DOIT
;
2179 csb
->csb_retrys
= 0;
2180 csb
->csb_ourtrys
= 0;
2182 if (csb
->csb_dmahandle
) {
2183 /* ensure that entire format xfer is in one cookie */
2185 * The change from ddi_dma_buf/addr_setup() to
2186 * ddi_dma_buf/addr_bind_handle() has already loaded
2187 * the first DMA window and cookie.
2189 if ((*csb
->csb_cmd
& ~FO_MFM
) == FO_FRMT
&&
2190 (4 * csb
->csb_cmd
[3]) != csb
->csb_dmacookie
.dmac_size
) {
2191 mutex_exit(&fcp
->c_lock
);
2197 if (fcp
->c_curunit
!= unit
|| !(fjp
->fj_flags
& FUNIT_CHAROK
)) {
2198 fcp
->c_curunit
= unit
;
2199 fjp
->fj_flags
|= FUNIT_CHAROK
;
2200 if (fjp
->fj_chars
->fdc_transfer_rate
== 417) {
2201 /* XXX hack for fdformat */
2202 /* fjp->fj_chars->fdc_transfer_rate == 500; */
2203 fjp
->fj_attr
->fda_rotatespd
= 360;
2205 if (fdcspecify(fcp
, fjp
->fj_chars
->fdc_transfer_rate
,
2206 fjp
->fj_drive
->fdd_steprate
, 40))
2208 "fdc_select: controller setup rejected "
2209 "fdcntrl %p transfer rate %x step rate %x "
2210 "head load time 40", (void*)fcp
,
2211 fjp
->fj_chars
->fdc_transfer_rate
,
2212 fjp
->fj_drive
->fdd_steprate
);
2214 mutex_enter(&fcp
->c_dorlock
);
2215 if (fdcspdchange(fcp
, fjp
, fjp
->fj_attr
->fda_rotatespd
)) {
2216 /* 3D drive requires 500 ms for speed change */
2217 (void) fdc_motorsm(fjp
, FMI_RSTARTCMD
, 5);
2219 * Return value ignored - fdcmotort deals with failure.
2222 mutex_exit(&fcp
->c_dorlock
);
2226 * If checking for disk_change is enabled
2227 * (i.e. not seeking in fdresetchng),
2228 * we sample the DSKCHG line to see if the diskette has wandered away.
2230 if (change
&& fdcsense_chng(fcp
, unit
)) {
2231 FCERRPRINT(FDEP_L3
, FDEM_EXEC
,
2232 (CE_WARN
, "diskette %d changed!!!", csb
->csb_drive
));
2233 fcp
->c_unit
[unit
]->fj_flags
|= FUNIT_CHANGED
;
2235 * If the diskette is still gone... so are we, adios!
2237 if (fdcheckdisk(fcp
, unit
)) {
2238 mutex_exit(&fcp
->c_lock
);
2240 /* VP/ix expects an EBUSY return here */
2241 if (*csb
->csb_cmd
== FO_SDRV
) {
2247 * delay to ensure that new diskette is up to speed
2249 mutex_enter(&fcp
->c_dorlock
);
2250 (void) fdc_motorsm(fjp
, FMI_RSTARTCMD
,
2251 fjp
->fj_drive
->fdd_motoron
);
2253 * Return value ignored - fdcmotort deals with failure.
2255 mutex_exit(&fcp
->c_dorlock
);
2259 * gather some statistics
2261 switch (csb
->csb_cmd
[0] & 0x1f) {
2269 fcp
->fdstats
.recal
++;
2272 fcp
->fdstats
.form
++;
2275 fcp
->fdstats
.other
++;
2279 bzero(csb
->csb_rslt
, 10);
2280 csb
->csb_cmdstat
= 0;
2282 if (csb
->csb_dmahandle
) {
2283 bzero(&dmaereq
, sizeof (struct ddi_dmae_req
));
2284 dmaereq
.der_command
= (csb
->csb_opflags
& CSB_OFDMAWT
) ?
2285 DMAE_CMD_WRITE
: DMAE_CMD_READ
;
2287 * setup for dma buffer chaining regardless of bus capability
2289 dmaereq
.der_bufprocess
= DMAE_BUF_CHAIN
;
2290 dmaereq
.proc
= fdc_dmae_isr
;
2291 dmaereq
.procparms
= (void *)fcp
;
2292 if (ddi_dmae_prog(fcp
->c_dip
, &dmaereq
, &csb
->csb_dmacookie
,
2293 fcp
->c_dmachan
) != DDI_SUCCESS
)
2294 cmn_err(CE_WARN
, "fdc_exec: dmae prog failed, "
2295 "dip %p, dmachan %x",
2296 (void*)fcp
->c_dip
, fcp
->c_dmachan
);
2299 if ((fdc_statemach(fcp
) == FXS_DOWT
) && !sleep
) {
2301 * If the operation has no results - then just return
2303 if (!csb
->csb_nrslts
) {
2304 mutex_exit(&fcp
->c_lock
);
2308 * this operation has no interrupt and an immediate result
2309 * so wait for the results and stuff them into the csb
2311 if (fdc_statemach(fcp
) == -1) {
2312 mutex_exit(&fcp
->c_lock
);
2316 fcp
->c_flags
|= FCFLG_WAITING
;
2318 * wait for completion interrupt
2320 while (fcp
->c_flags
& FCFLG_WAITING
) {
2321 cv_wait(&fcp
->c_iocv
, &fcp
->c_lock
);
2326 * See if there was an error detected, if so, fdrecover()
2327 * will check it out and say what to do.
2329 * Don't do this, though, if this was the Sense Drive Status
2330 * or the Dump Registers command.
2332 if (csb
->csb_cmdstat
&& *csb
->csb_cmd
!= FO_SDRV
) {
2333 /* if it can restarted OK, then do so, else return error */
2334 if (fdrecover(fcp
)) {
2335 mutex_exit(&fcp
->c_lock
);
2338 /* ASSUMES that cmd is still intact in csb */
2339 if (csb
->csb_xstate
== FXS_END
)
2340 csb
->csb_xstate
= FXS_START
;
2341 if (fdc_dma_attr
.dma_attr_sgllen
> 1 && csb
->csb_dmahandle
) {
2343 * restarted read/write operation requires
2344 * first DMA cookie of current window
2346 if (ddi_dma_getwin(csb
->csb_dmahandle
,
2347 csb
->csb_dmacurrwin
, &off
, &len
,
2348 &csb
->csb_dmacookie
,
2349 &csb
->csb_dmacookiecnt
) != DDI_SUCCESS
) {
2351 mutex_exit(&fcp
->c_lock
);
2354 csb
->csb_dmacurrcookie
= 0;
2358 /* things went ok */
2359 mutex_exit(&fcp
->c_lock
);
2365 * called by fdc_exec to check if the disk is still there - do a seek
2366 * then see if DSKCHG line went away; if so, diskette is in; else
2370 fdcheckdisk(struct fdcntlr
*fcp
, int unit
)
2372 struct fdcsb
*csb
= &fcp
->c_csb
;
2373 int newcyl
; /* where to seek for reset of DSKCHG */
2375 enum fxstate save_xstate
;
2376 uchar_t save_cmd
, save_cd1
, save_npcyl
;
2378 ASSERT(MUTEX_HELD(&fcp
->c_lock
));
2379 FCERRPRINT(FDEP_L1
, FDEM_CHEK
,
2380 (CE_CONT
, "fdcheckdisk unit %d\n", unit
));
2382 if (fcp
->c_curpcyl
[unit
])
2383 newcyl
= fcp
->c_curpcyl
[unit
] - 1;
2387 save_cmd
= *csb
->csb_cmd
;
2388 save_cd1
= csb
->csb_cmd
[1];
2389 save_npcyl
= csb
->csb_npcyl
;
2390 save_xstate
= csb
->csb_xstate
;
2392 *csb
->csb_cmd
= FO_SEEK
;
2393 csb
->csb_cmd
[1] = (uchar_t
)unit
;
2394 csb
->csb_npcyl
= (uchar_t
)newcyl
;
2395 fcp
->c_flags
|= FCFLG_WAITING
;
2397 if (fcp
->c_mtrstate
[unit
] != FMS_ON
&& fcp
->c_motort
[unit
] != 0)
2399 * wait for motor to get up to speed,
2400 * and let motor_timer issue seek cmd
2402 csb
->csb_xstate
= FXS_DKCHGX
;
2405 * motor is up to speed; issue seek cmd now
2407 csb
->csb_xstate
= FXS_SEEK
;
2408 if (rval
= fdcseek(fcp
, unit
, newcyl
)) {
2410 * any recal/seek errors are too serious to attend to
2412 FCERRPRINT(FDEP_L3
, FDEM_CHEK
,
2413 (CE_WARN
, "fdcheckdisk err %d", rval
));
2414 fcp
->c_flags
^= FCFLG_WAITING
;
2418 * wait for completion interrupt
2419 * XXX This should be backed up with a watchdog timer!
2421 while (fcp
->c_flags
& FCFLG_WAITING
) {
2422 cv_wait(&fcp
->c_iocv
, &fcp
->c_lock
);
2426 * if disk change still asserted, no diskette in drive!
2428 if (rval
= fdcsense_chng(fcp
, unit
)) {
2429 FCERRPRINT(FDEP_L3
, FDEM_CHEK
,
2430 (CE_WARN
, "fdcheckdisk no disk %d", unit
));
2433 *csb
->csb_cmd
= save_cmd
;
2434 csb
->csb_cmd
[1] = save_cd1
;
2435 csb
->csb_npcyl
= save_npcyl
;
2436 csb
->csb_xstate
= save_xstate
;
2441 fdrecover(struct fdcntlr
*fcp
)
2443 struct fcu_obj
*fjp
;
2444 struct fdcsb
*csb
= &fcp
->c_csb
;
2449 FCERRPRINT(FDEP_L2
, FDEM_RECO
,
2450 (CE_NOTE
, "fdrecover unit %d", csb
->csb_drive
));
2452 unit
= csb
->csb_drive
;
2453 fjp
= fcp
->c_unit
[unit
];
2454 if (fcp
->c_flags
& FCFLG_TIMEOUT
) {
2455 fcp
->c_flags
^= FCFLG_TIMEOUT
;
2456 csb
->csb_rslt
[1] |= 0x08;
2457 FCERRPRINT(FDEP_L3
, FDEM_RECO
,
2458 (CE_WARN
, "fd unit %d: %s timed out", csb
->csb_drive
,
2459 fdcmds
[*csb
->csb_cmd
& 0x1f].cmdname
));
2462 if (csb
->csb_status
& S0_SEKEND
)
2463 fcp
->c_curpcyl
[unit
] = -1;
2465 switch (csb
->csb_oldxs
) {
2466 case FXS_RCAL
: /* recalibrate */
2467 case FXS_SEEK
: /* seek */
2468 case FXS_RESET
: /* cntlr reset */
2469 FCERRPRINT(FDEP_L4
, FDEM_RECO
, (CE_WARN
,
2470 "fd unit %d: %s error: st0=0x%x pcn=%d", csb
->csb_drive
,
2471 fdcmds
[*csb
->csb_cmd
& 0x1f].cmdname
,
2472 *csb
->csb_rslt
, csb
->csb_rslt
[1]));
2473 if (csb
->csb_retrys
++ < skretry
&&
2474 !(csb
->csb_opflags
& CSB_OFRAWIOCTL
))
2478 case FXS_RDID
: /* read ID */
2479 if (!(csb
->csb_status
& S0_SEKEND
))
2480 csb
->csb_xstate
= FXS_HDST
;
2482 case FXS_DOIT
: /* original operation */
2483 case FXS_DOWT
: /* waiting on operation */
2484 if (csb
->csb_opflags
& (CSB_OFDMARD
| CSB_OFDMAWT
)) {
2485 if (ddi_dmae_getcnt(fcp
->c_dip
, fcp
->c_dmachan
,
2486 &residual
) != DDI_SUCCESS
)
2488 "fdc_recover: dmae getcnt failed, "
2489 "dip %p dmachan %x residual %x",
2490 (void*)fcp
->c_dip
, fcp
->c_dmachan
,
2492 FCERRPRINT(FDEP_L2
, FDEM_RECO
,
2494 "fd unit %d: %s error: "
2495 "dma count=0x%lx residual=0x%x",
2497 fdcmds
[*csb
->csb_cmd
& 0x1f].cmdname
,
2498 csb
->csb_dmacookie
.dmac_size
, residual
));
2500 if (csb
->csb_rslt
[1] == S1_OVRUN
)
2502 * handle retries of over/underrun
2503 * with a secondary retry counter
2505 if (++csb
->csb_ourtrys
<= OURUN_TRIES
) {
2506 FCERRPRINT(FDEP_L2
, FDEM_RECO
,
2508 "fd unit %d: %s error: over/under-run",
2510 fdcmds
[*csb
->csb_cmd
& 0x1f].cmdname
));
2514 * count 1 set of over/underruns
2515 * as 1 primary retry effort
2517 csb
->csb_ourtrys
= 0;
2519 if ((fjp
->fj_flags
& (FUNIT_UNLABELED
| FUNIT_LABELOK
)) &&
2520 !(csb
->csb_opflags
& CSB_OFRAWIOCTL
)) {
2522 * device is open so keep trying and
2523 * gather statistics on errors
2525 if (csb
->csb_rslt
[1] & S1_CRCER
)
2527 if (csb
->csb_rslt
[1] & S1_OVRUN
)
2529 if (csb
->csb_rslt
[1] & (S1_NODATA
| S1_MADMK
))
2530 fcp
->fdstats
.bfmt
++;
2531 if (csb
->csb_rslt
[1] & 0x08)
2535 * if we have not run out of retries, return 0
2537 if (csb
->csb_retrys
++ < csb
->csb_maxretry
&&
2538 (*csb
->csb_cmd
& ~FO_MFM
) != FO_FRMT
) {
2539 if (csb
->csb_opflags
&
2540 (CSB_OFDMARD
| CSB_OFDMAWT
)) {
2541 FCERRPRINT(FDEP_L4
, FDEM_RECO
,
2543 "fd unit %d: %s error: "
2544 "st0=0x%x st1=0x%x st2=0x%x",
2546 fdcmds
[*csb
->csb_cmd
&
2548 *csb
->csb_rslt
, csb
->csb_rslt
[1],
2551 if ((csb
->csb_retrys
& 1) &&
2552 csb
->csb_xstate
== FXS_END
)
2553 csb
->csb_xstate
= FXS_DOIT
;
2554 else if (csb
->csb_retrys
== 3)
2555 csb
->csb_xstate
= FXS_RESTART
;
2558 if (csb
->csb_rslt
[1] & S1_CRCER
)
2559 failure
= "crc error";
2560 else if (csb
->csb_rslt
[1] & S1_OVRUN
)
2561 failure
= "over/under-run";
2562 else if (csb
->csb_rslt
[1] & (S1_NODATA
| S1_MADMK
))
2563 failure
= "bad format";
2564 else if (csb
->csb_rslt
[1] & 0x08)
2565 failure
= "timeout";
2568 cmn_err(CE_NOTE
, "!fd unit %d: %s %s (%x %x %x)",
2570 fdcmds
[*csb
->csb_cmd
& 0x1f].cmdname
, failure
,
2571 *csb
->csb_rslt
, csb
->csb_rslt
[1], csb
->csb_rslt
[2]);
2573 FCERRPRINT(FDEP_L2
, FDEM_RECO
,
2574 (CE_NOTE
, "fd unit %d: %s failed (%x %x %x)",
2576 fdcmds
[*csb
->csb_cmd
& 0x1f].cmdname
,
2577 *csb
->csb_rslt
, csb
->csb_rslt
[1],
2583 FCERRPRINT(FDEP_L4
, FDEM_RECO
, (CE_WARN
,
2584 "fd unit %d: %s failed: st0=0x%x st1=0x%x st2=0x%x",
2585 csb
->csb_drive
, fdcmds
[*csb
->csb_cmd
& 0x1f].cmdname
,
2586 *csb
->csb_rslt
, csb
->csb_rslt
[1], csb
->csb_rslt
[2]));
2593 /* Autovector Interrupt Entry Point */
2595 fdc_intr(caddr_t arg
)
2597 struct fdcntlr
*fcp
= (struct fdcntlr
*)arg
;
2604 int rval
= DDI_DMA_DONE
;
2610 mutex_enter(&fcp
->c_lock
);
2611 if (fcp
->c_suspended
) {
2612 mutex_exit(&fcp
->c_lock
);
2613 return (DDI_INTR_UNCLAIMED
);
2617 * Wait for the RQM bit to be set, or until we've tested it
2618 * a bunch of times (which may imply this isn't our interrupt).
2620 state
= inb(fcp
->c_regbase
+ FCR_MSR
);
2621 pendstate
= state
& (MS_RQM
| MS_DIO
| MS_CB
);
2622 while (((pendstate
& MS_RQM
) == 0) && (maxspin
-- > 0)) {
2623 /* Small pause in between reading the status port */
2625 /* Reread the status port */
2626 state
= inb(fcp
->c_regbase
+ FCR_MSR
);
2627 pendstate
= state
& (MS_RQM
| MS_DIO
| MS_CB
);
2629 FCERRPRINT(FDEP_L0
, FDEM_INTR
,
2630 (CE_CONT
, "fdc_intr unit %d: xstate=%d MSR=0x%x\n",
2631 csb
->csb_drive
, csb
->csb_xstate
, state
));
2634 * If there is an operation outstanding AND the controller is ready
2635 * to receive a command or send us the result of a command (OR if the
2636 * controller is ready to accept a new command), AND if
2637 * someone has been waiting for a command to finish AND (if no unit
2638 * is BUSY OR if the unit that we're waiting for is BUSY (i.e. it's in
2639 * the middle of a seek/recalibrate)) then this interrupt is for us.
2641 if ((pendstate
== (MS_RQM
| MS_DIO
| MS_CB
) || pendstate
== MS_RQM
) &&
2642 (fcp
->c_flags
& FCFLG_WAITING
) &&
2643 (!(state
& 0x0f) || ((1 << csb
->csb_drive
) & state
))) {
2645 * Remove one of the conditions for entering this code.
2646 * The state_machine will release the c_lock if it
2649 fcp
->c_flags
^= FCFLG_WAITING
;
2651 if ((newstate
= fdc_statemach(fcp
)) == -1) {
2652 /* restore waiting flag */
2653 fcp
->c_flags
|= FCFLG_WAITING
;
2654 mutex_exit(&fcp
->c_lock
);
2655 return (DDI_INTR_CLAIMED
);
2658 if (fcp
->c_intrstat
)
2659 KIOIP
->intrs
[KSTAT_INTR_HARD
]++;
2660 if (newstate
== FXS_END
) {
2662 if (csb
->csb_dmahandle
&& !csb
->csb_cmdstat
&&
2664 * read/write operation may have multiple DMA
2665 * cookies: process next one
2667 ((csb
->csb_dmacurrcookie
<
2668 (csb
->csb_dmacookiecnt
- 1)) ||
2669 (csb
->csb_dmacurrwin
) < (csb
->csb_dmawincnt
- 1))) {
2671 * read/write operation requires another
2672 * DMA cookie: process next one
2675 if (++csb
->csb_dmacurrcookie
<
2676 csb
->csb_dmacookiecnt
) {
2677 ddi_dma_nextcookie(csb
->csb_dmahandle
,
2678 &csb
->csb_dmacookie
);
2679 } else if (++csb
->csb_dmacurrwin
<
2680 csb
->csb_dmawincnt
) {
2681 if (ddi_dma_getwin(csb
->csb_dmahandle
,
2682 csb
->csb_dmacurrwin
, &off
, &blklen
,
2683 &csb
->csb_dmacookie
,
2684 &csb
->csb_dmacookiecnt
) !=
2688 "dma getwin failed");
2690 csb
->csb_dmacurrcookie
= 0;
2693 if (ddi_dmae_prog(fcp
->c_dip
, NULL
,
2694 &csb
->csb_dmacookie
, fcp
->c_dmachan
) !=
2697 "fdc_intr: dmae prog failed, "
2698 "dip %p dmachannel %x",
2703 * status of last operation has disk
2704 * address for continuation
2706 csb
->csb_cmd
[2] = csb
->csb_rslt
[3];
2707 csb
->csb_cmd
[3] = csb
->csb_rslt
[4];
2708 csb
->csb_cmd
[4] = csb
->csb_rslt
[5];
2709 csb
->csb_cmd
[1] = (csb
->csb_cmd
[1] & ~0x04) |
2710 (csb
->csb_cmd
[3] << 2);
2712 csb
->csb_xstate
= FXS_START
;
2713 (void) fdc_statemach(fcp
);
2715 * Ignored return. If failed, warning already
2716 * posted. Returned state irrelevant.
2718 /* restore waiting flag */
2719 fcp
->c_flags
|= FCFLG_WAITING
;
2722 if (rval
!= DDI_DMA_DONE
)
2723 csb
->csb_cmdstat
= EIO
;
2725 * somebody's waiting for completion of fdcntlr/csb,
2728 cv_signal(&fcp
->c_iocv
);
2731 /* restore waiting flag */
2732 fcp
->c_flags
|= FCFLG_WAITING
;
2734 mutex_exit(&fcp
->c_lock
);
2735 return (DDI_INTR_CLAIMED
);
2738 if (state
& MS_RQM
) {
2739 (void) fdcsense_int(fcp
, &drive
, NULL
);
2741 * Ignored return - senser state already saved
2743 FCERRPRINT(FDEP_L4
, FDEM_INTR
,
2744 (CE_WARN
, "fdc_intr unit %d: nobody sleeping 0x%x",
2747 FCERRPRINT(FDEP_L4
, FDEM_INTR
,
2748 (CE_WARN
, "fdc_intr: nobody sleeping on %d 0x%x",
2749 csb
->csb_drive
, state
));
2752 * This should probably be protected, but, what the
2753 * heck...the cost isn't worth the accuracy for this
2756 if (fcp
->c_intrstat
)
2757 KIOIP
->intrs
[KSTAT_INTR_SPURIOUS
]++;
2758 mutex_exit(&fcp
->c_lock
);
2759 return (DDI_INTR_UNCLAIMED
);
2764 * is called from timeout() when a floppy operation timer has expired.
2769 struct fdcntlr
*fcp
= (struct fdcntlr
*)arg
;
2772 mutex_enter(&fcp
->c_lock
);
2774 if (fcp
->c_timeid
== 0) {
2776 * fdc_intr got here first, ergo, no timeout condition..
2778 mutex_exit(&fcp
->c_lock
);
2782 if (fcp
->c_flags
& FCFLG_WAITING
) {
2783 if (ddi_dmae_stop(fcp
->c_dip
, fcp
->c_dmachan
) != DDI_SUCCESS
)
2784 cmn_err(CE_WARN
, "fdwatch: dmae stop failed, "
2785 "dip %p, dmachan %x",
2786 (void*)fcp
->c_dip
, fcp
->c_dmachan
);
2788 FCERRPRINT(FDEP_L3
, FDEM_WATC
,
2789 (CE_WARN
, "fdcwatch unit %d: xstate = %d",
2790 csb
->csb_drive
, csb
->csb_xstate
));
2793 if (inb(fcp
->c_regbase
+ FCR_MSR
) != MS_RQM
) {
2795 * cntlr is still busy, so reset it
2797 csb
->csb_xstate
= FXS_KILL
;
2798 (void) fdc_statemach(fcp
);
2800 * Ignored return. If failed, warning already
2801 * posted. Returned state irrelevant.
2804 csb
->csb_xstate
= FXS_END
;
2806 fcp
->c_flags
^= FCFLG_WAITING
;
2807 cv_signal(&fcp
->c_iocv
);
2809 csb
->csb_cmdstat
= EIO
;
2810 fcp
->c_flags
|= FCFLG_TIMEOUT
;
2812 FCERRPRINT(FDEP_L4
, FDEM_INTR
,
2813 (CE_WARN
, "fdcwatch: not sleeping for unit %d",
2814 fcp
->c_csb
.csb_drive
));
2816 if (fcp
->c_intrstat
)
2817 KIOIP
->intrs
[KSTAT_INTR_WATCHDOG
]++;
2818 mutex_exit(&fcp
->c_lock
);
2823 fdc_statemach(struct fdcntlr
*fcp
)
2825 struct fcu_obj
*fjp
;
2826 struct fdcsb
*csb
= &fcp
->c_csb
;
2831 ASSERT(MUTEX_HELD(&fcp
->c_lock
));
2833 unit
= csb
->csb_drive
;
2834 fjp
= fcp
->c_unit
[unit
];
2836 csb
->csb_oldxs
= csb
->csb_xstate
;
2837 switch (csb
->csb_xstate
) {
2839 case FXS_START
: /* start of operation */
2840 ASSERT(fcp
->c_timeid
== 0);
2841 time
= drv_usectohz(100000 * (unsigned int)csb
->csb_timer
);
2843 time
= drv_usectohz(2000000);
2844 fcp
->c_timeid
= timeout(fdwatch
, (void *)fcp
, time
);
2846 if (fcp
->c_mtrstate
[unit
] == FMS_START
) {
2848 * wait for motor to get up to speed
2850 csb
->csb_xstate
= FXS_MTRON
;
2855 case FXS_MTRON
: /* motor is at speed */
2856 if (fcp
->c_mtrstate
[unit
] != FMS_ON
) {
2857 /* how did we get here ?? */
2858 cmn_err(CE_WARN
, "fdc: selected but motor off");
2861 if (fcp
->c_curpcyl
[unit
] != -1 && *csb
->csb_cmd
!= FO_RECAL
)
2863 recalcmd
[1] = (uchar_t
)unit
;
2864 if (fdc_docmd(fcp
, recalcmd
, 2) == -1) {
2865 /* cntlr did not accept command bytes */
2867 csb
->csb_cmdstat
= EIO
;
2868 csb
->csb_xstate
= FXS_RESET
;
2871 fcp
->c_sekdir
[unit
] = 0;
2872 csb
->csb_xstate
= FXS_RCAL
;
2875 case FXS_RCAL
: /* forced recalibrate is complete */
2876 #if 0 /* #ifdef _VPIX */
2877 /* WARNING: this code breaks SPARC compatibility */
2878 if (csb
->csb_opflags
& CSB_OFRAWIOCTL
&&
2879 *csb
->csb_cmd
== FO_RECAL
) {
2880 fcp
->c_curpcyl
[unit
] = 0;
2881 csb
->csb_status
= 0;
2885 (void) fdc_docmd(fcp
, &senseintcmd
, 1);
2887 * Ignored return. If failed, warning was issued by fdc_docmd.
2888 * fdc_results retrieves the controller/drive status
2890 (void) fdc_result(fcp
, csb
->csb_rslt
, 2);
2892 * Ignored return. If failed, warning was issued by fdc_result.
2893 * Actual results checked below
2895 if ((csb
->csb_status
= ((*csb
->csb_rslt
^ S0_SEKEND
) &
2896 (S0_ICMASK
| S0_SEKEND
| S0_ECHK
| S0_NOTRDY
))) != 0) {
2897 FCERRPRINT(FDEP_L3
, FDEM_EXEC
,
2898 (CE_WARN
, "fdc_statemach unit %d: recal result %x",
2899 csb
->csb_drive
, *csb
->csb_rslt
));
2901 csb
->csb_cmdstat
= EIO
;
2902 csb
->csb_xstate
= FXS_RESET
;
2905 if (unit
!= (*csb
->csb_rslt
& 3) || csb
->csb_rslt
[1]) {
2906 csb
->csb_status
= S0_SEKEND
;
2909 fcp
->c_curpcyl
[unit
] = csb
->csb_rslt
[1];
2910 if (*csb
->csb_cmd
== FO_RECAL
)
2913 if (*csb
->csb_cmd
!= FO_SEEK
&&
2914 csb
->csb_npcyl
== fcp
->c_curpcyl
[unit
])
2916 fcp
->c_sekdir
[unit
] = csb
->csb_npcyl
- fcp
->c_curpcyl
[unit
];
2919 case FXS_DKCHGX
: /* reset Disk-Change latch */
2920 (void) fdcseek(fcp
, csb
->csb_cmd
[1], csb
->csb_npcyl
);
2922 * Ignored return. If command rejected, warnig already posted
2925 csb
->csb_xstate
= FXS_SEEK
;
2928 case FXS_RESTART
: /* special restart of read/write operation */
2929 ASSERT(fcp
->c_timeid
== 0);
2930 time
= drv_usectohz(100000 * csb
->csb_timer
);
2932 time
= drv_usectohz(2000000);
2933 fcp
->c_timeid
= timeout(fdwatch
, (void *)fcp
, time
);
2935 if (fcp
->c_mtrstate
[unit
] != FMS_ON
) {
2936 cmn_err(CE_WARN
, "fdc: selected but motor off");
2939 if ((csb
->csb_npcyl
== 0 || fcp
->c_sekdir
[unit
] >= 0) &&
2940 (int)csb
->csb_cmd
[2] < (fjp
->fj_chars
->fdc_ncyl
- 1))
2941 backoff
= csb
->csb_npcyl
+ 1;
2943 backoff
= csb
->csb_npcyl
- 1;
2944 (void) fdcseek(fcp
, csb
->csb_cmd
[1], backoff
);
2946 * Ignored return. If command rejected, warnig already posted
2949 csb
->csb_xstate
= FXS_RESEEK
;
2952 case FXS_RESEEK
: /* seek to backoff-cyl complete */
2953 (void) fdc_docmd(fcp
, &senseintcmd
, 1);
2955 * Ignored return. If failed, warning was issued by fdc_docmd.
2956 * fdc_results retrieves the controller/drive status
2958 (void) fdc_result(fcp
, csb
->csb_rslt
, 2);
2960 * Ignored return. If failed, warning was issued by fdc_result.
2961 * Actual results checked below
2963 if ((csb
->csb_status
= ((*csb
->csb_rslt
^ S0_SEKEND
) &
2964 (S0_ICMASK
| S0_SEKEND
| S0_ECHK
| S0_NOTRDY
))) != 0)
2966 (void) fdcseek(fcp
, csb
->csb_cmd
[1], csb
->csb_npcyl
);
2968 * Ignored return. If command rejected, warnig already posted
2971 csb
->csb_xstate
= FXS_SEEK
;
2974 case FXS_SEEK
: /* seek complete */
2975 #if 0 /* #ifdef _VPIX */
2976 /* WARNING: this code breaks SPARC compatibility and */
2977 /* rawioctls in fdformat */
2978 if (csb
->csb_opflags
& CSB_OFRAWIOCTL
) {
2979 fcp
->c_curpcyl
[unit
] = csb
->csb_npcyl
;
2980 csb
->csb_status
= 0;
2984 (void) fdc_docmd(fcp
, &senseintcmd
, 1);
2986 * Ignored return. If failed, warning was issued by fdc_docmd.
2987 * fdc_results retrieves the controller/drive status
2989 (void) fdc_result(fcp
, csb
->csb_rslt
, 2);
2991 * Ignored return. If failed, warning was issued by fdc_result.
2992 * Actual results checked below
2994 if ((csb
->csb_status
= ((*csb
->csb_rslt
^ S0_SEKEND
) &
2995 (S0_ICMASK
| S0_SEKEND
| S0_ECHK
| S0_NOTRDY
))) != 0)
2997 if (unit
!= (*csb
->csb_rslt
& 3) ||
2998 csb
->csb_rslt
[1] != csb
->csb_npcyl
) {
2999 csb
->csb_status
= S0_SEKEND
;
3002 fcp
->c_curpcyl
[unit
] = csb
->csb_rslt
[1];
3003 /* use motor_timer to delay for head settle */
3004 mutex_enter(&fcp
->c_dorlock
);
3005 (void) fdc_motorsm(fjp
, FMI_DELAYCMD
,
3006 fjp
->fj_drive
->fdd_headsettle
/ 1000);
3008 * Return value ignored - fdcmotort deals with failure.
3010 mutex_exit(&fcp
->c_dorlock
);
3011 csb
->csb_xstate
= FXS_HDST
;
3014 case FXS_HDST
: /* head settle */
3015 if (*csb
->csb_cmd
== FO_SEEK
)
3017 if ((*csb
->csb_cmd
& ~FO_MFM
) == FO_FRMT
)
3019 fdcreadid(fcp
, csb
);
3020 csb
->csb_xstate
= FXS_RDID
;
3023 case FXS_RDID
: /* read ID complete */
3024 (void) fdc_result(fcp
, csb
->csb_rslt
, 7);
3026 * Ignored return. If failed, warning was issued by fdc_result.
3027 * Actual results checked below
3029 if ((csb
->csb_status
= (*csb
->csb_rslt
&
3030 (S0_ICMASK
| S0_ECHK
| S0_NOTRDY
))) != 0)
3032 if (csb
->csb_cmd
[2] != csb
->csb_rslt
[3]) {
3033 /* at wrong logical cylinder */
3034 csb
->csb_status
= S0_SEKEND
;
3039 case FXS_DOIT
: /* do original operation */
3040 ASSERT(fcp
->c_timeid
== 0);
3041 time
= drv_usectohz(100000 * csb
->csb_timer
);
3043 time
= drv_usectohz(2000000);
3044 fcp
->c_timeid
= timeout(fdwatch
, (void *)fcp
, time
);
3046 if (fdc_docmd(fcp
, csb
->csb_cmd
, csb
->csb_ncmds
) == -1) {
3047 /* cntlr did not accept command bytes */
3049 csb
->csb_xstate
= FXS_RESET
;
3050 csb
->csb_cmdstat
= EIO
;
3053 csb
->csb_xstate
= FXS_DOWT
;
3056 case FXS_DOWT
: /* operation complete */
3057 (void) fdc_result(fcp
, csb
->csb_rslt
, csb
->csb_nrslts
);
3059 * Ignored return. If failed, warning was issued by fdc_result.
3060 * Actual results checked below.
3062 if (*csb
->csb_cmd
== FO_SDRV
) {
3064 (*csb
->csb_rslt
^ (S3_DRRDY
| S3_2SIDE
)) &
3065 ~(S3_HEAD
| S3_UNIT
);
3067 csb
->csb_status
= *csb
->csb_rslt
&
3068 (S0_ICMASK
| S0_ECHK
| S0_NOTRDY
);
3071 if (csb
->csb_status
)
3072 csb
->csb_cmdstat
= EIO
;
3073 csb
->csb_xstate
= FXS_END
;
3075 /* remove watchdog timer if armed and not already triggered */
3076 if (fcp
->c_timeid
!= 0) {
3077 timeout_id_t timeid
;
3078 timeid
= fcp
->c_timeid
;
3080 mutex_exit(&fcp
->c_lock
);
3081 (void) untimeout(timeid
);
3082 mutex_enter(&fcp
->c_lock
);
3086 case FXS_KILL
: /* quiesce cntlr by reset */
3088 fcp
->c_timeid
= timeout(fdwatch
, (void *)fcp
,
3089 drv_usectohz(2000000));
3090 csb
->csb_xstate
= FXS_RESET
;
3093 case FXS_RESET
: /* int from reset */
3094 for (unit
= 0; unit
< NFDUN
; unit
++) {
3095 (void) fdcsense_int(fcp
, NULL
, NULL
);
3096 fcp
->c_curpcyl
[unit
] = -1;
3098 if (fcp
->c_timeid
!= 0) {
3099 timeout_id_t timeid
;
3100 timeid
= fcp
->c_timeid
;
3102 mutex_exit(&fcp
->c_lock
);
3103 (void) untimeout(timeid
);
3104 mutex_enter(&fcp
->c_lock
);
3106 csb
->csb_xstate
= FXS_END
;
3110 cmn_err(CE_WARN
, "fdc: statemach, unknown state");
3113 FCERRPRINT(FDEP_L1
, FDEM_EXEC
,
3114 (CE_CONT
, "fdc_statemach unit %d: %d -> %d\n",
3115 csb
->csb_drive
, csb
->csb_oldxs
, csb
->csb_xstate
));
3116 return (csb
->csb_xstate
);
3121 * routine to program a command into the floppy disk controller.
3124 fdc_docmd(struct fdcntlr
*fcp
, uchar_t
*oplistp
, uchar_t count
)
3129 FCERRPRINT(FDEP_L0
, FDEM_EXEC
,
3130 (CE_CONT
, "fdc_docmd: %x %x %x %x %x %x %x %x %x\n",
3131 oplistp
[0], oplistp
[1], oplistp
[2], oplistp
[3], oplistp
[4],
3132 oplistp
[5], oplistp
[6], oplistp
[7], oplistp
[8]));
3135 ntries
= FDC_RQM_RETRY
;
3137 if ((inb(fcp
->c_regbase
+ FCR_MSR
) & (MS_RQM
|MS_DIO
))
3144 FCERRPRINT(FDEP_L3
, FDEM_EXEC
,
3145 (CE_WARN
, "fdc_docmd: ctlr not ready"));
3148 outb(fcp
->c_regbase
+ FCR_DATA
, *oplistp
++);
3149 drv_usecwait(16); /* See comment in fdc_result() */
3156 * Routine to return controller/drive status information.
3157 * The diskette-controller data-register is read the
3158 * requested number of times and the results are placed in
3159 * consecutive memory locations starting at the passed
3163 fdc_result(struct fdcntlr
*fcp
, uchar_t
*rsltp
, uchar_t rcount
)
3166 uchar_t
*abresultp
= rsltp
;
3170 ntries
= 10 * FDC_RQM_RETRY
;
3173 if ((inb(fcp
->c_regbase
+ FCR_MSR
) &
3174 (MS_RQM
| MS_DIO
)) == (MS_RQM
| MS_DIO
))
3180 FCERRPRINT(FDEP_L3
, FDEM_EXEC
,
3181 (CE_WARN
, "fdc_result: ctlr not ready"));
3184 *rsltp
++ = inb(fcp
->c_regbase
+ FCR_DATA
);
3187 * The PRM suggests waiting for 14.5 us.
3188 * Adding a bit more to cover the case of bad calibration
3189 * of drv_usecwait().
3192 ntries
= FDC_RQM_RETRY
;
3194 while ((inb(fcp
->c_regbase
+ FCR_MSR
) & MS_CB
) && laxative
--) {
3195 FCERRPRINT(FDEP_L3
, FDEM_EXEC
,
3196 (CE_WARN
, "fdc_result: ctlr still busy"));
3198 * try to complete Result phase by purging
3199 * result bytes queued for reading
3201 *abresultp
= S0_IVCMD
;
3203 stat
= inb(fcp
->c_regbase
+ FCR_MSR
) &
3205 if (stat
== MS_RQM
) {
3207 * Result phase is complete
3208 * but did we get the results corresponding to
3209 * the command we think we executed?
3213 if (stat
== (MS_RQM
| MS_DIO
))
3218 if (!ntries
|| !laxative
) {
3219 FCERRPRINT(FDEP_L3
, FDEM_EXEC
,
3221 "fdc_result: ctlr still busy and not ready"));
3224 (void) inb(fcp
->c_regbase
+ FCR_DATA
);
3226 drv_usecwait(16); /* See comment above */
3227 ntries
= FDC_RQM_RETRY
;
3233 * Function: get_unit()
3235 * Assumptions: ioaddr is either 0x3f0 or 0x370
3238 get_unit(dev_info_t
*dip
, int *cntrl_num
)
3242 if (get_ioaddr(dip
, &ioaddr
) != DDI_SUCCESS
)
3243 return (DDI_FAILURE
);
3255 return (DDI_FAILURE
);
3257 return (DDI_SUCCESS
);
3261 get_ioaddr(dev_info_t
*dip
, int *ioaddr
)
3263 int reglen
, nregs
, i
;
3264 int status
= DDI_FAILURE
;
3271 if (ddi_getlongprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
3272 "reg", (caddr_t
)®list
, ®len
) != DDI_PROP_SUCCESS
) {
3273 cmn_err(CE_WARN
, "fdc: reg property not found");
3274 return (DDI_FAILURE
);
3277 nregs
= reglen
/ sizeof (*reglist
);
3278 for (i
= 0; i
< nregs
; i
++) {
3279 if (reglist
[i
].bustype
== 1) {
3280 *ioaddr
= reglist
[i
].base
;
3281 status
= DDI_SUCCESS
;
3285 kmem_free(reglist
, reglen
);
3287 if (status
== DDI_SUCCESS
) {
3288 if (*ioaddr
== 0x3f2 || *ioaddr
== 0x372) {
3290 * Some BIOS's (ASUS is one) don't include first
3291 * two IO ports in the floppy controller resources.
3294 *ioaddr
-= 2; /* step back to 0x3f0 or 0x370 */
3297 * It would be nice to update the regs property as well
3298 * so device pathname contains 3f0 instead of 3f2, but
3299 * updating the regs now won't have this effect as that
3300 * component of the device pathname has already been
3301 * constructed by the ISA nexus driver.
3303 * reglist[i].base -= 2;
3304 * reglist[i].size += 2;
3305 * dev = makedevice(ddi_driver_major(dip), 0);
3306 * ddi_prop_update_int_array(dev, dip, "reg",
3307 * (int *)reglist, reglen / sizeof (int));