1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 
  26 /*
  27  * Intel 82077 Floppy Disk Driver
  28  */
  29 
  30 /*
  31  * Notes
  32  *
  33  *      0. The driver supports two flavors of hardware design:
  34  *              "SUNW,fdtwo"    - sun4m - 82077 with sun4m style Auxio
  35  *              "fdthree"  - sun4u - 82077 with DMA
  36  *         In addition it supports an apparent bug in some versions of
  37  *         the 82077 controller.
  38  *
  39  *      1. The driver is mostly set up for multiple controllers, multiple
  40  *      drives. However- we *do* assume the use of the AUXIO register, and
  41  *      if we ever have > 1 fdc, we'll have to see what that means. This
  42  *      is all intrinsically machine specific, but there isn't much we
  43  *      can do about it.
  44  *
  45  *      2. The driver also is structured to deal with one drive active at
  46  *      a time. This is because the 82072 chip (no longer supported) was
  47  *      known to be buggy with respect to overlapped seeks.
  48  *
  49  *      3. The high level interrupt code is in assembler, and runs in a
  50  *      sparc trap window. It acts as a pseudo-dma engine as well as
  51  *      handles a couple of other interrupts. When it gets its job done,
  52  *      it schedules a second stage interrupt (soft interrupt) which
  53  *      is then fielded here in fd_lointr.  When DMA is used, the fdintr_dma
  54  *      interrupt handler is used.
  55  *
  56  *      4. Nearly all locking is done on a lower level MUTEX_DRIVER
  57  *      mutex. The locking is quite conservative, and is generally
  58  *      established very close to any of the entries into the driver.
  59  *      There is nearly no locking done of the high level MUTEX_DRIVER
  60  *      mutex (which generally is a SPIN mutex because the floppy usually
  61  *      interrupts above LOCK_LEVEL). The assembler high level interrupt
  62  *      handler grabs the high level mutex, but the code in the driver
  63  *      here is especially structured to not need to do this.
  64  *
  65  *      5. Fdrawioctl commands that pass data are not optimized for
  66  *      speed. If they need to be faster, the driver structure will
  67  *      have to be redone such that fdrawioctl calls physio after
  68  *      cons'ing up a uio structure and that fdstart will be able
  69  *      to detect that a particular buffer is a 'special' buffer.
  70  *
  71  *      6. Removable media support is not complete.
  72  *
  73  */
  74 
  75 #include <sys/param.h>
  76 #include <sys/buf.h>
  77 #include <sys/ioctl.h>
  78 #include <sys/uio.h>
  79 #include <sys/open.h>
  80 #include <sys/conf.h>
  81 #include <sys/file.h>
  82 #include <sys/cmn_err.h>
  83 #include <sys/debug.h>
  84 #include <sys/kmem.h>
  85 #include <sys/stat.h>
  86 #include <sys/autoconf.h>
  87 
  88 #include <sys/dklabel.h>
  89 
  90 #include <sys/vtoc.h>
  91 #include <sys/dkio.h>
  92 #include <sys/fdio.h>
  93 
  94 #include <sys/ddi.h>
  95 #include <sys/sunddi.h>
  96 #include <sys/kstat.h>
  97 
  98 /*
  99  * included to check for ELC or SLC which report floppy controller that
 100  */
 101 #include <sys/cpu.h>
 102 
 103 #include "sys/fdvar.h"
 104 #include "sys/fdreg.h"
 105 #include "sys/dma_i8237A.h"
 106 
 107 /*
 108  * Defines
 109  */
 110 #define KIOSP   KSTAT_IO_PTR(un->un_iostat)
 111 #define KIOIP   KSTAT_INTR_PTR(fdc->c_intrstat)
 112 #define MEDIUM_DENSITY  0x40
 113 #define SEC_SIZE_CODE   (fdctlr.c_csb->csb_unit]->un_chars->medium ? 3 : 2)
 114 #define CMD_READ        (MT + SK + FDRAW_RDCMD + MFM)
 115 #define CMD_WRITE       (MT + FDRAW_WRCMD + MFM)
 116 #define C               CE_CONT
 117 #define FD_POLLABLE_PROP        "pollable"      /* prom property */
 118 #define FD_MANUAL_EJECT         "manual"        /* prom property */
 119 #define FD_UNIT                 "unit"          /* prom property */
 120 
 121 /*
 122  * Sony MP-F17W-50D Drive Parameters
 123  *                              High Capacity
 124  *      Capacity unformatted    2Mb
 125  *      Capacity formatted      1.47Mb
 126  *      Encoding method  MFM
 127  *      Recording density       17434 bpi
 128  *      Track density           135 tpi
 129  *      Cylinders               80
 130  *      Heads                   2
 131  *      Tracks                  160
 132  *      Rotational speed        300 rpm
 133  *      Transfer rate           250/500 kbps
 134  *      Latency (average)       100 ms
 135  *      Access time
 136  *              Average         95 ms
 137  *              Track to track  3 ms
 138  *      Head settling time      15 ms
 139  *      Motor start time        500 ms
 140  *      Head load time          ? ms
 141  */
 142 
 143 /*
 144  * The max_fd_dma_len is used only when southbridge is present.
 145  * It has been observed that when IFB tests are run the floppy dma could get
 146  * starved and result in underrun errors. After experimenting it was found that
 147  * doing dma in chunks of 2048 works OK.
 148  * The reason for making this a global variable is that there could be
 149  * situations under which the customer would like to get full performance
 150  * from floppy. He may not be having IFB boards that cause underrun errors.
 151  * Under those conditions we could set this value to a much higher value
 152  * by editing /etc/system file.
 153  */
 154 int     max_fd_dma_len = 2048;
 155 
 156 static void quiesce_fd_interrupt(struct fdctlr *);
 157 
 158 /*
 159  * Character/block entry points function prototypes
 160  */
 161 static int fd_open(dev_t *, int, int, cred_t *);
 162 static int fd_close(dev_t, int, int, cred_t *);
 163 static int fd_strategy(struct buf *);
 164 static int fd_read(dev_t, struct uio *, cred_t *);
 165 static int fd_write(dev_t, struct uio *, cred_t *);
 166 static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
 167 static int
 168 fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *);
 169 
 170 /*
 171  * Device operations (dev_ops) entries function prototypes
 172  */
 173 static int fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
 174                 void **result);
 175 static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
 176 static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
 177 static int fd_power(dev_info_t *dip, int component, int level);
 178 
 179 /*
 180  * Internal functions
 181  */
 182 static int fd_attach_check_drive(struct fdctlr *fdc);
 183 static int fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc);
 184 static int fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc);
 185 static int fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc,
 186     int *hard);
 187 static int fd_build_label_vtoc(struct fdunit *, struct vtoc *);
 188 static void fd_build_user_vtoc(struct fdunit *, struct vtoc *);
 189 static int fdcheckdisk(struct fdctlr *fdc, int unit);
 190 static int fd_check_media(dev_t dev, enum dkio_state state);
 191 static void fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard,
 192     int locks);
 193 static void fdeject(struct fdctlr *, int unit);
 194 static int fdexec(struct fdctlr *fdc, int flags);
 195 static void fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit);
 196 static int fdformat(struct fdctlr *fdc, int unit, int cyl, int hd);
 197 static caddr_t fd_getauxiova();
 198 static struct fdctlr *fd_getctlr(dev_t);
 199 static void fdgetcsb(struct fdctlr *);
 200 static int fdgetlabel(struct fdctlr *fdc, int unit);
 201 enum dkio_state fd_get_media_state(struct fdctlr *, int);
 202 static uint_t fdintr_dma();
 203 static int fd_isauxiodip(dev_info_t *);
 204 static uint_t  fd_lointr(caddr_t arg);
 205 static void fd_media_watch(void *);
 206 static void fdmotoff(void *);
 207 static int fd_part_is_open(struct fdunit *un, int part);
 208 static int fdrawioctl(struct fdctlr *, int, intptr_t, int);
 209 static int fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg);
 210 static int fdrecover(struct fdctlr *);
 211 static void fdretcsb(struct fdctlr *);
 212 static int fdreset(struct fdctlr *);
 213 static int fdrw(struct fdctlr *fdc, int, int, int, int, int, caddr_t, uint_t);
 214 static void fdselect(struct fdctlr *fdc, int unit, int onoff);
 215 static int fdsensedrv(struct fdctlr *fdc, int unit);
 216 static int fdsense_chng(struct fdctlr *, int unit);
 217 static void fdstart(struct fdctlr *);
 218 static int fdstart_dma(register struct fdctlr *fdc, caddr_t addr, uint_t len);
 219 static int fd_unit_is_open(struct fdunit *);
 220 static void fdunpacklabel(struct packed_label *, struct dk_label *);
 221 static int fd_unbind_handle(struct fdctlr *);
 222 static void fdwatch(void *);
 223 static void set_rotational_speed(struct fdctlr *, int);
 224 static int fd_get_media_info(struct fdunit *un, caddr_t buf, int flag);
 225 static int fd_pm_lower_power(struct fdctlr *fdc);
 226 static int fd_pm_raise_power(struct fdctlr *fdc);
 227 static void create_pm_components(dev_info_t *dip);
 228 static void set_data_count_register(struct fdctlr *fdc, uint32_t count);
 229 static uint32_t get_data_count_register(struct fdctlr *fdc);
 230 static void reset_dma_controller(struct fdctlr *fdc);
 231 static void set_data_address_register(struct fdctlr *fdc, uint32_t address);
 232 static uint32_t get_dma_control_register(struct fdctlr *fdc);
 233 static void set_dma_mode(struct fdctlr *fdc, int val);
 234 static void set_dma_control_register(struct fdctlr *fdc, uint32_t val);
 235 static void release_sb_dma(struct fdctlr *fdc);
 236 
 237 /*
 238  * External functions
 239  */
 240 extern uint_t fd_intr(caddr_t); /* defined in fd_asm.s */
 241 extern void set_auxioreg();
 242 extern void call_debug();
 243 
 244 
 245 
 246 /*
 247  * The following macro checks whether the device in a SUSPENDED state.
 248  * As per WDD guide lines the I/O requests to a suspended device should
 249  * be blocked until the device is resumed.
 250  * Here we cv_wait on c_suspend_cv, and there is a cv_broadcast() in
 251  * DDI_RESUME to wake up this thread.
 252  *
 253  * NOTE: This code is not tested because the kernel threads are suspended
 254  * before the device is suspended. So there can not be any I/O requests on
 255  * a suspended device until the cpr implementation changes..
 256  */
 257 
 258 #define CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc)  \
 259                 {\
 260                         while (fdc->c_un->un_state == FD_STATE_SUSPENDED) {\
 261                                 cv_wait(&fdc->c_suspend_cv, \
 262                                                         &fdc->c_lolock);\
 263                         }\
 264                 }
 265 
 266 /*
 267  * bss (uninitialized data)
 268  */
 269 struct  fdctlr  *fdctlrs;       /* linked list of controllers */
 270 
 271 /*
 272  * initialized data
 273  */
 274 
 275 static int fd_check_media_time = 5000000;       /* 5 second state check */
 276 static int fd_pollable = 0;
 277 static uchar_t rwretry = 10;
 278 static uchar_t skretry = 5;
 279 /* This variable allows the dynamic change of the burst size */
 280 static int fd_burstsize = DCSR_BURST_0 | DCSR_BURST_1;
 281 
 282 static struct driver_minor_data {
 283         char    *name;
 284         int     minor;
 285         int     type;
 286 } fd_minor [] = {
 287         { "a", 0, S_IFBLK},
 288         { "b", 1, S_IFBLK},
 289         { "c", 2, S_IFBLK},
 290         { "a,raw", 0, S_IFCHR},
 291         { "b,raw", 1, S_IFCHR},
 292         { "c,raw", 2, S_IFCHR},
 293         {0}
 294 };
 295 
 296 /*
 297  * If the interrupt handler is invoked and no controllers expect an
 298  * interrupt, the kernel panics.  The following message is printed out.
 299  */
 300 char *panic_msg = "fd_intr: unexpected interrupt\n";
 301 
 302 /*
 303  * Specify/Configure cmd parameters
 304  */
 305 static uchar_t fdspec[2] = { 0xc2, 0x33 };      /*  "specify" parameters */
 306 static uchar_t fdconf[3] = { 0x64, 0x58, 0x00 }; /*  "configure" parameters */
 307 
 308 /* When DMA is used, set the ND bit to 0 */
 309 #define SPEC_DMA_MODE   0x32
 310 
 311 /*
 312  * default characteristics
 313  */
 314 static struct fd_char fdtypes[] = {
 315         {       /* struct fd_char fdchar_1.7MB density */
 316                 0,              /* medium */
 317                 500,            /* transfer rate */
 318                 80,             /* number of cylinders */
 319                 2,              /* number of heads */
 320                 512,            /* sector size */
 321                 21,             /* sectors per track */
 322                 -1,             /* (NA) # steps per data track */
 323         },
 324         {       /* struct fd_char fdchar_highdens */
 325                 0,              /* medium */
 326                 500,            /* transfer rate */
 327                 80,             /* number of cylinders */
 328                 2,              /* number of heads */
 329                 512,            /* sector size */
 330                 18,             /* sectors per track */
 331                 -1,             /* (NA) # steps per data track */
 332         },
 333         {       /* struct fd_char fdchar_meddens */
 334                 1,              /* medium */
 335                 500,            /* transfer rate */
 336                 77,             /* number of cylinders */
 337                 2,              /* number of heads */
 338                 1024,           /* sector size */
 339                 8,              /* sectors per track */
 340                 -1,             /* (NA) # steps per data track */
 341         },
 342         {       /* struct fd_char fdchar_lowdens  */
 343                 0,              /* medium */
 344                 250,            /* transfer rate */
 345                 80,             /* number of cylinders */
 346                 2,              /* number of heads */
 347                 512,            /* sector size */
 348                 9,              /* sectors per track */
 349                 -1,             /* (NA) # steps per data track */
 350         }
 351 };
 352 
 353 
 354 static int nfdtypes = sizeof (fdtypes) / sizeof (fdtypes[0]);
 355 
 356 
 357 /*
 358  * Default Label & partition maps
 359  */
 360 
 361 static struct packed_label fdlbl_high_21 = {
 362         { "3.5\" floppy cyl 80 alt 0 hd 2 sec 21" },
 363         300,                            /* rotations per minute */
 364         80,                             /* # physical cylinders */
 365         0,                              /* alternates per cylinder */
 366         1,                              /* interleave factor */
 367         80,                             /* # of data cylinders */
 368         0,                              /* # of alternate cylinders */
 369         2,                              /* # of heads in this partition */
 370         21,                             /* # of 512 byte sectors per track */
 371         {
 372                 { 0, 79 * 2 * 21 },     /* part 0 - all but last cyl */
 373                 { 79, 1 * 2 * 21 },     /* part 1 - just the last cyl */
 374                 { 0, 80 * 2 * 21 },     /* part 2 - "the whole thing" */
 375         },
 376         {       0,                      /* version */
 377                 "",                     /* volume label */
 378                 3,                      /* no. of partitions */
 379                 { 0 },                  /* partition hdrs, sec 2 */
 380                 { 0 },                  /* mboot info.  unsupported */
 381                 VTOC_SANE,              /* verify vtoc sanity */
 382                 { 0 },                  /* reserved space */
 383                 0,                      /* timestamp */
 384         },
 385 };
 386 
 387 static struct packed_label fdlbl_high_80 = {
 388         { "3.5\" floppy cyl 80 alt 0 hd 2 sec 18" },
 389         300,                            /* rotations per minute */
 390         80,                             /* # physical cylinders */
 391         0,                              /* alternates per cylinder */
 392         1,                              /* interleave factor */
 393         80,                             /* # of data cylinders */
 394         0,                              /* # of alternate cylinders */
 395         2,                              /* # of heads in this partition */
 396         18,                             /* # of 512 byte sectors per track */
 397         {
 398                 { 0, 79 * 2 * 18 },     /* part 0 - all but last cyl */
 399                 { 79, 1 * 2 * 18 },     /* part 1 - just the last cyl */
 400                 { 0, 80 * 2 * 18 },     /* part 2 - "the whole thing" */
 401         },
 402         {       0,                      /* version */
 403                 "",                     /* volume label */
 404                 3,                      /* no. of partitions */
 405                 { 0 },                  /* partition hdrs, sec 2 */
 406                 { 0 },                  /* mboot info.  unsupported */
 407                 VTOC_SANE,              /* verify vtoc sanity */
 408                 { 0 },                  /* reserved space */
 409                 0,                      /* timestamp */
 410         },
 411 };
 412 
 413 /*
 414  * A medium density diskette has 1024 byte sectors.  The dk_label structure
 415  * assumes a sector is DEVBSIZE (512) bytes.
 416  */
 417 static struct packed_label fdlbl_medium_80 = {
 418         { "3.5\" floppy cyl 77 alt 0 hd 2 sec 8" },
 419         360,                            /* rotations per minute */
 420         77,                             /* # physical cylinders */
 421         0,                              /* alternates per cylinder */
 422         1,                              /* interleave factor */
 423         77,                             /* # of data cylinders */
 424         0,                              /* # of alternate cylinders */
 425         2,                              /* # of heads in this partition */
 426         16,                             /* # of 512 byte sectors per track */
 427         {
 428                 { 0, 76 * 2 * 8 * 2 },  /* part 0 - all but last cyl */
 429                 { 76, 1 * 2 * 8 * 2 },  /* part 1 - just the last cyl */
 430                 { 0, 77 * 2 * 8 * 2 },  /* part 2 - "the whole thing" */
 431         },
 432         {       0,                      /* version */
 433                 "",                     /* volume label */
 434                 3,                      /* no. of partitions */
 435                 { 0 },                  /* partition hdrs, sec 2 */
 436                 { 0 },                  /* mboot info.  unsupported */
 437                 VTOC_SANE,              /* verify vtoc sanity */
 438                 { 0 },                  /* reserved space */
 439                 0,                      /* timestamp */
 440         },
 441 };
 442 
 443 static struct packed_label fdlbl_low_80 = {
 444         { "3.5\" floppy cyl 80 alt 0 hd 2 sec 9" },
 445         300,                            /* rotations per minute */
 446         80,                             /* # physical cylinders */
 447         0,                              /* alternates per cylinder */
 448         1,                              /* interleave factor */
 449         80,                             /* # of data cylinders */
 450         0,                              /* # of alternate cylinders */
 451         2,                              /* # of heads in this partition */
 452         9,                              /* # of 512 byte sectors per track */
 453         {
 454                 { 0, 79 * 2 * 9 },      /* part 0 - all but last cyl */
 455                 { 79, 1 * 2 * 9 },      /* part 1 - just the last cyl */
 456                 { 0, 80 * 2 * 9 },      /* part 2 - "the whole thing" */
 457         },
 458         {       0,                      /* version */
 459                 "",                     /* volume label */
 460                 3,                      /* no. of partitions */
 461                 { 0 },                  /* partition hdrs, sec 2 */
 462                 { 0 },                  /* mboot info.  unsupported */
 463                 VTOC_SANE,              /* verify vtoc sanity */
 464                 { 0 },                  /* reserved space */
 465                 0,                      /* timestamp */
 466         },
 467 };
 468 
 469 static struct fdcmdinfo {
 470         char *cmdname;          /* command name */
 471         uchar_t ncmdbytes;      /* number of bytes of command */
 472         uchar_t nrsltbytes;     /* number of bytes in result */
 473         uchar_t cmdtype;                /* characteristics */
 474 } fdcmds[] = {
 475         "", 0, 0, 0,                    /* - */
 476         "", 0, 0, 0,                    /* - */
 477         "read_track", 9, 7, 1,          /* 2 */
 478         "specify", 3, 0, 3,             /* 3 */
 479         "sense_drv_status", 2, 1, 3,    /* 4 */
 480         "write", 9, 7, 1,               /* 5 */
 481         "read", 9, 7, 1,                /* 6 */
 482         "recalibrate", 2, 0, 2,                 /* 7 */
 483         "sense_int_status", 1, 2, 3,    /* 8 */
 484         "write_del", 9, 7, 1,           /* 9 */
 485         "read_id", 2, 7, 2,             /* A */
 486         "motor_on/off", 1, 0, 4,        /* B */
 487         "read_del", 9, 7, 1,            /* C */
 488         "format_track", 10, 7, 1,       /* D */
 489         "dump_reg", 1, 10, 4,           /* E */
 490         "seek", 3, 0, 2,                /* F */
 491         "", 0, 0, 0,                    /* - */
 492         "", 0, 0, 0,                    /* - */
 493         "", 0, 0, 0,                    /* - */
 494         "configure", 4, 0, 4,           /* 13 */
 495         /* relative seek */
 496 };
 497 
 498 static struct cb_ops fd_cb_ops = {
 499         fd_open,                /* open */
 500         fd_close,               /* close */
 501         fd_strategy,            /* strategy */
 502         nodev,                  /* print */
 503         nodev,                  /* dump */
 504         fd_read,                /* read */
 505         fd_write,               /* write */
 506         fd_ioctl,               /* ioctl */
 507         nodev,                  /* devmap */
 508         nodev,                  /* mmap */
 509         nodev,                  /* segmap */
 510         nochpoll,               /* poll */
 511         fd_prop_op,             /* cb_prop_op */
 512         0,                      /* streamtab  */
 513         D_NEW | D_MP            /* Driver compatibility flag */
 514 };
 515 
 516 static struct dev_ops   fd_ops = {
 517         DEVO_REV,               /* devo_rev, */
 518         0,                      /* refcnt  */
 519         fd_info,                /* info */
 520         nulldev,                /* identify */
 521         nulldev,                /* probe */
 522         fd_attach,              /* attach */
 523         fd_detach,              /* detach */
 524         nodev,                  /* reset */
 525         &fd_cb_ops,                 /* driver operations */
 526         (struct bus_ops *)0,    /* bus operations */
 527         fd_power,               /* power */
 528         ddi_quiesce_not_supported,      /* devo_quiesce */
 529 };
 530 
 531 
 532 /*
 533  * error handling
 534  *
 535  * for debugging, set rwretry and skretry = 1
 536  *              set fderrlevel to 1
 537  *              set fderrmask  to 224  or 100644
 538  *
 539  * after debug set rwretry to 10, skretry to 5, and fderrlevel to 3
 540  * set fderrmask to FDEM_ALL
 541  * remove the define FD_DEBUG
 542  *
 543  */
 544 
 545 static unsigned int fderrmask = (unsigned int)FDEM_ALL;
 546 static int fderrlevel = 3;
 547 
 548 static int tosec = 16;  /* long timeouts for sundiag for now */
 549 
 550 /*
 551  * loadable module support
 552  */
 553 
 554 #include <sys/modctl.h>
 555 
 556 extern struct mod_ops mod_driverops;
 557 static struct modldrv modldrv = {
 558         &mod_driverops,             /* Type of module. driver here */
 559         "Floppy Driver",        /* Name of the module. */
 560         &fd_ops,            /* Driver ops vector */
 561 };
 562 
 563 static struct modlinkage modlinkage = {
 564         MODREV_1,
 565         &modldrv,
 566         NULL
 567 };
 568 
 569 int
 570 _init(void)
 571 {
 572         return (mod_install(&modlinkage));
 573 }
 574 
 575 int
 576 _info(struct modinfo *modinfop)
 577 {
 578         return (mod_info(&modlinkage, modinfop));
 579 }
 580 
 581 int
 582 _fini(void)
 583 {
 584         int e;
 585 
 586         if ((e = mod_remove(&modlinkage)) != 0)
 587                 return (e);
 588 
 589         /* ddi_soft_state_fini() */
 590         return (0);
 591 }
 592 
 593 /* ARGSUSED */
 594 static int
 595 fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 596 {
 597         struct                  fdctlr *fdc;
 598         struct                  driver_minor_data *dmdp;
 599         int                     instance = ddi_get_instance(dip);
 600         int                     hard_intr_set = 0;
 601 
 602         FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: start\n"));
 603 
 604         switch (cmd) {
 605                 case DDI_ATTACH:
 606                         break;
 607                 case DDI_RESUME:
 608 
 609                         if (!(fdc = fd_getctlr(instance << FDINSTSHIFT))) {
 610                                 return (DDI_FAILURE);
 611                         }
 612                         quiesce_fd_interrupt(fdc);
 613                         if (fdc->c_fdtype & FDCTYPE_SB)
 614                                 if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
 615                                     fdintr_dma, (caddr_t)0) != DDI_SUCCESS) {
 616                                 return (DDI_FAILURE);
 617                         }
 618 
 619                         (void) pm_raise_power(dip, 0, PM_LEVEL_ON);
 620                         mutex_enter(&fdc->c_lolock);
 621                         /*
 622                          * Wake up any thread blocked due to I/O requests
 623                          * while the device was suspended.
 624                          */
 625                         cv_broadcast(&fdc->c_suspend_cv);
 626                         mutex_exit(&fdc->c_lolock);
 627                         return (DDI_SUCCESS);
 628 
 629                 default:
 630                         return (DDI_FAILURE);
 631         }
 632 
 633 
 634         /*
 635          * Check for the pollable property
 636          * A pollable floppy drive currently only exists on the
 637          * Sparcstation Voyager.  This drive does not need to
 638          * be turned on in order to sense whether or not a diskette
 639          * is present.
 640          */
 641         if (ddi_getprop(DDI_DEV_T_ANY, dip,
 642             DDI_PROP_DONTPASS, FD_POLLABLE_PROP, 0))
 643                 fd_pollable = 1;
 644 
 645         fdc = kmem_zalloc(sizeof (*fdc), KM_SLEEP);
 646         fdc->c_dip = dip;
 647 
 648 
 649         fdc->c_next = fdctlrs;
 650         fdctlrs = fdc;
 651 
 652         /* Determine which type of controller is present and initialize it */
 653         if (fd_attach_det_ctlr(dip, fdc) == DDI_FAILURE) {
 654                 fd_cleanup(dip, fdc, hard_intr_set, 0);
 655                 return (DDI_FAILURE);
 656         }
 657         /* Finish mapping the device registers & setting up structures */
 658         if (fd_attach_map_regs(dip, fdc) == DDI_FAILURE) {
 659                 fd_cleanup(dip, fdc, hard_intr_set, 0);
 660                 return (DDI_FAILURE);
 661         }
 662 
 663         /*
 664          * Initialize the DMA limit structures if it's being used.
 665          */
 666         if (fdc->c_fdtype & FDCTYPE_DMA) {
 667                 fdc->c_fd_dma_lim.dma_attr_version = DMA_ATTR_V0;
 668                 fdc->c_fd_dma_lim.dma_attr_addr_lo = 0x00000000ull;
 669                 fdc->c_fd_dma_lim.dma_attr_addr_hi = 0xfffffffeull;
 670                 fdc->c_fd_dma_lim.dma_attr_count_max = 0xffffff;
 671                 if (fdc->c_fdtype & FDCTYPE_SB) {
 672                         fdc->c_fd_dma_lim.dma_attr_align = FD_SB_DMA_ALIGN;
 673                 } else {
 674                         fdc->c_fd_dma_lim.dma_attr_align = 1;
 675                 }
 676                 fdc->c_fd_dma_lim.dma_attr_burstsizes = 0x0;
 677                 fdc->c_fd_dma_lim.dma_attr_minxfer = 1;
 678                 fdc->c_fd_dma_lim.dma_attr_maxxfer = 0xffff;
 679                 fdc->c_fd_dma_lim.dma_attr_seg = 0xffff;
 680                 fdc->c_fd_dma_lim.dma_attr_sgllen = 1;
 681                 fdc->c_fd_dma_lim.dma_attr_granular = 512;
 682 
 683                 if (ddi_dma_alloc_handle(dip, &fdc->c_fd_dma_lim,
 684                     DDI_DMA_DONTWAIT, 0, &fdc->c_dmahandle) != DDI_SUCCESS) {
 685                         fd_cleanup(dip, fdc, hard_intr_set, 0);
 686                         return (DDI_FAILURE);
 687                 }
 688 
 689                 if (fdc->c_fdtype & FDCTYPE_SB) {
 690                         ddi_device_acc_attr_t dev_attr;
 691                         size_t  rlen;
 692 
 693                         dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
 694                         dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
 695                         dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
 696 
 697                         if (ddi_dma_mem_alloc(fdc->c_dmahandle,
 698                             (size_t)(32*1024), &dev_attr, DDI_DMA_CONSISTENT,
 699                             DDI_DMA_SLEEP, NULL, (caddr_t *)&fdc->dma_buf,
 700                             &rlen, &fdc->c_dma_buf_handle) != DDI_SUCCESS) {
 701                                 fd_cleanup(dip, fdc, hard_intr_set, 0);
 702                                 return (DDI_FAILURE);
 703                         }
 704 
 705                 }
 706         }
 707 
 708 
 709         /* Register the interrupts */
 710         if (fd_attach_register_interrupts(dip, fdc,
 711             &hard_intr_set) == DDI_FAILURE) {
 712                 fd_cleanup(dip, fdc, hard_intr_set, 0);
 713                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
 714                     (C, "fd_attach: registering interrupts failed\n"));
 715                 return (DDI_FAILURE);
 716         }
 717 
 718 
 719         /*
 720          * set initial controller/drive/disk "characteristics/geometry"
 721          *
 722          * NOTE:  The driver only supports one floppy drive.  The hardware
 723          * only supports one drive because there is only one auxio register
 724          * for one drive.
 725          */
 726         fdc->c_un = kmem_zalloc(sizeof (struct fdunit), KM_SLEEP);
 727         fdc->c_un->un_chars = kmem_alloc(sizeof (struct fd_char), KM_SLEEP);
 728         fdc->c_un->un_iostat = kstat_create("fd", 0, "fd0", "disk",
 729             KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
 730         if (fdc->c_un->un_iostat) {
 731                 fdc->c_un->un_iostat->ks_lock = &fdc->c_lolock;
 732                 kstat_install(fdc->c_un->un_iostat);
 733         }
 734 
 735         fdc->c_un->un_drive = kmem_zalloc(sizeof (struct fd_drive), KM_SLEEP);
 736 
 737         /* check for the manual eject property */
 738         if (ddi_getprop(DDI_DEV_T_ANY, dip,
 739             DDI_PROP_DONTPASS, FD_MANUAL_EJECT, 0)) {
 740                 fdc->c_un->un_drive->fdd_ejectable = 0;
 741         } else {
 742                 /* an absence of the property indicates auto eject */
 743                 fdc->c_un->un_drive->fdd_ejectable = -1;
 744         }
 745 
 746         FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: ejectable? %d\n",
 747             fdc->c_un->un_drive->fdd_ejectable));
 748 
 749         /*
 750          * Check for the drive id.  If the drive id property doesn't exist
 751          * then the drive id is set to 0
 752          */
 753         fdc->c_un->un_unit_no = ddi_getprop(DDI_DEV_T_ANY, dip,
 754             DDI_PROP_DONTPASS, FD_UNIT, 0);
 755 
 756 
 757         if (fdc->c_fdtype & FDCTYPE_SB) {
 758                 fdc->sb_dma_channel = ddi_getprop(DDI_DEV_T_ANY, dip,
 759                     DDI_PROP_DONTPASS, "dma-channel", 0);
 760         }
 761 
 762 
 763         FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: unit %d\n",
 764             fdc->c_un->un_unit_no));
 765 
 766         /* Initially set the characteristics to high density */
 767         fdc->c_un->un_curfdtype = 1;
 768         *fdc->c_un->un_chars = fdtypes[fdc->c_un->un_curfdtype];
 769         fdunpacklabel(&fdlbl_high_80, &fdc->c_un->un_label);
 770 
 771         /* Make sure drive is present */
 772         if (fd_attach_check_drive(fdc) == DDI_FAILURE) {
 773                 fd_cleanup(dip, fdc, hard_intr_set, 1);
 774                 return (DDI_FAILURE);
 775         }
 776 
 777         for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
 778                 if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
 779                     (instance << FDINSTSHIFT) | dmdp->minor,
 780                     DDI_NT_FD, 0) == DDI_FAILURE) {
 781                         fd_cleanup(dip, fdc, hard_intr_set, 1);
 782                         return (DDI_FAILURE);
 783                 }
 784         }
 785 
 786         create_pm_components(dip);
 787 
 788         /*
 789          * Add a zero-length attribute to tell the world we support
 790          * kernel ioctls (for layered drivers)
 791          */
 792         (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
 793             DDI_KERNEL_IOCTL, NULL, 0);
 794 
 795         ddi_report_dev(dip);
 796 
 797         FDERRPRINT(FDEP_L1, FDEM_ATTA,
 798             (C, "attached 0x%x\n", ddi_get_instance(dip)));
 799 
 800         return (DDI_SUCCESS);
 801 }
 802 
 803 /*
 804  * Finish mapping the registers and initializing structures
 805  */
 806 static int
 807 fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc)
 808 {
 809         ddi_device_acc_attr_t attr;
 810 
 811         attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
 812         attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
 813         attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
 814 
 815         /* Map the DMA registers of the platform supports DMA */
 816         if (fdc->c_fdtype & FDCTYPE_SB) {
 817                 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
 818                     0, sizeof (struct sb_dma_reg), &attr,
 819                     &fdc->c_handlep_dma)) {
 820                         return (DDI_FAILURE);
 821                 }
 822 
 823 
 824         } else if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
 825                 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
 826                     0, sizeof (struct cheerio_dma_reg), &attr,
 827                     &fdc->c_handlep_dma)) {
 828                         return (DDI_FAILURE);
 829                 }
 830         }
 831 
 832         /* Reset the DMA engine and enable floppy interrupts */
 833         reset_dma_controller(fdc);
 834         set_dma_control_register(fdc, DCSR_INIT_BITS);
 835 
 836         /* Finish initializing structures associated with the device regs */
 837         switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
 838         case FDCTYPE_82077:
 839                 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "type is 82077\n"));
 840                 /*
 841                  * Initialize addrs of key registers
 842                  */
 843                 fdc->c_control =
 844                     (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_control;
 845                 fdc->c_fifo = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_fifo;
 846                 fdc->c_dor = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dor;
 847                 fdc->c_dir = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dir;
 848 
 849 
 850                 FDERRPRINT(FDEP_L1, FDEM_ATTA, ((int)C,
 851                     (char *)"fdattach: msr/dsr at %p\n",
 852                     (void *)fdc->c_control));
 853 
 854                 /*
 855                  * The 82077 doesn't use the first configuration parameter
 856                  * so let's adjust that while we know we're an 82077.
 857                  */
 858                 fdconf[0] = 0;
 859 
 860                 quiesce_fd_interrupt(fdc);
 861                 break;
 862         default:
 863                 break;
 864         }
 865 
 866         return (0);
 867 }
 868 
 869 /*
 870  * Determine which type of floppy controller is present and
 871  * initialize the registers accordingly
 872  */
 873 static int
 874 fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc)
 875 {
 876         ddi_device_acc_attr_t attr;
 877         attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
 878         /* DDI_NEVERSWAP_ACC since the controller has a byte interface. */
 879         attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
 880         attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
 881 
 882         FDERRPRINT(FDEP_L1, FDEM_ATTA,
 883             (C, "fdattach_det_cltr: start \n"));
 884 
 885         /*
 886          * First, map in the controller's registers
 887          * The controller has an 8-bit interface, so byte
 888          * swapping isn't needed
 889          */
 890 
 891         if (ddi_regs_map_setup(dip, 0, (caddr_t *)&fdc->c_reg,
 892             0, sizeof (union fdcreg),
 893             &attr,
 894             &fdc->c_handlep_cont)) {
 895                 return (DDI_FAILURE);
 896         }
 897 
 898         FDERRPRINT(FDEP_L1, FDEM_ATTA,
 899             (C, "fdattach_det_cltr: mapped floppy regs\n"));
 900 
 901 
 902         /*
 903          * Set platform specific characteristics based on the device-tree
 904          * node name.
 905          */
 906 
 907 
 908         if (strcmp(ddi_get_name(dip), "SUNW,fdtwo") == 0) {
 909                 fdc->c_fdtype |= FDCTYPE_SLAVIO;
 910                 fdc->c_fdtype |= FDCTYPE_82077;
 911                 fdc->c_auxiova = fd_getauxiova(dip);
 912                 fdc->c_auxiodata = (uchar_t)(AUX_MBO4M|AUX_TC4M);
 913                 fdc->c_auxiodata2 = (uchar_t)AUX_TC4M;
 914                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
 915                     (C, "fdattach: slavio will be used!\n"));
 916 
 917 
 918 /*
 919  * Check the binding name to identify whether it is a South bridge based
 920  * system or not.
 921  */
 922         } else if (strcmp(ddi_get_name(dip), "pnpALI,1533,0") == 0) {
 923 
 924                 fdc->c_fdtype |= FDCTYPE_SB;
 925                 fdc->c_fdtype |= FDCTYPE_82077;
 926                 fdc->c_fdtype |= FDCTYPE_DMA;
 927 
 928                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
 929                     (C, "fdattach: southbridge will be used!\n"));
 930 
 931                 /*
 932                  * The driver assumes high density characteristics until
 933                  * the diskette is looked at.
 934                  */
 935 
 936                 fdc->c_fdtype |= FDCTYPE_DMA8237;
 937                 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
 938 
 939 
 940         } else if (strcmp(ddi_get_name(dip), "fdthree") == 0) {
 941 
 942                 fdc->c_fdtype |= FDCTYPE_CHEERIO;
 943                 fdc->c_fdtype |= FDCTYPE_82077;
 944 
 945                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
 946                     (C, "fdattach: cheerio will be used!\n"));
 947                 /*
 948                  * The cheerio auxio register should be memory mapped.  The
 949                  * auxio register on other platforms is shared and mapped
 950                  * elsewhere in the kernel
 951                  */
 952                 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&fdc->c_auxio_reg,
 953                     0, sizeof (uint_t), &attr, &fdc->c_handlep_aux)) {
 954                         return (DDI_FAILURE);
 955                 }
 956 
 957                 /*
 958                  * The driver assumes high density characteristics until
 959                  * the diskette is looked at.
 960                  */
 961                 Set_auxio(fdc, AUX_HIGH_DENSITY);
 962                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
 963                     (C, "fdattach: auxio register 0x%x\n",
 964                     *fdc->c_auxio_reg));
 965 
 966                 fdc->c_fdtype |= FDCTYPE_DMA;
 967                 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
 968 
 969         }
 970 
 971         if (fdc->c_fdtype == 0) {
 972                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
 973                     (C, "fdattach: no controller!\n"));
 974                 return (DDI_FAILURE);
 975         } else {
 976                 return (0);
 977         }
 978 }
 979 
 980 
 981 /*
 982  * Register the floppy interrupts
 983  */
 984 static int
 985 fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc, int *hard)
 986 {
 987         ddi_iblock_cookie_t  iblock_cookie_soft;
 988         int status;
 989 
 990         /*
 991          * First call ddi_get_iblock_cookie() to retrieve the
 992          * the interrupt block cookie so that the mutexes may
 993          * be initialized before adding the interrupt.  If the
 994          * mutexes are initialized after adding the interrupt, there
 995          * could be a race condition.
 996          */
 997         if (ddi_get_iblock_cookie(dip, 0, &fdc->c_block) != DDI_SUCCESS) {
 998                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
 999                     (C, "fdattach: ddi_get_iblock_cookie failed\n"));
1000                 return (DDI_FAILURE);
1001 
1002         }
1003 
1004         /* Initialize high level mutex */
1005         mutex_init(&fdc->c_hilock, NULL, MUTEX_DRIVER, fdc->c_block);
1006 
1007         /*
1008          * Try to register fast trap handler, if unable try standard
1009          * interrupt handler, else bad
1010          */
1011 
1012         if (fdc->c_fdtype & FDCTYPE_DMA) {
1013                 if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
1014                     fdintr_dma, (caddr_t)0) == DDI_SUCCESS) {
1015                         FDERRPRINT(FDEP_L1, FDEM_ATTA,
1016                             (C, "fdattach: standard intr\n"));
1017 
1018                                 /*
1019                                  * When DMA is used, the low level lock
1020                                  * is used in the hard interrupt handler.
1021                                  */
1022                                 mutex_init(&fdc->c_lolock, NULL,
1023                                     MUTEX_DRIVER, fdc->c_block);
1024 
1025                                 *hard = 1;
1026                 } else {
1027                         FDERRPRINT(FDEP_L1, FDEM_ATTA,
1028                             (C, "fdattach: can't add dma intr\n"));
1029 
1030                         mutex_destroy(&fdc->c_hilock);
1031 
1032                         return (DDI_FAILURE);
1033                 }
1034         } else {
1035                 /*
1036                  * Platforms that don't support DMA have both hard
1037                  * and soft interrupts.
1038                  */
1039                 if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
1040                     fd_intr, (caddr_t)0) == DDI_SUCCESS) {
1041                         FDERRPRINT(FDEP_L1, FDEM_ATTA,
1042                             (C, "fdattach: standard intr\n"));
1043                         *hard = 1;
1044 
1045                         /* fast traps are not enabled */
1046                         fdc->c_fasttrap = 0;
1047 
1048                 } else {
1049                         FDERRPRINT(FDEP_L1, FDEM_ATTA,
1050                             (C, "fdattach: can't add intr\n"));
1051 
1052                         mutex_destroy(&fdc->c_hilock);
1053 
1054                         return (DDI_FAILURE);
1055                 }
1056 
1057 
1058                 /*
1059                  * Initialize the soft interrupt handler.  First call
1060                  * ddi_get_soft_iblock_cookie() so that the mutex may
1061                  * be initialized before the handler is added.
1062                  */
1063                 status = ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
1064                     &iblock_cookie_soft);
1065 
1066 
1067                 if (status != DDI_SUCCESS) {
1068                         mutex_destroy(&fdc->c_hilock);
1069                         return (DDI_FAILURE);
1070                 }
1071 
1072                 /*
1073                  * Initialize low level mutex which is used in the soft
1074                  * interrupt handler
1075                  */
1076                 mutex_init(&fdc->c_lolock, NULL, MUTEX_DRIVER,
1077                     iblock_cookie_soft);
1078 
1079                 if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &fdc->c_softid,
1080                     NULL, NULL,
1081                     fd_lointr,
1082                     (caddr_t)fdc) != DDI_SUCCESS) {
1083 
1084                         mutex_destroy(&fdc->c_hilock);
1085                         mutex_destroy(&fdc->c_lolock);
1086 
1087                         return (DDI_FAILURE);
1088                 }
1089         }
1090 
1091         fdc->c_intrstat = kstat_create("fd", 0, "fdc0", "controller",
1092             KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
1093         if (fdc->c_intrstat) {
1094                 fdc->c_hiintct = &KIOIP->intrs[KSTAT_INTR_HARD];
1095                 kstat_install(fdc->c_intrstat);
1096         }
1097 
1098         /* condition variable to wait on while an io transaction occurs */
1099         cv_init(&fdc->c_iocv, NULL, CV_DRIVER, NULL);
1100 
1101         /* condition variable for the csb */
1102         cv_init(&fdc->c_csbcv, NULL, CV_DRIVER, NULL);
1103 
1104         /* condition variable for motor on waiting period */
1105         cv_init(&fdc->c_motoncv, NULL, CV_DRIVER, NULL);
1106 
1107         /* semaphore to serialize opens and closes */
1108         sema_init(&fdc->c_ocsem, 1, NULL, SEMA_DRIVER, NULL);
1109 
1110         /* condition variable to wait on suspended floppy controller. */
1111         cv_init(&fdc->c_suspend_cv, NULL, CV_DRIVER, NULL);
1112 
1113         return (0);
1114 }
1115 
1116 /*
1117  * Make sure the drive is present
1118  *      - acquires the low level lock
1119  */
1120 static int
1121 fd_attach_check_drive(struct fdctlr *fdc)
1122 {
1123         int tmp_fderrlevel;
1124         int unit = fdc->c_un->un_unit_no;
1125 
1126         FDERRPRINT(FDEP_L1, FDEM_ATTA,
1127             (C, "fd_attach_check_drive\n"));
1128 
1129 
1130         mutex_enter(&fdc->c_lolock);
1131         switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
1132 
1133         /* insure that the eject line is reset */
1134         case FDCTYPE_82077:
1135 
1136                 /*
1137                  * Everything but the motor enable, drive select,
1138                  * and reset bits are turned off.  These three
1139                  * bits remain as they are.
1140                  */
1141                 /* LINTED */
1142                 Set_dor(fdc, ~((MOTEN(unit))|DRVSEL|RESET), 0);
1143 
1144                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1145                     (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
1146 
1147                 drv_usecwait(5);
1148                 if (unit == 0) {
1149                         /* LINTED */
1150                         Set_dor(fdc, RESET|DRVSEL, 1);
1151                 } else {
1152 
1153                         /* LINTED */
1154                         Set_dor(fdc, DRVSEL, 0);
1155                         /* LINTED */
1156                         Set_dor(fdc, RESET, 1);
1157                 }
1158 
1159                 drv_usecwait(5);
1160 
1161                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1162                     (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
1163 
1164                 if (!((fdc->c_fdtype & FDCTYPE_CHEERIO) ||
1165                     (fdc->c_fdtype & FDCTYPE_SB))) {
1166                         set_auxioreg(AUX_TC4M, 0);
1167                 }
1168                 break;
1169         default:
1170                 break;
1171         }
1172 
1173 
1174         fdgetcsb(fdc);
1175         if (fdreset(fdc) != 0) {
1176                 mutex_exit(&fdc->c_lolock);
1177                 return (DDI_FAILURE);
1178         }
1179 
1180 
1181         /* check for drive present */
1182 
1183         tmp_fderrlevel = fderrlevel;
1184 
1185 
1186         fderrlevel = FDEP_LMAX;
1187 
1188         FDERRPRINT(FDEP_L1, FDEM_ATTA,
1189             (C, "fdattach: call fdrecalseek\n"));
1190 
1191         /* Make sure the drive is present */
1192         if (fdrecalseek(fdc, unit, -1, 0) != 0) {
1193                 timeout_id_t timeid = fdc->c_mtimeid;
1194                 fderrlevel = tmp_fderrlevel;
1195                 fdc->c_mtimeid = 0;
1196                 mutex_exit(&fdc->c_lolock);
1197 
1198 
1199                 /* Do not hold the mutex over the call to untimeout */
1200                 if (timeid) {
1201                         (void) untimeout(timeid);
1202                 }
1203 
1204                 FDERRPRINT(FDEP_L2, FDEM_ATTA,
1205                     (C, "fd_attach: no drive?\n"));
1206 
1207                 return (DDI_FAILURE);
1208         }
1209 
1210         fderrlevel = tmp_fderrlevel;
1211 
1212         fdselect(fdc, unit, 0);    /* deselect drive zero (used in fdreset) */
1213         fdretcsb(fdc);
1214         mutex_exit(&fdc->c_lolock);
1215 
1216         return (0);
1217 }
1218 
1219 /*
1220  * Clean up routine used by fd_detach and fd_attach
1221  *
1222  * Note: if the soft id is non-zero, then ddi_add_softintr() completed
1223  * successfully.  I can not make the same assumption about the iblock_cookie
1224  * for the high level interrupt handler.  So, the hard parameter indicates
1225  * whether or not a high level interrupt handler has been added.
1226  *
1227  * If the locks parameter is nonzero, then all mutexes, semaphores and
1228  * condition variables will be destroyed.
1229  *
1230  * Does not assume the low level mutex is held.
1231  *
1232  */
1233 static void
1234 fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard, int locks)
1235 {
1236 
1237 
1238         FDERRPRINT(FDEP_L1, FDEM_ATTA,
1239             (C, "fd_cleanup instance: %d ctlr: 0x%p\n",
1240             ddi_get_instance(dip), (void *)fdc));
1241 
1242 
1243         if (fdc == NULL) {
1244                 return;
1245         }
1246 
1247         /*
1248          * Remove interrupt handlers first before anything else
1249          * is deallocated.
1250          */
1251 
1252         /* Remove hard interrupt if one is registered */
1253         if (hard) {
1254                 ddi_remove_intr(dip, (uint_t)0, fdc->c_block);
1255         }
1256 
1257         /* Remove soft interrupt if one is registered */
1258         if (fdc->c_softid != NULL)
1259                 ddi_remove_softintr(fdc->c_softid);
1260 
1261 
1262         /* Remove timers */
1263         if (fdc->c_fdtype & FDCTYPE_82077) {
1264                 if (fdc->c_mtimeid)
1265                         (void) untimeout(fdc->c_mtimeid);
1266                 /*
1267                  * Need to turn off motor (includes select/LED for South Bridge
1268                  * chipset) just in case it was on when timer was removed
1269                  */
1270                 fdmotoff(fdc);
1271         }
1272         if (fdc->c_timeid)
1273                 (void) untimeout(fdc->c_timeid);
1274 
1275 
1276         /* Remove memory handles */
1277         if (fdc->c_handlep_cont)
1278                 ddi_regs_map_free(&fdc->c_handlep_cont);
1279 
1280         if (fdc->c_handlep_aux)
1281                 ddi_regs_map_free(&fdc->c_handlep_aux);
1282 
1283         if (fdc->c_handlep_dma)
1284                 ddi_regs_map_free(&fdc->c_handlep_dma);
1285 
1286         if (fdc->c_dma_buf_handle != NULL)
1287                 ddi_dma_mem_free(&fdc->c_dma_buf_handle);
1288 
1289         if (fdc->c_dmahandle != NULL)
1290                 ddi_dma_free_handle(&fdc->c_dmahandle);
1291 
1292 
1293         /* Remove all minor nodes */
1294         ddi_remove_minor_node(dip, NULL);
1295 
1296 
1297 
1298         /* Remove unit structure if one exists */
1299         if (fdc->c_un != (struct fdunit *)NULL) {
1300 
1301                 ASSERT(!mutex_owned(&fdc->c_lolock));
1302 
1303                 if (fdc->c_un->un_iostat)
1304                         kstat_delete(fdc->c_un->un_iostat);
1305                 fdc->c_un->un_iostat = NULL;
1306 
1307                 if (fdc->c_un->un_chars)
1308                         kmem_free(fdc->c_un->un_chars, sizeof (struct fd_char));
1309 
1310                 if (fdc->c_un->un_drive)
1311                         kmem_free(fdc->c_un->un_drive,
1312                             sizeof (struct fd_drive));
1313 
1314                 kmem_free((caddr_t)fdc->c_un, sizeof (struct fdunit));
1315         }
1316 
1317         if (fdc->c_intrstat) {
1318                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1319                     (C, "fd_cleanup: delete intrstat\n"));
1320 
1321                 kstat_delete(fdc->c_intrstat);
1322         }
1323 
1324         fdc->c_intrstat = NULL;
1325 
1326         if (locks) {
1327                 cv_destroy(&fdc->c_iocv);
1328                 cv_destroy(&fdc->c_csbcv);
1329                 cv_destroy(&fdc->c_motoncv);
1330                 cv_destroy(&fdc->c_suspend_cv);
1331                 sema_destroy(&fdc->c_ocsem);
1332                 mutex_destroy(&fdc->c_hilock);
1333                 mutex_destroy(&fdc->c_lolock);
1334         }
1335 
1336 
1337         fdctlrs = fdc->c_next;
1338         kmem_free(fdc, sizeof (*fdc));
1339 
1340 
1341 }
1342 
1343 
1344 static int
1345 fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1346 {
1347         int instance = ddi_get_instance(dip);
1348         struct fdctlr *fdc = fd_getctlr(instance << FDINSTSHIFT);
1349         timeout_id_t c_mtimeid;
1350 
1351         FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_detach\n"));
1352 
1353         switch (cmd) {
1354 
1355         case DDI_DETACH:
1356                 /*
1357                  * The hard parameter is set to 1.  If detach is called, then
1358                  * attach must have passed meaning that the high level
1359                  * interrupt handler was successfully added.
1360                  * Similarly, the locks parameter is also set to 1.
1361                  */
1362                 fd_cleanup(dip, fdc, 1, 1);
1363 
1364                 ddi_prop_remove_all(dip);
1365 
1366                 return (DDI_SUCCESS);
1367 
1368         case DDI_SUSPEND:
1369                 if (!fdc)
1370                         return (DDI_FAILURE);
1371 
1372 
1373                 mutex_enter(&fdc->c_lolock);
1374                 fdgetcsb(fdc);  /* Wait for I/O to finish */
1375                 c_mtimeid = fdc->c_mtimeid;
1376                 fdretcsb(fdc);
1377                 mutex_exit(&fdc->c_lolock);
1378 
1379                 (void) untimeout(c_mtimeid);
1380                 /*
1381                  * After suspend, the system could be powered off.
1382                  * When it is later powered on the southbridge floppy
1383                  * controller will tristate the interrupt line causing
1384                  * continuous dma interrupts.
1385                  * To avoid getting continuous fd interrupts we will remove the
1386                  * dma interrupt handler installed. We will re-install the
1387                  * handler when we RESUME.
1388                  */
1389                 if (fdc->c_fdtype & FDCTYPE_SB)
1390                         ddi_remove_intr(dip, 0, fdc->c_block);
1391 
1392                 fdc->c_un->un_state = FD_STATE_SUSPENDED;
1393 
1394                 return (DDI_SUCCESS);
1395 
1396         default:
1397                 return (DDI_FAILURE);
1398         }
1399 }
1400 
1401 /* ARGSUSED */
1402 static int
1403 fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1404 {
1405         register struct fdctlr *fdc;
1406         register int error;
1407 
1408         switch (infocmd) {
1409 
1410         case DDI_INFO_DEVT2DEVINFO:
1411                 if ((fdc = fd_getctlr((dev_t)arg)) == NULL) {
1412                         error = DDI_FAILURE;
1413                 } else {
1414                         *result = fdc->c_dip;
1415                         error = DDI_SUCCESS;
1416                 }
1417                 break;
1418 
1419         case DDI_INFO_DEVT2INSTANCE:
1420                 *result = 0;
1421                 error = DDI_SUCCESS;
1422                 break;
1423 
1424         default:
1425                 error = DDI_FAILURE;
1426         }
1427         return (error);
1428 }
1429 
1430 /*
1431  * property operation routine.  return the number of blocks for the partition
1432  * in question or forward the request to the property facilities.
1433  */
1434 static int
1435 fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1436     char *name, caddr_t valuep, int *lengthp)
1437 {
1438         struct fdunit   *un;
1439         struct fdctlr   *fdc;
1440         uint64_t        nblocks64;
1441 
1442         /*
1443          * Our dynamic properties are all device specific and size oriented.
1444          * Requests issued under conditions where size is valid are passed
1445          * to ddi_prop_op_nblocks with the size information, otherwise the
1446          * request is passed to ddi_prop_op.
1447          */
1448         if (dev == DDI_DEV_T_ANY) {
1449 pass:           return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1450                     name, valuep, lengthp));
1451         } else {
1452                 fdc = fd_getctlr(dev);
1453                 if (fdc == NULL)
1454                         goto pass;
1455 
1456                 /* we have size if diskette opened and label read */
1457                 un = fdc->c_un;
1458                 if ((un == NULL) || !fd_unit_is_open(fdc->c_un))
1459                         goto pass;
1460 
1461                 /* get nblocks value */
1462                 nblocks64 = (ulong_t)
1463                     un->un_label.dkl_map[FDPARTITION(dev)].dkl_nblk;
1464 
1465                 return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
1466                     name, valuep, lengthp, nblocks64));
1467         }
1468 }
1469 
1470 /* ARGSUSED3 */
1471 static int
1472 fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
1473 {
1474         dev_t dev;
1475         int  part;
1476         struct fdctlr *fdc;
1477         struct fdunit *un;
1478         struct dk_map32 *dkm;
1479         uchar_t pbit;
1480         int     err, part_is_open;
1481         int     unit;
1482 
1483         dev = *devp;
1484         fdc = fd_getctlr(dev);
1485         if ((fdc == NULL) || ((un = fdc->c_un) == NULL)) {
1486                 return (ENXIO);
1487         }
1488 
1489         unit = fdc->c_un->un_unit_no;
1490 
1491         /*
1492          * Serialize opens/closes
1493          */
1494 
1495         sema_p(&fdc->c_ocsem);
1496 
1497         /* check partition */
1498         part = FDPARTITION(dev);
1499         pbit = 1 << part;
1500         dkm = &un->un_label.dkl_map[part];
1501         if (dkm->dkl_nblk == 0) {
1502                 sema_v(&fdc->c_ocsem);
1503                 return (ENXIO);
1504         }
1505 
1506         FDERRPRINT(FDEP_L1, FDEM_OPEN,
1507             (C, "fdopen: ctlr %d unit %d part %d\n",
1508             ddi_get_instance(fdc->c_dip), unit, part));
1509 
1510         FDERRPRINT(FDEP_L1, FDEM_OPEN,
1511             (C, "fdopen: flag 0x%x", flag));
1512 
1513 
1514         /*
1515          * Insure that drive is present with a recalibrate on first open.
1516          */
1517         (void) pm_busy_component(fdc->c_dip, 0);
1518 
1519         mutex_enter(&fdc->c_lolock);
1520 
1521         CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
1522 
1523         if (fdc->c_un->un_state == FD_STATE_STOPPED) {
1524                 mutex_exit(&fdc->c_lolock);
1525                 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
1526                     != DDI_SUCCESS) {
1527                         FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
1528                             failed. \n"));
1529 
1530                                 sema_v(&fdc->c_ocsem);
1531                                 (void) pm_idle_component(fdc->c_dip, 0);
1532                                 return (EIO);
1533                 }
1534                 mutex_enter(&fdc->c_lolock);
1535         }
1536         if (fd_unit_is_open(un) == 0) {
1537                 fdgetcsb(fdc);
1538                 /*
1539                  * no check changed!
1540                  */
1541                 err = fdrecalseek(fdc, unit, -1, 0);
1542                 fdretcsb(fdc);
1543                 if (err) {
1544                         FDERRPRINT(FDEP_L3, FDEM_OPEN,
1545                             (C, "fd%d: drive not ready\n", 0));
1546                         /* deselect drv on last close */
1547                         fdselect(fdc, unit, 0);
1548                         mutex_exit(&fdc->c_lolock);
1549                         sema_v(&fdc->c_ocsem);
1550                         (void) pm_idle_component(fdc->c_dip, 0);
1551                         return (EIO);
1552                 }
1553         }
1554 
1555         /*
1556          * Check for previous exclusive open, or trying to exclusive open
1557          */
1558         if (otyp == OTYP_LYR) {
1559                 part_is_open = (un->un_lyropen[part] != 0);
1560         } else {
1561                 part_is_open = fd_part_is_open(un, part);
1562         }
1563         if ((un->un_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
1564                 mutex_exit(&fdc->c_lolock);
1565                 sema_v(&fdc->c_ocsem);
1566                 FDERRPRINT(FDEP_L2, FDEM_OPEN, (C, "fd:just return\n"));
1567                 (void) pm_idle_component(fdc->c_dip, 0);
1568                 return (EBUSY);
1569         }
1570 
1571         /* don't attempt access, just return successfully */
1572         if (flag & (FNDELAY | FNONBLOCK)) {
1573                 FDERRPRINT(FDEP_L2, FDEM_OPEN,
1574                     (C, "fd: return busy..\n"));
1575                 goto out;
1576         }
1577 
1578         fdc->c_csb.csb_unit = (uchar_t)unit;
1579         if (fdgetlabel(fdc, unit)) {
1580                 /* didn't find label (couldn't read anything) */
1581                 FDERRPRINT(FDEP_L3, FDEM_OPEN,
1582                     (C,
1583                     "fd%d: unformatted diskette or no diskette in the drive\n",
1584                     0));
1585                 if (fd_unit_is_open(un) == 0) {
1586                         /* deselect drv on last close */
1587                         fdselect(fdc, unit, 0);
1588                 }
1589 
1590                 mutex_exit(&fdc->c_lolock);
1591                 sema_v(&fdc->c_ocsem);
1592                 (void) pm_idle_component(fdc->c_dip, 0);
1593                 return (EIO);
1594         }
1595 
1596         /*
1597          * if opening for writing, check write protect on diskette
1598          */
1599         if (flag & FWRITE) {
1600                 fdgetcsb(fdc);
1601                 err = fdsensedrv(fdc, unit) & WP_SR3;
1602                 fdretcsb(fdc);
1603                 if (err) {
1604                         if (fd_unit_is_open(un) == 0)
1605                                 fdselect(fdc, unit, 0);
1606                         mutex_exit(&fdc->c_lolock);
1607                         sema_v(&fdc->c_ocsem);
1608                         (void) pm_idle_component(fdc->c_dip, 0);
1609                         return (EROFS);
1610                 }
1611         }
1612 
1613 out:
1614         /*
1615          * mark open as having succeeded
1616          */
1617         if (flag & FEXCL) {
1618                 un->un_exclmask |= pbit;
1619         }
1620         if (otyp == OTYP_LYR) {
1621                 un->un_lyropen[part]++;
1622         } else {
1623                 un->un_regopen[otyp] |= pbit;
1624         }
1625         mutex_exit(&fdc->c_lolock);
1626         sema_v(&fdc->c_ocsem);
1627         (void) pm_idle_component(fdc->c_dip, 0);
1628         return (0);
1629 }
1630 /*
1631  * fd_part_is_open
1632  *      return 1 if the partition is open
1633  *      return 0 otherwise
1634  */
1635 static int
1636 fd_part_is_open(struct fdunit *un, int part)
1637 {
1638         int i;
1639         for (i = 0; i < OTYPCNT - 1; i++)
1640                 if (un->un_regopen[i] & (1 << part))
1641                         return (1);
1642         return (0);
1643 }
1644 
1645 
1646 /* ARGSUSED */
1647 static int
1648 fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
1649 {
1650         int unit, part_is_closed, part;
1651         register struct fdctlr *fdc;
1652         register struct fdunit *un;
1653 
1654         fdc = fd_getctlr(dev);
1655         if (!fdc || !(un = fdc->c_un))
1656                 return (ENXIO);
1657 
1658 
1659         unit = fdc->c_un->un_unit_no;
1660         FDERRPRINT(FDEP_L1, FDEM_CLOS, (C, "fd_close\n"));
1661         part = FDPARTITION(dev);
1662 
1663         sema_p(&fdc->c_ocsem);
1664         mutex_enter(&fdc->c_lolock);
1665 
1666         if (otyp == OTYP_LYR) {
1667                 un->un_lyropen[part]--;
1668                 part_is_closed = (un->un_lyropen[part] == 0);
1669         } else {
1670                 un->un_regopen[otyp] &= ~(1<<part);
1671                 part_is_closed = 1;
1672         }
1673         if (part_is_closed)
1674                 un->un_exclmask &= ~(1<<part);
1675 
1676         if (fd_unit_is_open(un) == 0) {
1677                 /* deselect drive on last close */
1678                 fdselect(fdc, unit, 0);
1679                 un->un_flags &= ~FDUNIT_CHANGED;
1680         }
1681         mutex_exit(&fdc->c_lolock);
1682         sema_v(&fdc->c_ocsem);
1683 
1684         return (0);
1685 }
1686 
1687 /*
1688  * fd_strategy
1689  *      checks operation, hangs buf struct off fdctlr, calls fdstart
1690  *      if not already busy.  Note that if we call start, then the operation
1691  *      will already be done on return (start sleeps).
1692  */
1693 static int
1694 fd_strategy(register struct buf *bp)
1695 {
1696         struct fdctlr *fdc;
1697         struct fdunit *un;
1698         uint_t  phys_blkno;
1699         struct dk_map32 *dkm;
1700 
1701         FDERRPRINT(FDEP_L1, FDEM_STRA,
1702             (C, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
1703             (void *)bp, bp->b_edev));
1704         FDERRPRINT(FDEP_L1, FDEM_STRA,
1705             (C, "b_blkno=%x b_flags=%x b_count=%x\n",
1706             (int)bp->b_blkno, bp->b_flags, (int)bp->b_bcount));
1707         fdc = fd_getctlr(bp->b_edev);
1708         un = fdc->c_un;
1709         dkm = &un->un_label.dkl_map[FDPARTITION(bp->b_edev)];
1710 
1711         /*
1712          * If it's medium density and the block no. isn't a multiple
1713          * of 1K, then return an error.
1714          */
1715         if (un->un_chars->fdc_medium) {
1716                 phys_blkno = (uint_t)bp->b_blkno >> 1;
1717                 if (bp->b_blkno & 1) {
1718                         FDERRPRINT(FDEP_L3, FDEM_STRA,
1719                             (C, "b_blkno=0x%lx is not 1k aligned\n",
1720                             (long)bp->b_blkno));
1721                         bp->b_error = EINVAL;
1722                         bp->b_resid = bp->b_bcount;
1723                         bp->b_flags |= B_ERROR;
1724                         biodone(bp);
1725                         return (0);
1726                 }
1727         } else {
1728                 phys_blkno = (uint_t)bp->b_blkno;
1729         }
1730 
1731 
1732         /* If the block number is past the end, return an error */
1733         if ((phys_blkno > dkm->dkl_nblk)) {
1734                 FDERRPRINT(FDEP_L3, FDEM_STRA,
1735                     (C, "fd%d: block %ld is past the end! (nblk=%d)\n",
1736                     0, (long)bp->b_blkno, dkm->dkl_nblk));
1737                 bp->b_error = ENOSPC;
1738                 bp->b_resid = bp->b_bcount;
1739                 bp->b_flags |= B_ERROR;
1740                 biodone(bp);
1741                 return (0);
1742         }
1743 
1744         /* if at end of file, skip out now */
1745         if (phys_blkno == dkm->dkl_nblk) {
1746                 FDERRPRINT(FDEP_L1, FDEM_STRA,
1747                     (C, "b_blkno is at the end!\n"));
1748 
1749                 if ((bp->b_flags & B_READ) == 0) {
1750                         /* a write needs to get an error! */
1751                         bp->b_error = ENOSPC;
1752                         bp->b_flags |= B_ERROR;
1753 
1754                         FDERRPRINT(FDEP_L1, FDEM_STRA,
1755                             (C, "block is at end and this is a write\n"));
1756 
1757                 }
1758 
1759                 bp->b_resid = bp->b_bcount;
1760                 biodone(bp);
1761                 return (0);
1762         }
1763 
1764         /* if operation not a multiple of sector size, is error! */
1765         if (bp->b_bcount % un->un_chars->fdc_sec_size) {
1766                 FDERRPRINT(FDEP_L3, FDEM_STRA,
1767                     (C, "fd%d: requested transfer size(0x%lx) is not"
1768                     " multiple of sector size(0x%x)\n", 0,
1769                     bp->b_bcount, un->un_chars->fdc_sec_size));
1770                 FDERRPRINT(FDEP_L3, FDEM_STRA,
1771                     (C, "       b_blkno=0x%lx b_flags=0x%x\n",
1772                     (long)bp->b_blkno, bp->b_flags));
1773                 bp->b_error = EINVAL;
1774                 bp->b_resid = bp->b_bcount;
1775                 bp->b_flags |= B_ERROR;
1776                 biodone(bp);
1777                 return (0);
1778 
1779         }
1780 
1781         /*
1782          * Put the buf request in the controller's queue, FIFO.
1783          */
1784         bp->av_forw = 0;
1785         sema_p(&fdc->c_ocsem);
1786 
1787         (void) pm_busy_component(fdc->c_dip, 0);
1788 
1789         mutex_enter(&fdc->c_lolock);
1790 
1791         CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
1792 
1793         if (fdc->c_un->un_state == FD_STATE_STOPPED) {
1794                 mutex_exit(&fdc->c_lolock);
1795                 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
1796                     != DDI_SUCCESS) {
1797                         sema_v(&fdc->c_ocsem);
1798                         (void) pm_idle_component(fdc->c_dip, 0);
1799                         bp->b_error = EIO;
1800                         bp->b_resid = bp->b_bcount;
1801                         bp->b_flags |= B_ERROR;
1802                         biodone(bp);
1803                         return (0);
1804                 } else {
1805                         mutex_enter(&fdc->c_lolock);
1806                 }
1807         }
1808         if (un->un_iostat) {
1809                 kstat_waitq_enter(KIOSP);
1810         }
1811         if (fdc->c_actf)
1812                 fdc->c_actl->av_forw = bp;
1813         else
1814                 fdc->c_actf = bp;
1815         fdc->c_actl = bp;
1816 
1817 
1818         /* call fdstart to start the transfer */
1819         fdstart(fdc);
1820 
1821         mutex_exit(&fdc->c_lolock);
1822         sema_v(&fdc->c_ocsem);
1823         (void) pm_idle_component(fdc->c_dip, 0);
1824         return (0);
1825 }
1826 
1827 /* ARGSUSED2 */
1828 static int
1829 fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
1830 {
1831         FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_read\n"));
1832         return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
1833 }
1834 
1835 /* ARGSUSED2 */
1836 static int
1837 fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
1838 {
1839         FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_write\n"));
1840         return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
1841 }
1842 
1843 static void
1844 fdmotoff(void *arg)
1845 {
1846         struct fdctlr *fdc = arg;
1847         int unit = fdc->c_un->un_unit_no;
1848 
1849         mutex_enter(&fdc->c_lolock);
1850 
1851         /* Just return if we're about to call untimeout */
1852         if (fdc->c_mtimeid == 0) {
1853                 mutex_exit(&fdc->c_lolock);
1854                 return;
1855         }
1856 
1857         FDERRPRINT(FDEP_L1, FDEM_MOFF, (C, "fdmotoff\n"));
1858 
1859         fdc->c_mtimeid = 0;
1860 
1861         if (!(Msr(fdc) & CB) && (Dor(fdc) & (MOTEN(unit)))) {
1862                 /* LINTED */
1863                 Set_dor(fdc, MOTEN(unit), 0);
1864         }
1865 
1866         mutex_exit(&fdc->c_lolock);
1867 }
1868 
1869 /* ARGSUSED */
1870 static int
1871 fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
1872         cred_t *cred_p, int *rval_p)
1873 {
1874         union {
1875                 struct dk_cinfo dki;
1876                 struct dk_geom dkg;
1877                 struct dk_allmap32 dka;
1878                 struct fd_char fdchar;
1879                 struct fd_drive drvchar;
1880                 int     temp;
1881         } cpy;
1882 
1883         struct vtoc     vtoc;
1884         struct fdunit *un;
1885         struct fdctlr *fdc;
1886         int unit, dkunit;
1887         int err = 0;
1888         uint_t  sec_size;
1889         enum dkio_state state;
1890         int     transfer_rate;
1891 
1892         FDERRPRINT(FDEP_L1, FDEM_IOCT,
1893             (C, "fd_ioctl: cmd 0x%x, arg 0x%lx\n", cmd, (long)arg));
1894 
1895         /* The minor number should always be 0 */
1896         if (FDUNIT(dev) != 0)
1897                 return (ENXIO);
1898 
1899         fdc = fd_getctlr(dev);
1900         unit = fdc->c_un->un_unit_no;
1901         un = fdc->c_un;
1902         sec_size = un->un_chars->fdc_sec_size;
1903         bzero(&cpy, sizeof (cpy));
1904 
1905         switch (cmd) {
1906         case DKIOCINFO:
1907                 cpy.dki.dki_addr = 0;
1908 
1909                 /*
1910                  * The meaning of the dki_slave and dki_unit fields
1911                  * is unclear.  The sparc floppy driver follows the same
1912                  * convention as sd.c in that the instance number is
1913                  * returned in the dki_cnum field.  The dki_slave field is
1914                  * ignored.
1915                  *
1916                  * The dki_cnum contains the controller instance
1917                  * and its value can be any positive number. Even
1918                  * though currently Sparc platforms only support
1919                  * one controller, the controller instance number
1920                  * can be any number since it is assigned by the
1921                  * system depending on the device properties.
1922                  */
1923 
1924                 cpy.dki.dki_cnum = FDCTLR(dev);
1925 
1926                 /*
1927                  * Sparc platforms support only one floppy drive.
1928                  * The device node for the controller is the same as
1929                  * the device node for the drive.  The x86 driver is
1930                  * different in that it has a node for the controller
1931                  * and a child node for each drive. Since Sparc supports
1932                  * only one drive, the unit number will always be zero.
1933                  */
1934 
1935                 cpy.dki.dki_unit = FDUNIT(dev);
1936 
1937                 /*
1938                  * The meaning of the dki_slave field is unclear.
1939                  * So, I will leave it set to 0.
1940                  */
1941 
1942                 cpy.dki.dki_slave = 0;
1943 
1944                 cpy.dki.dki_ctype = (ushort_t)-1;
1945                 if (fdc->c_fdtype & FDCTYPE_82077)
1946                         cpy.dki.dki_ctype = DKC_INTEL82077;
1947                 cpy.dki.dki_flags = DKI_FMTTRK;
1948                 cpy.dki.dki_partition = FDPARTITION(dev);
1949                 cpy.dki.dki_maxtransfer = maxphys / DEV_BSIZE;
1950                 if (ddi_copyout((caddr_t)&cpy.dki, (caddr_t)arg,
1951                     sizeof (cpy.dki), flag))
1952                         err = EFAULT;
1953                 break;
1954         case DKIOCGGEOM:
1955                 cpy.dkg.dkg_ncyl = un->un_chars->fdc_ncyl;
1956                 cpy.dkg.dkg_nhead = un->un_chars->fdc_nhead;
1957                 cpy.dkg.dkg_nsect = un->un_chars->fdc_secptrack;
1958                 cpy.dkg.dkg_intrlv = un->un_label.dkl_intrlv;
1959                 cpy.dkg.dkg_rpm = un->un_label.dkl_rpm;
1960                 cpy.dkg.dkg_pcyl = un->un_chars->fdc_ncyl;
1961                 cpy.dkg.dkg_read_reinstruct =
1962                     (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
1963                 cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
1964                 if (ddi_copyout((caddr_t)&cpy.dkg, (caddr_t)arg,
1965                     sizeof (cpy.dkg), flag))
1966                         err = EFAULT;
1967                 break;
1968         case DKIOCSGEOM:
1969                 FDERRPRINT(FDEP_L3, FDEM_IOCT,
1970                     (C, "fd_ioctl: DKIOCSGEOM not supported\n"));
1971                 err = ENOTTY;
1972                 break;
1973 
1974         /*
1975          * return the map of all logical partitions
1976          */
1977         case DKIOCGAPART:
1978                 /*
1979                  * We don't have anything to do if the application is ILP32
1980                  * because the label map has a 32-bit format. Otherwise
1981                  * convert.
1982                  */
1983                 if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
1984                         if (ddi_copyout(&un->un_label.dkl_map,
1985                             (void *)arg, sizeof (struct dk_allmap32), flag))
1986                                 err = EFAULT;
1987                 }
1988 #ifdef _MULTI_DATAMODEL
1989                 else {
1990                         struct dk_allmap dk_allmap;
1991 
1992                         ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
1993                         for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
1994                                 dk_allmap.dka_map[dkunit].dkl_cylno =
1995                                     un->un_label.dkl_map[dkunit].dkl_cylno;
1996                                 dk_allmap.dka_map[dkunit].dkl_nblk =
1997                                     un->un_label.dkl_map[dkunit].dkl_nblk;
1998                         }
1999                         if (ddi_copyout(&dk_allmap, (void *)arg,
2000                             sizeof (struct dk_allmap), flag))
2001                                 err = EFAULT;
2002                 }
2003 #endif /* _MULTI_DATAMODEL */
2004                 break;
2005 
2006         /*
2007          * Set the map of all logical partitions
2008          */
2009         case DKIOCSAPART:
2010                 if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2011                         if (ddi_copyin((const void *)arg, &cpy.dka,
2012                             sizeof (cpy.dka), flag))
2013                                 return (EFAULT);
2014                         else {
2015                                 mutex_enter(&fdc->c_lolock);
2016                                 for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
2017                                         un->un_label.dkl_map[dkunit] =
2018                                             cpy.dka.dka_map[dkunit];
2019                                 }
2020                                 mutex_exit(&fdc->c_lolock);
2021                         }
2022                 }
2023 #ifdef _MULTI_DATAMODEL
2024                 else {
2025                         struct dk_allmap dk_allmap;
2026 
2027                         ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
2028                         if (ddi_copyin((const void *)arg, &dk_allmap,
2029                             sizeof (dk_allmap), flag))
2030                                 return (EFAULT);
2031                         else {
2032                                 mutex_enter(&fdc->c_lolock);
2033                                 for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
2034                                         un->un_label.dkl_map[dkunit].dkl_cylno =
2035                                             dk_allmap.dka_map[dkunit].dkl_cylno;
2036                                         un->un_label.dkl_map[dkunit].dkl_nblk =
2037                                             dk_allmap.dka_map[dkunit].dkl_nblk;
2038                                 }
2039                                 mutex_exit(&fdc->c_lolock);
2040                         }
2041                 }
2042 #endif /* _MULTI_DATAMODEL */
2043                 break;
2044 
2045         case DKIOCGVTOC:
2046                 mutex_enter(&fdc->c_lolock);
2047 
2048                 /*
2049                  * Exit if the diskette has no label.
2050                  * Also, get the label to make sure the
2051                  * correct one is being used since the diskette
2052                  * may have changed
2053                  */
2054                 if (fdgetlabel(fdc, unit)) {
2055                         mutex_exit(&fdc->c_lolock);
2056                         err = EINVAL;
2057                         break;
2058                 }
2059 
2060                 /* Build a vtoc from the diskette's label */
2061                 fd_build_user_vtoc(un, &vtoc);
2062                 mutex_exit(&fdc->c_lolock);
2063 
2064 #ifdef _MULTI_DATAMODEL
2065                 switch (ddi_model_convert_from(flag & FMODELS)) {
2066                 case DDI_MODEL_ILP32: {
2067                         struct vtoc32 vtoc32;
2068 
2069                         vtoctovtoc32(vtoc, vtoc32);
2070                         if (ddi_copyout(&vtoc32, (void *)arg,
2071                             sizeof (struct vtoc32), flag))
2072                                 return (EFAULT);
2073                         break;
2074                 }
2075 
2076                 case DDI_MODEL_NONE:
2077                         if (ddi_copyout(&vtoc, (void *)arg,
2078                             sizeof (vtoc), flag))
2079                                 return (EFAULT);
2080                         break;
2081                 }
2082 #else /* ! _MULTI_DATAMODEL */
2083                 if (ddi_copyout(&vtoc, (void *)arg, sizeof (vtoc), flag))
2084                         return (EFAULT);
2085 #endif /* _MULTI_DATAMODEL */
2086                 break;
2087 
2088         case DKIOCSVTOC:
2089 
2090 #ifdef _MULTI_DATAMODEL
2091                 switch (ddi_model_convert_from(flag & FMODELS)) {
2092                 case DDI_MODEL_ILP32: {
2093                         struct vtoc32 vtoc32;
2094 
2095                         if (ddi_copyin((const void *)arg, &vtoc32,
2096                             sizeof (struct vtoc32), flag)) {
2097                                 return (EFAULT);
2098                         }
2099                         vtoc32tovtoc(vtoc32, vtoc);
2100                         break;
2101                 }
2102 
2103                 case DDI_MODEL_NONE:
2104                         if (ddi_copyin((const void *)arg, &vtoc,
2105                             sizeof (vtoc), flag)) {
2106                                 return (EFAULT);
2107                         }
2108                         break;
2109                 }
2110 #else /* ! _MULTI_DATAMODEL */
2111                 if (ddi_copyin((const void *)arg, &vtoc, sizeof (vtoc), flag))
2112                         return (EFAULT);
2113 #endif /* _MULTI_DATAMODEL */
2114 
2115                 mutex_enter(&fdc->c_lolock);
2116 
2117                 /*
2118                  * The characteristics structure must be filled in because
2119                  * it helps build the vtoc.
2120                  */
2121                 if ((un->un_chars->fdc_ncyl == 0) ||
2122                     (un->un_chars->fdc_nhead == 0) ||
2123                     (un->un_chars->fdc_secptrack == 0)) {
2124                         mutex_exit(&fdc->c_lolock);
2125                         err = EINVAL;
2126                         break;
2127                 }
2128 
2129                 if ((err = fd_build_label_vtoc(un, &vtoc)) != 0) {
2130                         mutex_exit(&fdc->c_lolock);
2131                         break;
2132                 }
2133 
2134                 (void) pm_busy_component(fdc->c_dip, 0);
2135 
2136                 err = fdrw(fdc, unit, FDWRITE, 0, 0, 1,
2137                     (caddr_t)&un->un_label, sizeof (struct dk_label));
2138                 mutex_exit(&fdc->c_lolock);
2139                 (void) pm_idle_component(fdc->c_dip, 0);
2140                 break;
2141 
2142         case DKIOCSTATE:
2143                 if (ddi_copyin((caddr_t)arg, (caddr_t)&state,
2144                     sizeof (int), flag)) {
2145                         err = EFAULT;
2146                         break;
2147                 }
2148                 (void) pm_busy_component(fdc->c_dip, 0);
2149 
2150                 err = fd_check_media(dev, state);
2151                 (void) pm_idle_component(fdc->c_dip, 0);
2152 
2153                 if (ddi_copyout((caddr_t)&un->un_media_state,
2154                     (caddr_t)arg, sizeof (int), flag))
2155                         err = EFAULT;
2156                 break;
2157 
2158         case FDIOGCHAR:
2159                 if (ddi_copyout((caddr_t)un->un_chars, (caddr_t)arg,
2160                     sizeof (struct fd_char), flag))
2161                         err = EFAULT;
2162                 break;
2163 
2164         case FDIOSCHAR:
2165                 if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.fdchar,
2166                                 sizeof (struct fd_char), flag)) {
2167                         err = EFAULT;
2168                         break;
2169                 }
2170 
2171                 /*
2172                  * Check the fields in the fdchar structure that are either
2173                  * driver or controller dependent.
2174                  */
2175 
2176                 transfer_rate = cpy.fdchar.fdc_transfer_rate;
2177                 if ((transfer_rate != 500) && (transfer_rate != 300) &&
2178                     (transfer_rate != 250) && (transfer_rate != 1000)) {
2179                         FDERRPRINT(FDEP_L3, FDEM_IOCT,
2180                             (C, "fd_ioctl: FDIOSCHAR odd transfer rate %d\n",
2181                             cpy.fdchar.fdc_transfer_rate));
2182                         err = EINVAL;
2183                         break;
2184                 }
2185 
2186                 if ((cpy.fdchar.fdc_nhead < 1) ||
2187                     (cpy.fdchar.fdc_nhead > 2)) {
2188                         FDERRPRINT(FDEP_L3, FDEM_IOCT,
2189                             (C, "fd_ioctl: FDIOSCHAR bad no. of heads %d\n",
2190                             cpy.fdchar.fdc_nhead));
2191                         err = EINVAL;
2192                         break;
2193                 }
2194 
2195                 /*
2196                  * The number of cylinders must be between 0 and 255
2197                  */
2198                 if ((cpy.fdchar.fdc_ncyl < 0) || (cpy.fdchar.fdc_ncyl > 255)) {
2199                         FDERRPRINT(FDEP_L3, FDEM_IOCT,
2200                             (C, "fd_ioctl: FDIOSCHAR bad cyl no %d\n",
2201                             cpy.fdchar.fdc_ncyl));
2202                         err = EINVAL;
2203                         break;
2204                 }
2205 
2206                 /* Copy the fdchar structure */
2207 
2208                 mutex_enter(&fdc->c_lolock);
2209                 *(un->un_chars) = cpy.fdchar;
2210 
2211                 un->un_curfdtype = -1;
2212 
2213                 mutex_exit(&fdc->c_lolock);
2214 
2215                 break;
2216         case FDEJECT:  /* eject disk */
2217         case DKIOCEJECT:
2218 
2219                 /*
2220                  * Fail the ioctl if auto-eject isn't supported
2221                  */
2222                 if (fdc->c_un->un_drive->fdd_ejectable == 0) {
2223 
2224                         err = ENOSYS;
2225 
2226                 } else {
2227                         (void) pm_busy_component(fdc->c_dip, 0);
2228 
2229                         mutex_enter(&fdc->c_lolock);
2230 
2231                         CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2232 
2233                         if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2234                                 mutex_exit(&fdc->c_lolock);
2235                                 if ((pm_raise_power(fdc->c_dip, 0,
2236                                     PM_LEVEL_ON)) != DDI_SUCCESS) {
2237                                         (void) pm_idle_component(fdc->c_dip, 0);
2238                                         err = EIO;
2239                                 }
2240                                 mutex_enter(&fdc->c_lolock);
2241                         }
2242                 }
2243                 if (err == 0) {
2244                         fdselect(fdc, unit, 1);
2245                         fdeject(fdc, unit);
2246                         mutex_exit(&fdc->c_lolock);
2247                 }
2248 
2249                 (void) pm_idle_component(fdc->c_dip, 0);
2250 
2251                 /*
2252                  * Make sure the drive is turned off
2253                  */
2254                 if (fdc->c_fdtype & FDCTYPE_82077) {
2255                         if (fdc->c_mtimeid == 0) {
2256                                 fdc->c_mtimeid = timeout(fdmotoff, fdc,
2257                                     Motoff_delay);
2258                         }
2259                 }
2260 
2261                 break;
2262         case FDGETCHANGE: /* disk changed */
2263 
2264                 if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.temp,
2265                     sizeof (int), flag)) {
2266                         err = EFAULT;
2267                         break;
2268                 }
2269 
2270                 /* zero out the user's parameter */
2271                 cpy.temp = 0;
2272 
2273                 (void) pm_busy_component(fdc->c_dip, 0);
2274 
2275                 mutex_enter(&fdc->c_lolock);
2276 
2277                 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2278 
2279                 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2280                         mutex_exit(&fdc->c_lolock);
2281                         if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
2282                             != DDI_SUCCESS) {
2283                                 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
2284                                     change failed. \n"));
2285                                 (void) pm_idle_component(fdc->c_dip, 0);
2286                                 return (EIO);
2287                         }
2288 
2289                         mutex_enter(&fdc->c_lolock);
2290                 }
2291                 if (un->un_flags & FDUNIT_CHANGED)
2292                         cpy.temp |= FDGC_HISTORY;
2293                 else
2294                         cpy.temp &= ~FDGC_HISTORY;
2295                 un->un_flags &= ~FDUNIT_CHANGED;
2296 
2297                 if (fd_pollable) {
2298                         /*
2299                          * If it's a "pollable" floppy, then we don't
2300                          * have to do all the fdcheckdisk nastyness to
2301                          * figure out if the thing is still there.
2302                          */
2303                         if (fdsense_chng(fdc, unit)) {
2304                                 cpy.temp |= FDGC_CURRENT;
2305                         } else {
2306                                 cpy.temp &= ~FDGC_CURRENT;
2307                         }
2308                 } else {
2309 
2310                         if (fdsense_chng(fdc, unit)) {
2311                                 /*
2312                                  * check disk change signal is asserted.
2313                                  * Now find out if the floppy is
2314                                  * inserted
2315                                  */
2316                                 if (fdcheckdisk(fdc, unit)) {
2317                                         cpy.temp |= FDGC_CURRENT;
2318                                 } else {
2319                                         /*
2320                                          * Yes, the floppy was
2321                                          * reinserted. Implies
2322                                          * floppy change.
2323                                          */
2324                                         cpy.temp &= ~FDGC_CURRENT;
2325                                         cpy.temp |= FDGC_HISTORY;
2326                                 }
2327                         } else {
2328                                 cpy.temp &= ~FDGC_CURRENT;
2329                         }
2330                 }
2331 
2332                 /*
2333                  * For a pollable floppy, the floppy_change signal
2334                  * reflects whether the floppy is in there or not.
2335                  * We can not detect a floppy change if we don't poll
2336                  * this signal when the floppy is being changed.
2337                  * Because as soon as the floppy is put back, the
2338                  * signal is reset.
2339                  * BUT the pollable floppies are available only on
2340                  * Sparcstation Voyager Voyagers (Gypsy) only and
2341                  * those are motorized floppies. For motorized floppies,
2342                  * the floppy can only (assuming the user doesn't use a
2343                  * pin to take out the floppy) be taken out by
2344                  * issuing 'eject' command which sets the
2345                  * un->un_ejected flag. So, if the following
2346                  * condition is true, we can assume there
2347                  * was a floppy change.
2348                  */
2349                 if (un->un_ejected && !(cpy.temp & FDGC_CURRENT)) {
2350                         cpy.temp |= FDGC_HISTORY;
2351                 }
2352                 un->un_ejected = 0;
2353 
2354 
2355                 /* return the write-protection status */
2356                 fdgetcsb(fdc);
2357                 if (fdsensedrv(fdc, unit) & WP_SR3) {
2358                         cpy.temp |= FDGC_CURWPROT;
2359                 }
2360                 fdretcsb(fdc);
2361                 mutex_exit(&fdc->c_lolock);
2362 
2363                 if (ddi_copyout((caddr_t)&cpy.temp, (caddr_t)arg,
2364                     sizeof (int), flag))
2365                         err = EFAULT;
2366                 (void) pm_idle_component(fdc->c_dip, 0);
2367                 break;
2368 
2369         case FDGETDRIVECHAR:
2370 
2371                 if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.drvchar,
2372                                 sizeof (struct fd_drive), flag)) {
2373                         err = EFAULT;
2374                         break;
2375                 }
2376 
2377                 /*
2378                  * Return the ejectable value based on the FD_MANUAL_EJECT
2379                  * property
2380                  */
2381                 cpy.drvchar.fdd_ejectable = fdc->c_un->un_drive->fdd_ejectable;
2382                 cpy.drvchar.fdd_maxsearch = nfdtypes; /* 3 - hi m lo density */
2383                 if (fd_pollable)        /* pollable device */
2384                         cpy.drvchar.fdd_flags |= FDD_POLLABLE;
2385 
2386                 /* the rest of the fd_drive struct is meaningless to us */
2387 
2388                 if (ddi_copyout((caddr_t)&cpy.drvchar, (caddr_t)arg,
2389                     sizeof (struct fd_drive), flag))
2390                         err = EFAULT;
2391                 break;
2392 
2393         case FDSETDRIVECHAR:
2394                 FDERRPRINT(FDEP_L3, FDEM_IOCT,
2395                     (C, "fd_ioctl: FDSETDRIVECHAR not supportedn\n"));
2396                 err = ENOTTY;
2397                 break;
2398 
2399         case DKIOCREMOVABLE: {
2400                 int     i = 1;
2401 
2402                 /* no brainer: floppies are always removable */
2403                 if (ddi_copyout((caddr_t)&i, (caddr_t)arg, sizeof (int),
2404                     flag)) {
2405                         err = EFAULT;
2406                 }
2407                 break;
2408         }
2409         case DKIOCGMEDIAINFO:
2410                 err = fd_get_media_info(un, (caddr_t)arg, flag);
2411                 break;
2412 
2413 
2414         case FDIOCMD:
2415         {
2416                 struct fd_cmd fc;
2417                 int cyl, hd, spc, spt;
2418                 int nblks; /* total no. of blocks */
2419 
2420 #ifdef _MULTI_DATAMODEL
2421                 switch (ddi_model_convert_from(flag & FMODELS)) {
2422                 case DDI_MODEL_ILP32: {
2423                         struct fd_cmd32 fc32;
2424 
2425                         if (ddi_copyin((const void *)arg, &fc32,
2426                             sizeof (fc32), flag)) {
2427                                 return (EFAULT);
2428                         }
2429                         fc.fdc_cmd      = fc32.fdc_cmd;
2430                         fc.fdc_flags    = fc32.fdc_flags;
2431                         fc.fdc_blkno    = (daddr_t)fc32.fdc_blkno;
2432                         fc.fdc_secnt    = fc32.fdc_secnt;
2433                         fc.fdc_bufaddr  = (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
2434                         fc.fdc_buflen   = fc32.fdc_buflen;
2435                         fc.fdc_cmd      = fc32.fdc_cmd;
2436 
2437                         break;
2438                 }
2439 
2440                 case DDI_MODEL_NONE:
2441                         if (ddi_copyin((const void *)arg, &fc,
2442                             sizeof (fc), flag)) {
2443                                 return (EFAULT);
2444                         }
2445                         break;
2446                 }
2447 #else /* ! _MULTI_DATAMODEL */
2448                 if (ddi_copyin((const void *)arg, &fc, sizeof (fc), flag)) {
2449                         return (EFAULT);
2450                 }
2451 #endif /* _MULTI_DATAMODEL */
2452 
2453                 if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
2454                         auto struct iovec aiov;
2455                         auto struct uio auio;
2456                         struct uio *uio = &auio;
2457 
2458                         spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
2459 
2460                         bzero(&auio, sizeof (struct uio));
2461                         bzero(&aiov, sizeof (struct iovec));
2462                         aiov.iov_base = fc.fdc_bufaddr;
2463                         aiov.iov_len = (uint_t)fc.fdc_secnt * sec_size;
2464                         uio->uio_iov = &aiov;
2465 
2466                         uio->uio_iovcnt = 1;
2467                         uio->uio_resid = aiov.iov_len;
2468                         uio->uio_segflg = UIO_USERSPACE;
2469                         FDERRPRINT(FDEP_L2, FDEM_IOCT,
2470                             (C, "fd_ioctl: call physio\n"));
2471                         err = physio(fd_strategy, NULL, dev,
2472                             spc, minphys, uio);
2473                         break;
2474                 } else if (fc.fdc_cmd != FDCMD_FORMAT_TRACK) {
2475 
2476                         /*
2477                          * The manpage states that only the FDCMD_WRITE,
2478                          * FDCMD_READ, and the FDCMD_FORMAT_TR are available.
2479                          */
2480                         FDERRPRINT(FDEP_L1, FDEM_IOCT,
2481                             (C, "fd_ioctl: FDIOCMD invalid command\n"));
2482                         err = EINVAL;
2483                         break;
2484                 }
2485 
2486                 /* The command is FDCMD_FORMAT_TRACK */
2487 
2488                 spt = un->un_chars->fdc_secptrack;        /* sec/trk */
2489                 spc = un->un_chars->fdc_nhead * spt;      /* sec/cyl */
2490                 cyl = fc.fdc_blkno / spc;
2491                 hd = (fc.fdc_blkno % spc) / spt;
2492 
2493                 /*
2494                  * Make sure the specified block number is in the correct
2495                  * range. (block numbers start at 0)
2496                  */
2497                 nblks = spc * un->un_chars->fdc_ncyl;
2498 
2499                 if (fc.fdc_blkno < 0 || fc.fdc_blkno > (nblks - 1)) {
2500                         err = EINVAL;
2501                         break;
2502                 }
2503 
2504                 (void) pm_busy_component(fdc->c_dip, 0);
2505 
2506                 mutex_enter(&fdc->c_lolock);
2507                 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2508                 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2509                         mutex_exit(&fdc->c_lolock);
2510                         if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
2511                             != DDI_SUCCESS) {
2512                                 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
2513                                     change failed. \n"));
2514                                 (void) pm_idle_component(fdc->c_dip, 0);
2515                                 return (EIO);
2516                         }
2517 
2518                         mutex_enter(&fdc->c_lolock);
2519                 }
2520 
2521                 if (fdformat(fdc, unit, cyl, hd))
2522                         err = EIO;
2523 
2524                 mutex_exit(&fdc->c_lolock);
2525                 (void) pm_idle_component(fdc->c_dip, 0);
2526 
2527                 break;
2528         }
2529 
2530         case FDRAW:
2531 
2532                 (void) pm_busy_component(fdc->c_dip, 0);
2533                 err = fdrawioctl(fdc, unit, arg, flag);
2534 
2535                 (void) pm_idle_component(fdc->c_dip, 0);
2536 
2537                 break;
2538 #ifdef FD_DEBUG
2539         case IOCTL_DEBUG:
2540                 fderrlevel--;
2541                 if (fderrlevel < 0)
2542                         fderrlevel = 3;
2543                 cmn_err(C, "fdioctl: CHANGING debug to %d", fderrlevel);
2544                 return (0);
2545 #endif /* FD_DEBUG */
2546         default:
2547                 FDERRPRINT(FDEP_L2, FDEM_IOCT,
2548                     (C, "fd_ioctl: invalid ioctl 0x%x\n", cmd));
2549                 err = ENOTTY;
2550                 break;
2551         }
2552 
2553         return (err);
2554 }
2555 
2556 /*
2557  * fdrawioctl
2558  *
2559  *      - acquires the low level lock
2560  */
2561 
2562 static int
2563 fdrawioctl(struct fdctlr *fdc, int unit, intptr_t arg, int mode)
2564 {
2565         struct fd_raw fdr;
2566 #ifdef _MULTI_DATAMODEL
2567         struct fd_raw32 fdr32;
2568 #endif
2569         struct fdcsb *csb;
2570         int i, err, flag;
2571         caddr_t fa;
2572         uint_t  fc;
2573         size_t  real_length;
2574         int     res;
2575         ddi_device_acc_attr_t attr;
2576         ddi_acc_handle_t        mem_handle;
2577 
2578         attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2579         attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
2580         attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2581 
2582         ASSERT(fdc->c_un->un_unit_no == unit);
2583 
2584         flag = B_READ;
2585         err = 0;
2586         fa = NULL;
2587         fc = (uint_t)0;
2588 
2589         /* Copy in the arguments */
2590         switch (ddi_model_convert_from(mode)) {
2591 #ifdef _MULTI_DATAMODEL
2592         case DDI_MODEL_ILP32:
2593                 if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr32,
2594                     sizeof (fdr32), mode)) {
2595                         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2596                             (C, "fdrawioctl: copyin error, args32\n"));
2597                         return (EFAULT);
2598                 }
2599                 bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
2600                 fdr.fdr_cnum = fdr32.fdr_cnum;
2601                 bcopy(fdr32.fdr_result, fdr.fdr_result,
2602                     sizeof (fdr.fdr_result));
2603                 fdr.fdr_nbytes = fdr32.fdr_nbytes;
2604                 fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
2605                 break;
2606 #endif
2607         default:
2608         case DDI_MODEL_NONE:
2609                 if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr,
2610                     sizeof (fdr), mode)) {
2611                         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2612                             (C, "fdrawioctl: copyin error, args\n"));
2613                         return (EFAULT);
2614                 }
2615                 break;
2616         }
2617 
2618         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2619             (C, "fdrawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
2620 
2621         mutex_enter(&fdc->c_lolock);
2622 
2623         CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2624 
2625         if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2626                 mutex_exit(&fdc->c_lolock);
2627                 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
2628                     != DDI_SUCCESS) {
2629                         FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
2630                             failed. \n"));
2631 
2632                         (void) pm_idle_component(fdc->c_dip, 0);
2633                         return (EIO);
2634                 }
2635                 mutex_enter(&fdc->c_lolock);
2636         }
2637 
2638         fdgetcsb(fdc);
2639         csb = &fdc->c_csb;
2640         csb->csb_unit = (uchar_t)unit;
2641 
2642         /* copy cmd bytes into csb */
2643         for (i = 0; i <= fdr.fdr_cnum; i++)
2644                 csb->csb_cmds[i] = fdr.fdr_cmd[i];
2645         csb->csb_ncmds = (uchar_t)fdr.fdr_cnum;
2646 
2647         csb->csb_maxretry = 0;       /* let the application deal with errors */
2648         csb->csb_retrys = 0;
2649 
2650         switch (fdr.fdr_cmd[0] & 0x0f) {
2651 
2652         case FDRAW_SPECIFY:
2653                 /*
2654                  * Ensure that the right DMA mode is selected.  There is
2655                  * currently no way for the user to tell if DMA is
2656                  * happening so set the value for the user.
2657                  */
2658 
2659                 if (fdc->c_fdtype & FDCTYPE_DMA)
2660                         csb->csb_cmds[2] = csb->csb_cmds[2] & 0xFE;
2661                 else
2662                         csb->csb_cmds[2] = csb->csb_cmds[2] | 0x1;
2663 
2664                 csb->csb_opflags = CSB_OFNORESULTS;
2665                 csb->csb_nrslts = 0;
2666                 break;
2667 
2668         case FDRAW_SENSE_DRV:
2669                 /* Insert the appropriate drive number */
2670                 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2671                 csb->csb_opflags = CSB_OFIMMEDIATE;
2672                 csb->csb_nrslts = 1;
2673                 break;
2674 
2675         case FDRAW_REZERO:
2676         case FDRAW_SEEK:
2677                 /* Insert the appropriate drive number */
2678                 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2679                 csb->csb_opflags = CSB_OFSEEKOPS + CSB_OFTIMEIT;
2680                 csb->csb_nrslts = 2;
2681                 break;
2682 
2683         case FDRAW_FORMAT:
2684                 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2685                     (C, "fdrawioctl: cmd is fdfraw format\n"));
2686 
2687                 /* Insert the appropriate drive number */
2688                 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2689                 csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
2690                 csb->csb_nrslts = NRBRW;
2691                 flag = B_WRITE;
2692 
2693                 /*
2694                  * Allocate memory for the command.
2695                  * If PIO is being used, then add an extra 16 bytes
2696                  */
2697                 if (fdc->c_fdtype & FDCTYPE_DMA) {
2698 
2699                         fc = (uint_t)(fdr.fdr_nbytes);
2700                         mutex_enter(&fdc->c_hilock);
2701 
2702                         res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
2703                             &attr, DDI_DMA_STREAMING,
2704                             DDI_DMA_DONTWAIT, 0, &fa, &real_length,
2705                             &mem_handle);
2706 
2707                         if (res != DDI_SUCCESS) {
2708                                 fdretcsb(fdc);
2709                                 mutex_exit(&fdc->c_lolock);
2710                                 mutex_exit(&fdc->c_hilock);
2711                                 return (EIO);
2712                         }
2713 
2714                         fdc->c_csb.csb_read = CSB_WRITE;
2715                         if (fdstart_dma(fdc, fa, fc) != 0) {
2716                                 ddi_dma_mem_free(&mem_handle);
2717                                 fdretcsb(fdc);
2718                                 mutex_exit(&fdc->c_lolock);
2719                                 mutex_exit(&fdc->c_hilock);
2720                                 return (EIO);
2721                         }
2722                         mutex_exit(&fdc->c_hilock);
2723 
2724                 } else {
2725                         fc = (uint_t)(fdr.fdr_nbytes + 16);
2726                         fa = kmem_zalloc(fc, KM_SLEEP);
2727                 }
2728 
2729                 /* copy in the user's command bytes */
2730                 if (ddi_copyin(fdr.fdr_addr, fa,
2731                     (uint_t)fdr.fdr_nbytes, mode)) {
2732                         fdretcsb(fdc);
2733                         mutex_exit(&fdc->c_lolock);
2734 
2735                         if (fdc->c_fdtype & FDCTYPE_DMA) {
2736                                 ddi_dma_mem_free(&mem_handle);
2737                                 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2738                                     (C, "fdrawioctl: (err)free dma memory\n"));
2739                         } else {
2740                                 kmem_free(fa, fc);
2741                         }
2742 
2743                         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2744                             (C, "fdrawioctl: ddi_copyin error\n"));
2745                         return (EFAULT);
2746                 }
2747 
2748                 break;
2749         case FDRAW_WRCMD:
2750         case FDRAW_WRITEDEL:
2751                 flag = B_WRITE;
2752                 /* FALLTHROUGH */
2753         case FDRAW_RDCMD:
2754         case FDRAW_READDEL:
2755         case FDRAW_READTRACK:
2756                 /* Insert the appropriate drive number */
2757                 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2758                 if (fdc->c_fdtype & FDCTYPE_SB)
2759                         csb->csb_cmds[1] |= IPS;
2760                 csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
2761                 csb->csb_nrslts = NRBRW;
2762                 break;
2763 
2764         default:
2765                 fdretcsb(fdc);
2766                 mutex_exit(&fdc->c_lolock);
2767                 return (EINVAL);
2768         }
2769 
2770         if ((csb->csb_opflags & CSB_OFXFEROPS) && (fdr.fdr_nbytes == 0)) {
2771                 fdretcsb(fdc);
2772                 mutex_exit(&fdc->c_lolock);
2773                 return (EINVAL);
2774         }
2775         csb->csb_opflags |= CSB_OFRAWIOCTL;
2776 
2777         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2778             (C, "fdrawioctl: nbytes = %u\n", fdr.fdr_nbytes));
2779 
2780         if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT) {
2781                 if ((fc = (uint_t)fdr.fdr_nbytes) > 0) {
2782                         /*
2783                          * In SunOS 4.X, we used to as_fault things in.
2784                          * We really cannot do this in 5.0/SVr4. Unless
2785                          * someone really believes that speed is of the
2786                          * essence here, it is just much simpler to do
2787                          * this in kernel space and use copyin/copyout.
2788                          */
2789                         if (fdc->c_fdtype & FDCTYPE_DMA) {
2790                                 mutex_enter(&fdc->c_hilock);
2791                                 res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
2792                                     &attr, DDI_DMA_STREAMING,
2793                                     DDI_DMA_DONTWAIT, 0, &fa, &real_length,
2794                                     &mem_handle);
2795 
2796                                 if (res != DDI_SUCCESS) {
2797                                         fdretcsb(fdc);
2798                                         mutex_exit(&fdc->c_lolock);
2799                                         mutex_exit(&fdc->c_hilock);
2800                                         return (EIO);
2801                                 }
2802 
2803                                 if (flag == B_WRITE)
2804                                         fdc->c_csb.csb_read = CSB_WRITE;
2805                                 else
2806                                         fdc->c_csb.csb_read = CSB_READ;
2807 
2808                                 if (fdstart_dma(fdc, fa, fc) != 0) {
2809                                         ddi_dma_mem_free(&mem_handle);
2810                                         fdretcsb(fdc);
2811                                         mutex_exit(&fdc->c_lolock);
2812                                         mutex_exit(&fdc->c_hilock);
2813                                         return (EIO);
2814                                 }
2815                                 mutex_exit(&fdc->c_hilock);
2816 
2817                         } else {
2818                                 fa = kmem_zalloc(fc, KM_SLEEP);
2819                         }
2820 
2821                         if (flag == B_WRITE) {
2822                                 if (ddi_copyin(fdr.fdr_addr, fa, fc, mode)) {
2823                                         if (fdc->c_fdtype & FDCTYPE_DMA)
2824                                                 ddi_dma_mem_free(&mem_handle);
2825                                         else
2826                                                 kmem_free(fa, fc);
2827                                         fdretcsb(fdc);
2828                                         mutex_exit(&fdc->c_lolock);
2829                                         FDERRPRINT(FDEP_L1, FDEM_RAWI, (C,
2830                                             "fdrawioctl: can't copy data\n"));
2831 
2832                                         return (EFAULT);
2833                                 }
2834                         }
2835                         csb->csb_addr = fa;
2836                         csb->csb_len = fc;
2837                 } else {
2838                         csb->csb_addr = 0;
2839                         csb->csb_len = 0;
2840                 }
2841         } else {
2842                 csb->csb_addr = fa;
2843                 csb->csb_len = fc;
2844         }
2845 
2846         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2847             (C, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmds[0],
2848             csb->csb_cmds[1], csb->csb_cmds[2], csb->csb_cmds[3],
2849             csb->csb_cmds[4], csb->csb_cmds[5], csb->csb_cmds[6],
2850             csb->csb_cmds[7], csb->csb_cmds[8], csb->csb_cmds[9]));
2851         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2852             (C, "nbytes: %x, opflags: %x, addr: %p, len: %x\n",
2853             csb->csb_ncmds, csb->csb_opflags, (void *)csb->csb_addr,
2854             csb->csb_len));
2855 
2856 
2857         /*
2858          * Note that we ignore any error return s from fdexec.
2859          * This is the way the driver has been, and it may be
2860          * that the raw ioctl senders simply don't want to
2861          * see any errors returned in this fashion.
2862          */
2863 
2864         if ((csb->csb_opflags & CSB_OFNORESULTS) ||
2865             (csb->csb_opflags & CSB_OFIMMEDIATE)) {
2866                 (void) fdexec(fdc, 0); /* don't sleep, don't check change */
2867         } else {
2868                 (void) fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG);
2869         }
2870 
2871 
2872         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2873             (C, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0],
2874             csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3],
2875             csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6],
2876             csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9]));
2877 
2878         if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT && fc &&
2879             flag == B_READ && err == 0) {
2880                 if (ddi_copyout(fa, fdr.fdr_addr, fc, mode)) {
2881                         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2882                             (C, "fdrawioctl: can't copy read data\n"));
2883 
2884                         err = EFAULT;
2885                 }
2886         }
2887 
2888 
2889         if (fc) {
2890                 if (fdc->c_fdtype & FDCTYPE_DMA) {
2891                         ddi_dma_mem_free(&mem_handle);
2892                         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2893                             (C, "fdrawioctl: free dma memory\n"));
2894                 } else {
2895                         kmem_free(fa, fc);
2896                 }
2897         }
2898 
2899 
2900         /* copy cmd results into fdr */
2901         for (i = 0; (int)i <= (int)csb->csb_nrslts; i++)
2902                 fdr.fdr_result[i] = csb->csb_rslt[i];
2903         fdr.fdr_nbytes = fdc->c_csb.csb_rlen; /* return resid */
2904 
2905         switch (ddi_model_convert_from(mode)) {
2906 #ifdef _MULTI_DATAMODEL
2907         case DDI_MODEL_ILP32:
2908                 bcopy(fdr.fdr_cmd, fdr32.fdr_cmd, sizeof (fdr32.fdr_cmd));
2909                 fdr32.fdr_cnum = fdr.fdr_cnum;
2910                 bcopy(fdr.fdr_result, fdr32.fdr_result,
2911                     sizeof (fdr32.fdr_result));
2912                 fdr32.fdr_nbytes = fdr.fdr_nbytes;
2913                 fdr32.fdr_addr = (caddr32_t)(uintptr_t)fdr.fdr_addr;
2914                 if (ddi_copyout(&fdr32, (caddr_t)arg, sizeof (fdr32), mode)) {
2915                         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2916                             (C, "fdrawioctl: can't copy results32\n"));
2917                         err = EFAULT;
2918                 }
2919                 break;
2920 #endif
2921         case DDI_MODEL_NONE:
2922         default:
2923                 if (ddi_copyout(&fdr, (caddr_t)arg, sizeof (fdr), mode)) {
2924                         FDERRPRINT(FDEP_L1, FDEM_RAWI,
2925                             (C, "fdrawioctl: can't copy results\n"));
2926                         err = EFAULT;
2927                 }
2928                 break;
2929         }
2930 
2931         fdretcsb(fdc);
2932         mutex_exit(&fdc->c_lolock);
2933         return (0);
2934 }
2935 
2936 /*
2937  * fdformat
2938  *      format a track
2939  * For PIO, builds a table of sector data values with 16 bytes
2940  * (sizeof fdc's fifo) of dummy on end.  This is so than when fdc->c_len
2941  * goes to 0 and fd_intr sends a TC that all the real formatting will
2942  * have already been done.
2943  *
2944  *      - called with the low level lock held
2945  */
2946 static int
2947 fdformat(struct fdctlr *fdc, int unit, int cyl, int hd)
2948 {
2949         struct fdcsb *csb;
2950         struct fdunit *un;
2951         struct fd_char *ch;
2952         int     cmdresult;
2953         uchar_t *fmthdrs;
2954         caddr_t fd;
2955         int     i;
2956         size_t  real_length;
2957         ddi_device_acc_attr_t attr;
2958         ddi_acc_handle_t mem_handle;
2959 
2960         FDERRPRINT(FDEP_L1, FDEM_FORM,
2961             (C, "fdformat cyl %d, hd %d\n", cyl, hd));
2962         fdgetcsb(fdc);
2963 
2964         ASSERT(fdc->c_un->un_unit_no == unit);
2965 
2966         csb = &fdc->c_csb;
2967         un = fdc->c_un;
2968         ch = un->un_chars;
2969 
2970         /* setup common things in csb */
2971         csb->csb_unit = (uchar_t)unit;
2972 
2973         /*
2974          * The controller needs to do a seek before
2975          * each format to get to right cylinder.
2976          */
2977         if (fdrecalseek(fdc, unit, cyl, FDXC_CHECKCHG)) {
2978                 fdretcsb(fdc);
2979                 return (EIO);
2980         }
2981 
2982         /*
2983          * now do the format itself
2984          */
2985         csb->csb_nrslts = NRBRW;
2986         csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
2987 
2988         csb->csb_cmds[0] = FDRAW_FORMAT;
2989         /* always or in MFM bit */
2990         csb->csb_cmds[0] |= MFM;
2991         csb->csb_cmds[1] = (hd << 2) | (unit & 0x03);
2992         csb->csb_cmds[2] = ch->fdc_medium ? 3 : 2;
2993         csb->csb_cmds[3] = ch->fdc_secptrack;
2994         csb->csb_cmds[4] = GPLF;
2995         csb->csb_cmds[5] = FDATA;
2996         csb->csb_ncmds = 6;
2997         csb->csb_maxretry = rwretry;
2998         csb->csb_retrys = 0;
2999 
3000         /*
3001          * NOTE: have to add size of fifo also - for dummy format action
3002          * if PIO is being used.
3003          */
3004 
3005 
3006         if (fdc->c_fdtype & FDCTYPE_DMA) {
3007 
3008                 csb->csb_len = (uint_t)4 * ch->fdc_secptrack;
3009 
3010                 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
3011                 attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
3012                 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
3013 
3014                 mutex_enter(&fdc->c_hilock);
3015 
3016                 cmdresult = ddi_dma_mem_alloc(fdc->c_dmahandle, csb->csb_len,
3017                     &attr, DDI_DMA_STREAMING,
3018                     DDI_DMA_DONTWAIT, 0, &fd, &real_length,
3019                     &mem_handle);
3020 
3021                 if (cmdresult != DDI_SUCCESS) {
3022                         mutex_exit(&fdc->c_hilock);
3023                         return (cmdresult);
3024                 }
3025 
3026                 fdc->c_csb.csb_read = CSB_WRITE;
3027                 if (fdstart_dma(fdc, fd,  csb->csb_len) != 0) {
3028                         ddi_dma_mem_free(&mem_handle);
3029                         mutex_exit(&fdc->c_hilock);
3030                         return (-1);
3031                 }
3032                 mutex_exit(&fdc->c_hilock);
3033 
3034 
3035         } else {
3036                 csb->csb_len = (uint_t)4 * ch->fdc_secptrack + 16;
3037                 fd = kmem_zalloc(csb->csb_len, KM_SLEEP);
3038                 fmthdrs = (uchar_t *)fd;
3039         }
3040 
3041         csb->csb_addr = (caddr_t)fd;
3042 
3043         for (i = 1; i <= ch->fdc_secptrack; i++) {
3044                 *fd++ = (uchar_t)cyl;           /* cylinder */
3045                 *fd++ = (uchar_t)hd;            /* head */
3046                 *fd++ = (uchar_t)i;     /* sector number */
3047                 *fd++ = ch->fdc_medium ? 3 : 2; /* sec_size code */
3048         }
3049 
3050         if ((cmdresult = fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG)) == 0) {
3051                 if (csb->csb_cmdstat)
3052                         cmdresult = EIO;        /* XXX TBD NYD for now */
3053         }
3054 
3055         if (fdc->c_fdtype & FDCTYPE_DMA) {
3056                 ddi_dma_mem_free(&mem_handle);
3057         } else {
3058                 kmem_free((caddr_t)fmthdrs, csb->csb_len);
3059         }
3060 
3061         fdretcsb(fdc);
3062 
3063         return (cmdresult);
3064 }
3065 
3066 /*
3067  * fdstart
3068  *      called from fd_strategy() or from fdXXXX() to setup and
3069  *      start operations of read or write only (using buf structs).
3070  *      Because the chip doesn't handle crossing cylinder boundaries on
3071  *      the fly, this takes care of those boundary conditions.  Note that
3072  *      it sleeps until the operation is done *within fdstart* - so that
3073  *      when fdstart returns, the operation is already done.
3074  *
3075  *      - called with the low level lock held
3076  *
3077  */
3078 
3079 static int slavio_index_pulse_work_around = 0;
3080 
3081 static void
3082 fdstart(struct fdctlr *fdc)
3083 {
3084         struct buf *bp;
3085         struct fdcsb *csb;
3086         struct fdunit *un;
3087         struct fd_char *ch;
3088         struct dk_map32 *dkm;
3089         uint_t  part;           /* partition number for the transfer */
3090         uint_t  start_part;     /* starting block of the partition */
3091         uint_t  last_part;      /* last block of the partition */
3092         uint_t  blk;            /* starting block of transfer on diskette */
3093         uint_t  sect;           /* starting block's offset into track */
3094         uint_t  cyl;            /* starting cylinder of the transfer */
3095         uint_t  bincyl;         /* starting blocks's offset into cylinder */
3096         uint_t  secpcyl;        /* number of sectors per cylinder */
3097         uint_t  phys_blkno;     /* no. of blocks on the diskette */
3098         uint_t  head;           /* one of two diskette heads */
3099         uint_t  unit;
3100         uint_t  len, tlen;
3101         caddr_t addr;
3102         caddr_t temp_addr;
3103         uint_t  partial_read = 0;
3104         int sb_temp_buf_used = 0;
3105 
3106         bp = fdc->c_actf;
3107 
3108         while (bp != NULL) {
3109 
3110                 fdc->c_actf = bp->av_forw;
3111                 fdc->c_current = bp;
3112 
3113                 /*
3114                  * Initialize the buf structure.  The residual count is
3115                  * initially the number of bytes to be read or written
3116                  */
3117                 bp->b_flags &= ~B_ERROR;
3118                 bp->b_error = 0;
3119                 bp->b_resid = bp->b_bcount;
3120                 bp_mapin(bp);                   /* map in buffers */
3121 
3122                 addr = bp->b_un.b_addr;              /* assign buffer address */
3123 
3124                 /*
3125                  * Find the unit and partition numbers.
3126                  */
3127                 unit = fdc->c_un->un_unit_no;
3128                 un = fdc->c_un;
3129                 ch = un->un_chars;
3130                 part = FDPARTITION(bp->b_edev);
3131                 dkm = &un->un_label.dkl_map[part];
3132 
3133                 if (un->un_chars->fdc_medium) {
3134                         phys_blkno = bp->b_blkno >> 1;
3135                 } else {
3136                         phys_blkno = bp->b_blkno;
3137                 }
3138 
3139                 if (un->un_iostat) {
3140                         kstat_waitq_to_runq(KIOSP);
3141                 }
3142 
3143                 FDERRPRINT(FDEP_L1, FDEM_STRT,
3144                     (C, "fdstart: bp=0x%p blkno=0x%x bcount=0x%x\n",
3145                     (void *)bp, (int)bp->b_blkno, (int)bp->b_bcount));
3146 
3147                 /*
3148                  * Get the csb and initialize the values that are the same
3149                  * for DMA and PIO.
3150                  */
3151                 fdgetcsb(fdc);          /* get csb (maybe wait for it) */
3152                 csb = &fdc->c_csb;
3153                 csb->csb_unit = unit;                /* floppy unit number */
3154 
3155 
3156                 /*
3157                  * bugID:4133425 : If the controller is SLAVIO, and
3158                  * the read does not reach end of track, then modify
3159                  * the tlen to read until the end of track to a temp
3160                  * buffer and disable MT. After the read is over,
3161                  * copy the useful portion of the data to 'addr'.
3162                  * Enable this feature only when
3163                  * slavio_index_pulse_work_aound variable is
3164                  * set in /etc/system.
3165                  */
3166 
3167 
3168                 if (bp->b_flags & B_READ) {
3169                         if (((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
3170                             slavio_index_pulse_work_around) ||
3171                             (fdc->c_fdtype & FDCTYPE_TCBUG))
3172                                 csb->csb_cmds[0] = SK | FDRAW_RDCMD | MFM;
3173                         else
3174                                 csb->csb_cmds[0] = MT | SK | FDRAW_RDCMD | MFM;
3175                 } else {
3176                         if (fdc->c_fdtype & FDCTYPE_TCBUG)
3177                                 csb->csb_cmds[0] = FDRAW_WRCMD | MFM;
3178                         else
3179                                 csb->csb_cmds[0] = MT | FDRAW_WRCMD | MFM;
3180                 }
3181 
3182 
3183                 if (bp->b_flags & B_READ)
3184                         fdc->c_csb.csb_read = CSB_READ;
3185                 else
3186                         fdc->c_csb.csb_read = CSB_WRITE;
3187 
3188 
3189                 csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size  */
3190                 csb->csb_cmds[6] = ch->fdc_secptrack; /* EOT-# of sectors/trk */
3191                 csb->csb_cmds[7] = GPLN;     /* GPL - gap 3 size code */
3192                 csb->csb_cmds[8] = SSSDTL;   /* DTL - be 0xFF if N != 0 */
3193 
3194                 csb->csb_ncmds = NCBRW;              /* number of command bytes */
3195                 csb->csb_nrslts = NRBRW;     /* number of result bytes */
3196 
3197 
3198                 /*
3199                  * opflags for interrupt handler, et.al.
3200                  */
3201                 csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
3202 
3203 
3204                 /*
3205                  * Make sure the transfer does not go off the end
3206                  * of the partition.  Limit the actual amount transferred
3207                  * to fit the partition.
3208                  */
3209 
3210                 blk = phys_blkno;
3211                 start_part = (dkm->dkl_cylno * ch->fdc_secptrack
3212                     * ch->fdc_nhead);
3213                 blk = blk + start_part;
3214                 last_part = start_part + dkm->dkl_nblk;
3215 
3216                 if ((blk + (bp->b_bcount / ch->fdc_sec_size)) > last_part)
3217                         len = (last_part - blk) * ch->fdc_sec_size;
3218                 else
3219                         len = (uint_t)bp->b_bcount;
3220 
3221                 /*
3222                  * now we have the real start blk,
3223                  * addr and len for xfer op
3224                  * sectors per cylinder
3225                  */
3226                 secpcyl = ch->fdc_nhead * ch->fdc_secptrack;
3227 
3228                 /*
3229                  * The controller can transfer up to a cylinder at a time.
3230                  * Early revs of the 82077 have a bug that causes the chip to
3231                  * fail to respond to the Terminal Count signal.  Due to this
3232                  * bug, controllers with type FDCTYPE_TCBUG, only transfer up
3233                  * to a track at a time.
3234                  * See earlier comment for bugID:4133425 for index pulse
3235                  * work around.
3236                  */
3237 
3238                 while (len != 0) {
3239 
3240                         cyl = blk / secpcyl;    /* cylinder of transfer */
3241                         bincyl = blk % secpcyl; /* blk within cylinder */
3242                         head = bincyl / ch->fdc_secptrack;
3243                         sect = (bincyl % ch->fdc_secptrack) + 1;
3244                                                 /* sect w/in track */
3245 
3246                         /*
3247                          * If the desired block and length will go beyond the
3248                          * cylinder end, limit it to the cylinder end.
3249                          */
3250 
3251                         if ((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
3252                             slavio_index_pulse_work_around &&
3253                             (fdc->c_csb.csb_read == CSB_READ)) {
3254 
3255                                 tlen = (ch->fdc_secptrack - sect + 1) *
3256                                     ch->fdc_sec_size;
3257                                 if (len < tlen) {
3258                                         partial_read = 1;
3259                                         temp_addr = (caddr_t)kmem_alloc(tlen,
3260                                             KM_SLEEP);
3261                                 }
3262 
3263                         } else if (fdc->c_fdtype & FDCTYPE_TCBUG) {
3264                                 tlen = len;
3265                                 if (len > ((ch->fdc_secptrack - sect + 1) *
3266                                     ch->fdc_sec_size))
3267                                         tlen = (ch->fdc_secptrack - sect + 1)
3268                                             * ch->fdc_sec_size;
3269                         } else {
3270                                 if (len > ((secpcyl - bincyl)
3271                                     * ch->fdc_sec_size))
3272                                         tlen = (secpcyl - bincyl)
3273                                             * ch->fdc_sec_size;
3274 
3275                                 else
3276                                         tlen = len;
3277                         }
3278                         if (fdc->c_fdtype & FDCTYPE_SB) {
3279                                 /*
3280                                  * To avoid underrun errors during IFB activity.
3281                                  */
3282                                 if (tlen > max_fd_dma_len)
3283                                         tlen = max_fd_dma_len;
3284                         }
3285 
3286                         FDERRPRINT(FDEP_L1, FDEM_STRT,
3287                             (C, "       blk 0x%x, addr 0x%p, len 0x%x\n",
3288                             blk, (void *)addr, len));
3289                         FDERRPRINT(FDEP_L1, FDEM_STRT,
3290                             (C, "cyl:%x, head:%x, sec:%x\n",
3291                             cyl, head, sect));
3292 
3293                         FDERRPRINT(FDEP_L1, FDEM_STRT,
3294                             (C, "       resid 0x%lx, tlen %d\n",
3295                             bp->b_resid, tlen));
3296 
3297                         /*
3298                          * Finish programming the command
3299                          */
3300                         csb->csb_cmds[1] = (head << 2) | unit;
3301                         if (fdc->c_fdtype & FDCTYPE_SB)
3302                                 csb->csb_cmds[1] |= IPS;
3303 
3304                         csb->csb_cmds[2] = cyl;      /* C - cylinder address */
3305                         csb->csb_cmds[3] = head;     /* H - head number */
3306                         csb->csb_cmds[4] = sect;     /* R - sector number */
3307                         if (fdc->c_fdtype & FDCTYPE_TCBUG)
3308                                 csb->csb_cmds[6] = sect +
3309                                     (tlen / ch->fdc_sec_size) - 1;
3310 
3311                         csb->csb_len = tlen;
3312                         if (partial_read)
3313                                 csb->csb_addr = temp_addr;
3314                         else
3315                                 csb->csb_addr = addr;
3316 
3317                         /* retry this many times max */
3318                         csb->csb_maxretry = rwretry;
3319                         csb->csb_retrys = 0;
3320 
3321                         /* If platform supports DMA, set up DMA resources */
3322                         if (fdc->c_fdtype & FDCTYPE_DMA) {
3323                                 if ((fdc->c_fdtype & FDCTYPE_SB) &&
3324                                     (((uint32_t)(uintptr_t)addr & 0xFFFF0000) !=
3325                                     (((uint32_t)(uintptr_t)addr + tlen) &
3326                                     0xFFFF0000))) {
3327                                         csb->csb_addr = fdc->dma_buf;
3328                                         sb_temp_buf_used = 1;
3329                                         if (csb->csb_read != CSB_READ) {
3330                                                 bcopy(addr, fdc->dma_buf, tlen);
3331                                 }
3332                         }
3333                                 mutex_enter(&fdc->c_hilock);
3334 
3335                                 if (fdstart_dma(fdc, csb->csb_addr,
3336                                     tlen) != 0) {
3337 
3338                                         bp->b_flags |= B_ERROR;
3339                                         bp->b_error = EAGAIN;
3340 
3341                                         mutex_exit(&fdc->c_hilock);
3342                                         FDERRPRINT(FDEP_L1, FDEM_STRT,
3343                                             (C, "fdstart: no dma resources\n"));
3344 
3345                                         break;
3346                                 }
3347                                 mutex_exit(&fdc->c_hilock);
3348 
3349                         }
3350 
3351                         bp->b_error = fdexec(fdc, FDXC_SLEEP|FDXC_CHECKCHG);
3352                         if (bp->b_error != 0) {
3353                                 /*
3354                                  * error in fdexec
3355                                  */
3356                                 FDERRPRINT(FDEP_L1, FDEM_STRT, (C,
3357                                     "fdstart: bad exec of bp: 0x%p, err %d\n",
3358                                     (void *)bp, bp->b_error));
3359 
3360                                 bp->b_flags |= B_ERROR;
3361                                 if (partial_read) {
3362                                         partial_read = 0;
3363                                         kmem_free(temp_addr, tlen);
3364                                 }
3365                                 break;
3366                         }
3367 
3368                         /*
3369                          * If it was a partial read, copy the useful
3370                          * portion of data to 'addr'.
3371                          */
3372                         if (partial_read) {
3373                                 partial_read = 0;
3374                                 bcopy(temp_addr, addr, len);
3375                                 kmem_free(temp_addr, tlen);
3376                                 tlen = len;
3377                         }
3378                         if ((fdc->c_fdtype & FDCTYPE_SB) &&
3379                             (csb->csb_read == CSB_READ)) {
3380                                 if (sb_temp_buf_used) {
3381                                         bcopy(fdc->dma_buf, addr, tlen);
3382                                         sb_temp_buf_used = 0;
3383                                 }
3384                         }
3385 
3386                         blk += tlen / ch->fdc_sec_size;
3387                         len -= tlen;
3388                         addr += tlen;
3389                         bp->b_resid -= tlen;
3390 
3391                 }
3392 
3393                 FDERRPRINT(FDEP_L1, FDEM_STRT,
3394                     (C, "fdstart done: b_resid %lu, b_count %lu, csb_rlen %d\n",
3395                     bp->b_resid, bp->b_bcount, fdc->c_csb.csb_rlen));
3396 
3397                 fdc->c_current = 0;
3398                 fdretcsb(fdc);
3399                 if (un->un_iostat) {
3400                         if (bp->b_flags & B_READ) {
3401                                 KIOSP->reads++;
3402                                 KIOSP->nread +=
3403                                     (bp->b_bcount - bp->b_resid);
3404                         } else {
3405                                 KIOSP->writes++;
3406                                 KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
3407                         }
3408                         kstat_runq_exit(KIOSP);
3409                 }
3410                 biodone(bp);
3411 
3412                 /*
3413                  * Look at the next buffer
3414                  */
3415                 bp = fdc->c_actf;
3416 
3417         }
3418 }
3419 
3420 /*
3421  * Set up DMA resources
3422  * The DMA handle was initialized in fd_attach()
3423  * Assumes the handle has already been allocated by fd_attach()
3424  */
3425 static int
3426 fdstart_dma(struct fdctlr *fdc, caddr_t addr, uint_t len)
3427 {
3428         int             flags;          /* flags for setting up resources */
3429         int             res;
3430 
3431         FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: start\n"));
3432 
3433         if (fdc->c_csb.csb_read == CSB_READ) {
3434                 flags = DDI_DMA_READ;
3435         } else {
3436                 flags = DDI_DMA_WRITE;
3437         }
3438 
3439 
3440         /* allow partial mapping to maximize the portability of the driver */
3441         flags = flags | DDI_DMA_PARTIAL;
3442 
3443         FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: amt. asked for %d\n",
3444             len));
3445 
3446         /*
3447          * Zero out the current cookie.  This is done to ensure that
3448          * the previous transfers cookie information can in no way be
3449          * used.
3450          */
3451         bzero((char *)&fdc->c_csb.csb_dmacookie,
3452             sizeof (fdc->c_csb.csb_dmacookie));
3453         fdc->c_csb.csb_nwin = 0;
3454         fdc->c_csb.csb_windex = 0;
3455         fdc->c_csb.csb_ccount = 0;
3456 
3457         res = ddi_dma_addr_bind_handle(fdc->c_dmahandle, NULL, addr, len,
3458             flags, DDI_DMA_DONTWAIT, 0,  &fdc->c_csb.csb_dmacookie,
3459             &fdc->c_csb.csb_ccount);
3460 
3461         switch (res) {
3462                 case DDI_DMA_MAPPED:
3463                         /*
3464                          * There is one window. csb_windex is the index
3465                          * into the array of windows. If there are n
3466                          * windows then, (0 <= windex <= n-1).  csb_windex
3467                          * represents the index of the next window
3468                          * to be processed.
3469                          */
3470                         fdc->c_csb.csb_nwin = 1;
3471                         fdc->c_csb.csb_windex = 1;
3472 
3473 
3474                         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3475                             (C, "fdstart_dma: DDI_DMA_MAPPED\n"));
3476 
3477                         break;
3478                 case DDI_DMA_PARTIAL_MAP:
3479 
3480                         /*
3481                          * obtain the number of DMA windows
3482                          */
3483                         if (ddi_dma_numwin(fdc->c_dmahandle,
3484                             &fdc->c_csb.csb_nwin) != DDI_SUCCESS) {
3485                                 return (-1);
3486                         }
3487 
3488 
3489                         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3490                             (C, "fdstart_dma: partially mapped %d windows\n",
3491                             fdc->c_csb.csb_nwin));
3492 
3493                         /*
3494                          * The DMA window currently in use is window number
3495                          * one.
3496                          */
3497                         fdc->c_csb.csb_windex = 1;
3498 
3499                         break;
3500                 case DDI_DMA_NORESOURCES:
3501                         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3502                             (C, "fdstart_dma: no resources\n"));
3503                         return (-1);
3504                 case DDI_DMA_NOMAPPING:
3505                         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3506                             (C, "fdstart_dma: no mapping\n"));
3507                         return (-1);
3508                 case DDI_DMA_TOOBIG:
3509                         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3510                             (C, "fdstart_dma: too big\n"));
3511                         return (-1);
3512 
3513                 case DDI_DMA_INUSE:
3514                         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3515                             (C, "fdstart_dma: dma inuse\n"));
3516                         return (-1);
3517                 default:
3518                         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3519                             (C, "fdstart_dma: result is 0x%x\n", res));
3520                         return (-1);
3521 
3522         };
3523 
3524         FDERRPRINT(FDEP_L1, FDEM_SDMA,
3525             (C, "fdstart_dma: bound the handle\n"));
3526 
3527         ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
3528 
3529         FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: done\n"));
3530         return (0);
3531 }
3532 
3533 
3534 /*
3535  * fd_unbind_handle: unbind a dma handle if one exists
3536  *              return EIO if unbind failes
3537  */
3538 static int
3539 fd_unbind_handle(struct fdctlr *fdc)
3540 {
3541         if ((fdc->c_fdtype & FDCTYPE_DMA) &&
3542             ((fdc->c_csb.csb_read == CSB_READ) ||
3543             (fdc->c_csb.csb_read == CSB_WRITE))) {
3544                 mutex_enter(&fdc->c_hilock);
3545 
3546                 if (fdc->c_fdtype & FDCTYPE_SB) {
3547                         if (fdc->sb_dma_lock) {
3548                                 release_sb_dma(fdc);
3549                         }
3550                 }
3551 
3552                 /*
3553                  * If the byte count isn't zero, then the DMA engine is
3554                  * still doing a transfer.  If the byte count is nonzero,
3555                  * reset the DMA engine to cause it to drain.
3556                  */
3557 
3558                 if (get_data_count_register(fdc) != 0) {
3559                         FDERRPRINT(FDEP_L1, FDEM_EXEC,
3560                             (C, "unbind & byte count isn't zero\n"));
3561 
3562                         reset_dma_controller(fdc);
3563                         set_dma_control_register(fdc, DCSR_INIT_BITS);
3564                 }
3565 
3566                 if (ddi_dma_unbind_handle(fdc->c_dmahandle) != DDI_SUCCESS) {
3567                         FDERRPRINT(FDEP_L1, FDEM_EXEC,
3568                             (C, "problem unbinding the handle\n"));
3569                         mutex_exit(&fdc->c_hilock);
3570                         return (EIO);
3571                 }
3572                 mutex_exit(&fdc->c_hilock);
3573         }
3574         return (0);
3575 }
3576 
3577 /*
3578  * fdexec
3579  *      all commands go through here.  Assumes the command block
3580  *      fdctlr.c_csb is filled in.  The bytes are sent to the
3581  *      controller and then we do whatever else the csb says -
3582  *      like wait for immediate results, etc.
3583  *
3584  *      All waiting for operations done is in here - to allow retrys
3585  *      and checking for disk changed - so we don't have to worry
3586  *      about sleeping at interrupt level.
3587  *
3588  * RETURNS: 0 if all ok,
3589  *      ENXIO - diskette not in drive
3590  *      EBUSY - if chip is locked or busy
3591  *      EIO - for timeout during sending cmds to chip
3592  *
3593  * to sleep: set FDXC_SLEEP, to check for disk
3594  * changed: set FDXC_CHECKCHG
3595  *
3596  *      - called with the lock held
3597  */
3598 static int
3599 fdexec(struct fdctlr *fdc, int flags)
3600 {
3601         struct fdcsb *csb;
3602         int     i;
3603         int     to, unit;
3604         uchar_t tmp;
3605         caddr_t a = (caddr_t)fdc;
3606 
3607         FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: flags:%x\n", flags));
3608 
3609         ASSERT(mutex_owned(&fdc->c_lolock));
3610 
3611         csb = &fdc->c_csb;
3612         unit = csb->csb_unit;
3613 
3614 
3615         ASSERT(unit == fdc->c_un->un_unit_no);
3616 
3617 retry:
3618         FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: cmd is %s\n",
3619             fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
3620         FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: transfer rate = %d\n",
3621             fdc->c_un->un_chars->fdc_transfer_rate));
3622         FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: sec size = %d\n",
3623             fdc->c_un->un_chars->fdc_sec_size));
3624         FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: nblocks (512) = %d\n",
3625             fdc->c_un->un_label.dkl_map[2].dkl_nblk));
3626 
3627         if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
3628                 fdexec_turn_on_motor(fdc, flags, unit);
3629         }
3630 
3631 
3632         fdselect(fdc, unit, 1); /* select drive */
3633 
3634         /*
3635          * select data rate for this unit/command
3636          */
3637         switch (fdc->c_un->un_chars->fdc_transfer_rate) {
3638         case 500:
3639                 Dsr(fdc, 0);
3640                 break;
3641         case 300:
3642                 Dsr(fdc, 1);
3643                 break;
3644         case 250:
3645                 Dsr(fdc, 2);
3646                 break;
3647         }
3648         drv_usecwait(2);
3649 
3650 
3651         /*
3652          * If checking for changed is enabled (i.e., not seeking in checkdisk),
3653          * we sample the DSKCHG line to see if the diskette has wandered away.
3654          */
3655         if ((flags & FDXC_CHECKCHG) && fdsense_chng(fdc, unit)) {
3656                 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "diskette changed\n"));
3657                 fdc->c_un->un_flags |= FDUNIT_CHANGED;
3658 
3659                 if (fdcheckdisk(fdc, unit)) {
3660 
3661                         (void) fd_unbind_handle(fdc);
3662                         return (ENXIO);
3663 
3664                 }
3665         }
3666 
3667         /*
3668          * gather some statistics
3669          */
3670         switch (csb->csb_cmds[0] & 0x1f) {
3671         case FDRAW_RDCMD:
3672                 fdc->fdstats.rd++;
3673                 break;
3674         case FDRAW_WRCMD:
3675                 fdc->fdstats.wr++;
3676                 break;
3677         case FDRAW_REZERO:
3678                 fdc->fdstats.recal++;
3679                 break;
3680         case FDRAW_FORMAT:
3681                 fdc->fdstats.form++;
3682                 break;
3683         default:
3684                 fdc->fdstats.other++;
3685                 break;
3686         }
3687 
3688         /*
3689          * Always set the opmode *prior* to poking the chip.
3690          * This way we don't have to do any locking at high level.
3691          */
3692         csb->csb_raddr = 0;
3693         csb->csb_rlen = 0;
3694         if (csb->csb_opflags & CSB_OFSEEKOPS) {
3695                 csb->csb_opmode = 2;
3696         } else if (csb->csb_opflags & CSB_OFIMMEDIATE) {
3697                 csb->csb_opmode = 0;
3698         } else {
3699                 csb->csb_opmode = 1; /* normal data xfer commands */
3700                 csb->csb_raddr = csb->csb_addr;
3701                 csb->csb_rlen = csb->csb_len;
3702         }
3703 
3704         bzero((caddr_t)csb->csb_rslt, 10);
3705         csb->csb_status = 0;
3706         csb->csb_cmdstat = 0;
3707 
3708 
3709         /*
3710          * Program the DMA engine with the length and address of the transfer
3711          * (DMA is only used on a read or a write)
3712          */
3713         if ((fdc->c_fdtype & FDCTYPE_DMA) &&
3714             ((fdc->c_csb.csb_read == CSB_READ) ||
3715             (fdc->c_csb.csb_read == CSB_WRITE)))  {
3716                 mutex_enter(&fdc->c_hilock);
3717 
3718                 /* Reset the dcsr to clear it of all errors */
3719 
3720                 reset_dma_controller(fdc);
3721 
3722                 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie addr 0x%p\n",
3723                     (void *)fdc->c_csb.csb_dmacookie.dmac_laddress));
3724 
3725                 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie length %ld\n",
3726                     fdc->c_csb.csb_dmacookie.dmac_size));
3727                 ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
3728 
3729                 set_data_count_register(fdc,
3730                     fdc->c_csb.csb_dmacookie.dmac_size);
3731                 set_data_address_register(fdc,
3732                     fdc->c_csb.csb_dmacookie.dmac_laddress);
3733 
3734                 /* Program the DCSR */
3735 
3736                 if (fdc->c_csb.csb_read == CSB_READ)
3737                         set_dma_mode(fdc, CSB_READ);
3738                 else
3739                         set_dma_mode(fdc, CSB_WRITE);
3740                 mutex_exit(&fdc->c_hilock);
3741         }
3742 
3743         /*
3744          * I saw this (chip unexpectedly busy) happen when i shoved the
3745          * floppy into the drive while
3746          * running a dd if= /dev/rfd0c. so it *is* possible for this to happen.
3747          * we need to do a ctlr reset ...
3748          */
3749 
3750         if (Msr(fdc) & CB) {
3751                 /* tried to give command to chip when it is busy! */
3752                 FDERRPRINT(FDEP_L3, FDEM_EXEC,
3753                     (C, "fdc: unexpectedly busy-stat 0x%x\n", Msr(fdc)));
3754                 csb->csb_cmdstat = 1;        /* XXX TBD ERRS NYD for now */
3755 
3756                 (void) fd_unbind_handle(fdc);
3757                 return (EBUSY);
3758         }
3759 
3760         /* Give command to the controller */
3761         for (i = 0; i < (int)csb->csb_ncmds; i++) {
3762 
3763                 /* Test the readiness of the controller to receive the cmd */
3764                 for (to = FD_CRETRY; to; to--) {
3765                         if ((Msr(fdc) & (DIO|RQM)) == RQM)
3766                                 break;
3767                 }
3768                 if (to == 0) {
3769                         FDERRPRINT(FDEP_L2, FDEM_EXEC,
3770                             (C, "fdc: no RQM - stat 0x%x\n", Msr(fdc)));
3771                         csb->csb_cmdstat = 1;
3772 
3773                         (void) fd_unbind_handle(fdc);
3774                         return (EIO);
3775                 }
3776 
3777                 Set_Fifo(fdc, csb->csb_cmds[i]);
3778 
3779                 FDERRPRINT(FDEP_L1, FDEM_EXEC,
3780                     (C, "fdexec: sent 0x%x, Msr 0x%x\n", csb->csb_cmds[i],
3781                     Msr(fdc)));
3782 
3783         }
3784 
3785 
3786         /*
3787          * Start watchdog timer on data transfer type commands - required
3788          * in case a diskette is not present or is unformatted
3789          */
3790         if (csb->csb_opflags & CSB_OFTIMEIT) {
3791                 fdc->c_timeid = timeout(fdwatch, a,
3792                     tosec * drv_usectohz(1000000));
3793         }
3794 
3795         FDERRPRINT(FDEP_L1, FDEM_EXEC,
3796             (C, "fdexec: cmd sent, Msr 0x%x\n", Msr(fdc)));
3797 
3798         /* If the operation has no results - then just return */
3799         if (csb->csb_opflags & CSB_OFNORESULTS) {
3800                 if (fdc->c_fdtype & FDCTYPE_82077) {
3801                         if (fdc->c_mtimeid == 0) {
3802                                 fdc->c_mtimeid = timeout(fdmotoff, a,
3803                                     Motoff_delay);
3804                         }
3805                 }
3806                 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..\n"));
3807 
3808                 /*
3809                  * Make sure the last byte is received well by the
3810                  * controller. On faster CPU, it may still be busy
3811                  * by the time another command comes here.
3812                  */
3813                 for (to = FD_CRETRY; to; to--) {
3814                         if ((Msr(fdc) & (DIO|RQM)) == RQM)
3815                                 break;
3816                         }
3817                 if (to == 0) {
3818                         csb->csb_cmdstat = 1;
3819                         return (EIO);
3820                 }
3821 
3822                 /*
3823                  * An operation that has no results isn't doing DMA so,
3824                  * there is no reason to try to unbind a handle
3825                  */
3826                 return (0);
3827         }
3828 
3829         /*
3830          * If this operation has no interrupt AND an immediate result
3831          * then we just busy wait for the results and stuff them into
3832          * the csb
3833          */
3834         if (csb->csb_opflags & CSB_OFIMMEDIATE) {
3835                 to = FD_RRETRY;
3836                 csb->csb_nrslts = 0;
3837                 /*
3838                  * Wait while this command is still going on.
3839                  */
3840                 while ((tmp = Msr(fdc)) & CB) {
3841                         /*
3842                          * If RQM + DIO, then a result byte is at hand.
3843                          */
3844                         if ((tmp & (RQM|DIO|CB)) == (RQM|DIO|CB)) {
3845                                 csb->csb_rslt[csb->csb_nrslts++] =
3846                                     Fifo(fdc);
3847                                 /*
3848                                  * FDERRPRINT(FDEP_L4, FDEM_EXEC,
3849                                  *    (C, "fdexec: got result 0x%x\n",
3850                                  *    csb->csb_nrslts));
3851                                  */
3852                         } else if (--to == 0) {
3853                                 FDERRPRINT(FDEP_L4, FDEM_EXEC,
3854                                     (C, "fdexec: timeout, Msr%x, nr%x\n",
3855                                     Msr(fdc), csb->csb_nrslts));
3856 
3857                                 csb->csb_status = 2;
3858                                 if (fdc->c_fdtype & FDCTYPE_82077) {
3859                                         if (fdc->c_mtimeid == 0) {
3860                                                 fdc->c_mtimeid = timeout(
3861                                                     fdmotoff, a, Motoff_delay);
3862                                         }
3863                                 }
3864                                 /*
3865                                  * There is no DMA happening.  No need to
3866                                  * try freeing a handle.
3867                                  */
3868 
3869                                 return (EIO);
3870                         }
3871                 }
3872         }
3873 
3874         /*
3875          * If told to sleep here, well then sleep!
3876          */
3877 
3878         if (flags & FDXC_SLEEP) {
3879                 fdc->c_flags |= FDCFLG_WAITING;
3880                 while (fdc->c_flags & FDCFLG_WAITING) {
3881                         cv_wait(&fdc->c_iocv, &fdc->c_lolock);
3882                 }
3883         }
3884 
3885         /*
3886          * kludge for end-of-cylinder error which must be ignored!!!
3887          */
3888 
3889         if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
3890             ((csb->csb_rslt[0] & IC_SR0) == 0x40) &&
3891             (csb->csb_rslt[1] & EN_SR1))
3892                 csb->csb_rslt[0] &= ~IC_SR0;
3893 
3894         /*
3895          * See if there was an error detected, if so, fdrecover()
3896          * will check it out and say what to do.
3897          *
3898          * Don't do this, though, if this was the Sense Drive Status
3899          * or the Dump Registers command.
3900          */
3901         if (((csb->csb_rslt[0] & IC_SR0) || (fdc->c_csb.csb_dcsr_rslt) ||
3902             (csb->csb_status)) &&
3903             ((csb->csb_cmds[0] != FDRAW_SENSE_DRV) &&
3904             (csb->csb_cmds[0] != DUMPREG))) {
3905                 /* if it can restarted OK, then do so, else return error */
3906                 if (fdrecover(fdc) != 0) {
3907                         if (fdc->c_fdtype & FDCTYPE_82077) {
3908                                 if (fdc->c_mtimeid == 0) {
3909                                         fdc->c_mtimeid = timeout(fdmotoff,
3910                                             a, Motoff_delay);
3911                                 }
3912                         }
3913 
3914                         /*
3915                          * If this was a dma transfer, unbind the handle so
3916                          * that other transfers may use it.
3917                          */
3918 
3919                         (void) fd_unbind_handle(fdc);
3920                         return (EIO);
3921                 } else {
3922                         /* ASSUMES that cmd is still intact in csb */
3923                         goto retry;
3924                 }
3925         }
3926 
3927         /* things went ok */
3928         if (fdc->c_fdtype & FDCTYPE_82077) {
3929                 if (fdc->c_mtimeid == 0) {
3930                         fdc->c_mtimeid = timeout(fdmotoff, a, Motoff_delay);
3931                 }
3932         }
3933         FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..........\n"));
3934 
3935         if (fd_unbind_handle(fdc))
3936                 return (EIO);
3937 
3938         return (0);
3939 }
3940 
3941 /*
3942  * Turn on the drive's motor
3943  *
3944  *      - called with the low level lock held
3945  */
3946 static void
3947 fdexec_turn_on_motor(struct fdctlr *fdc, int flags,  uint_t unit)
3948 {
3949         clock_t local_lbolt;
3950         timeout_id_t timeid;
3951 
3952         /*
3953          * The low level mutex may not be held over the call to
3954          * untimeout().  See the manpage for details.
3955          */
3956         timeid = fdc->c_mtimeid;
3957         fdc->c_mtimeid = 0;
3958         if (timeid) {
3959                 mutex_exit(&fdc->c_lolock);
3960                 (void) untimeout(timeid);
3961                 mutex_enter(&fdc->c_lolock);
3962         }
3963 
3964         ASSERT(fdc->c_un->un_unit_no == unit);
3965 
3966 
3967         set_rotational_speed(fdc, unit);
3968 
3969         if (!(Dor(fdc) & (MOTEN(unit)))) {
3970                 /*
3971                  * Turn on the motor
3972                  */
3973                 FDERRPRINT(FDEP_L1, FDEM_EXEC,
3974                     (C, "fdexec: turning on motor\n"));
3975 
3976                 /* LINTED */
3977                 Set_dor(fdc, (MOTEN(unit)), 1);
3978 
3979                 if (flags & FDXC_SLEEP) {
3980                         local_lbolt = ddi_get_lbolt();
3981                         (void) cv_timedwait(&fdc->c_motoncv,
3982                             &fdc->c_lolock, local_lbolt + Moton_delay);
3983                 } else {
3984                         drv_usecwait(1000000);
3985                 }
3986         }
3987 
3988 }
3989 
3990 /*
3991  * fdrecover
3992  *      see if possible to retry an operation.
3993  *      All we can do is restart the operation.  If we are out of allowed
3994  *      retries - return non-zero so that the higher levels will be notified.
3995  *
3996  * RETURNS: 0 if ok to restart, !0 if can't or out of retries
3997  *      - called with the low level lock held
3998  */
3999 static int
4000 fdrecover(struct fdctlr *fdc)
4001 {
4002         struct fdcsb *csb;
4003 
4004         FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdrecover\n"));
4005         csb = &fdc->c_csb;
4006 
4007         if (fdc->c_flags & FDCFLG_TIMEDOUT) {
4008                 struct fdcsb savecsb;
4009 
4010                 fdc->c_flags ^= FDCFLG_TIMEDOUT;
4011                 csb->csb_rslt[1] |= TO_SR1;
4012                 FDERRPRINT(FDEP_L1, FDEM_RECO,
4013                     (C, "fd%d: %s timed out\n", csb->csb_unit,
4014                     fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
4015 
4016                 /* use private csb */
4017                 savecsb = fdc->c_csb;
4018                 bzero(&fdc->c_csb, sizeof (struct fdcsb));
4019                 FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdc: resetting\n"));
4020 
4021                 (void) fdreset(fdc);
4022 
4023                 if (fdc->c_fdtype & FDCTYPE_DMA) {
4024                         mutex_enter(&fdc->c_hilock);
4025                         /* Reset the DMA engine as well */
4026                         reset_dma_controller(fdc);
4027                         set_dma_control_register(fdc, DCSR_INIT_BITS);
4028                         mutex_exit(&fdc->c_hilock);
4029                 }
4030 
4031 
4032                 /* check change first?? */
4033                 /* don't ckchg in fdexec, too convoluted */
4034                 (void) fdrecalseek(fdc, savecsb.csb_unit, -1, 0);
4035                 fdc->c_csb = savecsb; /* restore original csb */
4036         }
4037 
4038         /*
4039          * gather statistics on errors
4040          */
4041         if (csb->csb_rslt[1] & DE_SR1) {
4042                 fdc->fdstats.de++;
4043         }
4044         if (csb->csb_rslt[1] & OR_SR1) {
4045                 fdc->fdstats.run++;
4046         }
4047         if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
4048                 fdc->fdstats.bfmt++;
4049         }
4050         if (csb->csb_rslt[1] & TO_SR1) {
4051                 fdc->fdstats.to++;
4052         }
4053 
4054         /*
4055          * If raw ioctl don't examine results just pass status
4056          * back via fdraw. Raw commands are timed too, so put this
4057          * after the above check.
4058          */
4059         if (csb->csb_opflags & CSB_OFRAWIOCTL) {
4060                 return (1);
4061         }
4062 
4063 
4064         /*
4065          * if there was a pci bus error, do not retry
4066          */
4067 
4068                 if (csb->csb_dcsr_rslt == 1) {
4069                         FDERRPRINT(FDEP_L3, FDEM_RECO,
4070                             (C, "fd%d: host bus error\n", 0));
4071                 return (1);
4072                 }
4073 
4074         /*
4075          * If there was an error with the DMA functions, do not retry
4076          */
4077         if (csb->csb_dma_rslt == 1) {
4078                         FDERRPRINT(FDEP_L1, FDEM_RECO,
4079                             (C, "fd%d: DMA interface error\n", csb->csb_unit));
4080                 return (1);
4081         }
4082 
4083 
4084         /*
4085          * if we have run out of retries, return an error
4086          * XXX need better status interp
4087          */
4088 
4089         csb->csb_retrys++;
4090         if (csb->csb_retrys > csb->csb_maxretry) {
4091                 FDERRPRINT(FDEP_L3, FDEM_RECO,
4092                     (C, "fd%d: %s failed (%x %x %x)\n",
4093                     0, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
4094                     csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
4095                 if (csb->csb_rslt[1] & NW_SR1) {
4096                         FDERRPRINT(FDEP_L3, FDEM_RECO,
4097                             (C, "fd%d: not writable\n", 0));
4098                 }
4099                 if (csb->csb_rslt[1] & DE_SR1) {
4100                         FDERRPRINT(FDEP_L3, FDEM_RECO,
4101                             (C, "fd%d: crc error blk %d\n", 0,
4102                             (int)fdc->c_current->b_blkno));
4103                 }
4104                 if (csb->csb_rslt[1] & OR_SR1) {
4105                         if (fdc->c_fdtype & FDCTYPE_SB) {
4106                                 /*
4107                                  * When using southbridge chip we need to
4108                                  * retry atleast 10 times to shake off the
4109                                  * underrun err.
4110                                  */
4111                                 if (csb->csb_retrys <= rwretry)
4112                                         return (0);
4113                         }
4114                         FDERRPRINT(FDEP_L3, FDEM_RECO,
4115                             (C, "fd%d: over/underrun\n", 0));
4116                 }
4117 
4118                 if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
4119                         FDERRPRINT(FDEP_L3, FDEM_RECO,
4120                             (C, "fd%d: bad format\n", 0));
4121                 }
4122 
4123                 if (csb->csb_rslt[1] & TO_SR1) {
4124                         FDERRPRINT(FDEP_L3, FDEM_RECO,
4125                             (C, "fd%d: timeout\n", 0));
4126                 }
4127 
4128                 csb->csb_cmdstat = 1; /* failed - give up */
4129                 return (1);
4130         }
4131 
4132         if (csb->csb_opflags & CSB_OFSEEKOPS) {
4133                 /* seek, recal type commands - just look at st0 */
4134                 FDERRPRINT(FDEP_L2, FDEM_RECO,
4135                     (C, "fd%d: %s error : st0 0x%x\n", csb->csb_unit,
4136                     fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
4137                     csb->csb_rslt[0]));
4138         }
4139         if (csb->csb_opflags & CSB_OFXFEROPS) {
4140                 /* rd, wr, fmt type commands - look at st0, st1, st2 */
4141                 FDERRPRINT(FDEP_L2, FDEM_RECO,
4142                     (C, "fd%d: %s error : st0=0x%x st1=0x%x st2=0x%x\n",
4143                     csb->csb_unit, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
4144                     csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
4145         }
4146 
4147         return (0);     /* tell fdexec to retry */
4148 }
4149 
4150 /*
4151  * Interrupt handle for DMA
4152  */
4153 
4154 static uint_t
4155 fdintr_dma()
4156 {
4157         struct fdctlr   *fdc;
4158         off_t           off;
4159         size_t          len;
4160         uint_t          ccount;
4161         uint_t          windex;
4162         uint_t          done = 0;
4163         int             tmp_dcsr;
4164         int             to;
4165         uchar_t         tmp;
4166         int             i = 0;
4167         int             res = DDI_INTR_UNCLAIMED;
4168         int             not_cheerio = 1;
4169 
4170         /* search for a controller that's expecting an interrupt */
4171         fdc = fdctlrs;
4172 
4173         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
4174                 tmp_dcsr = get_dma_control_register(fdc);
4175                 if (!(tmp_dcsr & DCSR_INT_PEND) && !(DCSR_ERR_PEND & tmp_dcsr))
4176                         return (res);
4177                 not_cheerio = 0;
4178         }
4179 
4180         mutex_enter(&fdc->c_hilock);
4181 
4182         if (fdc->c_csb.csb_opmode == 0x0) {
4183                 fdc->c_csb.csb_opmode = 2;
4184         }
4185         if (fdc->sb_dma_lock) {
4186                 release_sb_dma(fdc);
4187         }
4188 
4189         /*
4190          * An interrupt can come from either the floppy controller or
4191          * or the DMA engine.  The DMA engine will only issue an
4192          * interrupt if there was an error.
4193          */
4194 
4195         switch (fdc->c_csb.csb_opmode) {
4196                 case 0x1:
4197                         /* read/write/format data-xfer case */
4198 
4199                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4200                             (C, "fdintr_dma: opmode 1\n"));
4201 
4202                         /*
4203                          * See if the interrupt is from the floppy
4204                          * controller.  If there is, take out the status bytes.
4205                          */
4206 
4207                         if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
4208 
4209                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4210                                     (C, "fdintr_dma: INT_PEND \n"));
4211 
4212                                 res = DDI_INTR_CLAIMED;
4213 
4214                                 to = FD_RRETRY;
4215                                 fdc->c_csb.csb_nrslts = 0;
4216 
4217                                 /* check status */
4218                                 i = 0;
4219 
4220                                 /*
4221                                  * CB turns off once all the result bytes are
4222                                  *  read.
4223                                  *
4224                                  * NOTE: the counters are there so that the
4225                                  * handler will never get stuck in a loop.
4226                                  * If the counters do reach their maximum
4227                                  * values, then a catastrophic error has
4228                                  * occurred.  This should never be the case.
4229                                  * The counters only came into play during
4230                                  * development.
4231                                  */
4232                                 while (((tmp = Msr(fdc)) & CB) &&
4233                                     (i < 1000001)) {
4234 
4235                                         /*
4236                                          * If RQM + DIO, then a result byte
4237                                          * is at hand.
4238                                          */
4239                                         if ((tmp & (RQM|DIO|CB)) ==
4240                                             (RQM|DIO|CB)) {
4241                                                 fdc->c_csb.csb_rslt
4242                                                     [fdc->c_csb.csb_nrslts++]
4243                                                     = Fifo(fdc);
4244 
4245                                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4246                                                     (C,
4247                                                     "fdintr_dma: res 0x%x\n",
4248                                                     fdc->c_csb.csb_rslt
4249                                                     [fdc->c_csb.csb_nrslts
4250                                                     - 1]));
4251 
4252                                         } else if (--to == 0) {
4253                                                 /*
4254                                                  * controller was never
4255                                                  * ready to give results
4256                                                  */
4257                                                 fdc->c_csb.csb_status = 2;
4258                                                 break;
4259                                         }
4260                                         i++;
4261                                 }
4262                                 if (i == 10000) {
4263                                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4264                                             (C, "First loop overran\n"));
4265                                 }
4266                         }
4267 
4268                         /*
4269                          * See if the interrupt is from the DMA engine,
4270                          * which will only interrupt on an error
4271                          */
4272                         if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
4273 
4274                                 res = DDI_INTR_CLAIMED;
4275 
4276                                 done = 1;
4277                                 fdc->c_csb.csb_dcsr_rslt = 1;
4278                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4279                                     (C, "fdintr_dma: Error pending\n"));
4280                                 reset_dma_controller(fdc);
4281                                 set_dma_control_register(fdc, DCSR_INIT_BITS);
4282                                 break;
4283                         }
4284 
4285                         /* TCBUG kludge */
4286                         if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
4287                             ((fdc->c_csb.csb_rslt[0] & IC_SR0) == 0x40) &&
4288                             (fdc->c_csb.csb_rslt[1] & EN_SR1)) {
4289 
4290                                 fdc->c_csb.csb_rslt[0] &= ~IC_SR0;
4291 
4292                                 fdc->c_csb.csb_rslt[1] &= ~EN_SR1;
4293 
4294 
4295                         }
4296 
4297 
4298                         /* Exit if there were errors in the DMA */
4299                         if (((fdc->c_csb.csb_rslt[0] & IC_SR0) != 0) ||
4300                             (fdc->c_csb.csb_rslt[1] != 0) ||
4301                             (fdc->c_csb.csb_rslt[2] != 0)) {
4302                                 done = 1;
4303                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4304                                     (C, "fdintr_dma: errors in command\n"));
4305 
4306 
4307                                 break;
4308                         }
4309 
4310 
4311                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4312                             (C, "fdintr_dma: dbcr 0x%x\n",
4313                             get_data_count_register(fdc)));
4314                         /*
4315                          * The csb_ccount is the number of cookies that still
4316                          * need to be processed.  A cookie was just processed
4317                          * so decrement the cookie counter.
4318                          */
4319                         if (fdc->c_csb.csb_ccount == 0) {
4320                                 done = 1;
4321                                 break;
4322                         }
4323                         fdc->c_csb.csb_ccount--;
4324                         ccount = fdc->c_csb.csb_ccount;
4325 
4326                         windex = fdc->c_csb.csb_windex;
4327 
4328                         /*
4329                          * If there are no more cookies and all the windows
4330                          * have been DMA'd, then DMA is done.
4331                          *
4332                          */
4333                         if ((ccount == 0) && (windex == fdc->c_csb.csb_nwin)) {
4334 
4335                                 done = 1;
4336 
4337                                 /*
4338                                  * The handle is unbound in fdexec
4339                                  */
4340 
4341                                 break;
4342                         }
4343 
4344                         if (ccount != 0) {
4345                                 /* process the next cookie */
4346                                 ddi_dma_nextcookie(fdc->c_dmahandle,
4347                                     &fdc->c_csb.csb_dmacookie);
4348 
4349                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4350                                     (C, "cookie addr 0x%" PRIx64 "\n",
4351                                     fdc->c_csb.csb_dmacookie.dmac_laddress));
4352 
4353                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4354                                     (C, "cookie length %lu\n",
4355                                     fdc->c_csb.csb_dmacookie.dmac_size));
4356 
4357                         } else {
4358 
4359                                 (void) ddi_dma_getwin(fdc->c_dmahandle,
4360                                     fdc->c_csb.csb_windex,
4361                                     &off, &len,
4362                                     &fdc->c_csb.csb_dmacookie,
4363                                     &fdc->c_csb.csb_ccount);
4364                                 fdc->c_csb.csb_windex++;
4365 
4366                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4367                                     (C, "fdintr_dma: process %d window\n",
4368                                     fdc->c_csb.csb_windex));
4369 
4370                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4371                                     (C, "fdintr_dma: process no. cookies %d\n",
4372                                     fdc->c_csb.csb_ccount));
4373 
4374                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4375                                     (C, "cookie addr 0x%" PRIx64 "\n",
4376                                     fdc->c_csb.csb_dmacookie.dmac_laddress));
4377 
4378                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4379                                     (C, "cookie length %lu\n",
4380                                     fdc->c_csb.csb_dmacookie.dmac_size));
4381                         }
4382 
4383                         /*
4384                          * Program the DMA engine with the length and
4385                          * the address of the transfer
4386                          */
4387 
4388                         ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
4389 
4390                         set_data_count_register(fdc,
4391                             fdc->c_csb.csb_dmacookie.dmac_size);
4392                         set_data_address_register(fdc,
4393                             fdc->c_csb.csb_dmacookie.dmac_laddress);
4394 
4395                         FDERRPRINT(FDEP_L1, FDEM_INTR, (C,
4396                             "fdintr_dma: size 0x%lx\n",
4397                             fdc->c_csb.csb_dmacookie.dmac_size));
4398 
4399 
4400                         /* reprogram the controller */
4401                         fdc->c_csb.csb_cmds[2] = fdc->c_csb.csb_rslt[3];
4402                         fdc->c_csb.csb_cmds[3] = fdc->c_csb.csb_rslt[4];
4403                         fdc->c_csb.csb_cmds[4] = fdc->c_csb.csb_rslt[5];
4404                         fdc->c_csb.csb_cmds[1] = (fdc->c_csb.csb_cmds[1]
4405                             & ~0x04) | (fdc->c_csb.csb_rslt[4] << 2);
4406 
4407                         for (i = 0; i < (int)fdc->c_csb.csb_ncmds; i++) {
4408 
4409                                 /*
4410                                  * Test the readiness of the controller
4411                                  * to receive the cmd
4412                                  */
4413                                 for (to = FD_CRETRY; to; to--) {
4414                                         if ((Msr(fdc) & (DIO|RQM)) == RQM)
4415                                                 break;
4416                                 }
4417                                 if (to == 0) {
4418                                         FDERRPRINT(FDEP_L2, FDEM_EXEC,
4419                                             (C,
4420                                             "fdc: no RQM - stat 0x%x\n",
4421                                             Msr(fdc)));
4422                                         /* stop the DMA from happening */
4423                                         fdc->c_csb.csb_status = 2;
4424                                         done = 1;
4425                                         break;
4426                                 }
4427 
4428                                 Set_Fifo(fdc, fdc->c_csb.csb_cmds[i]);
4429 
4430                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4431                                     (C,
4432                                     "fdintr_dma: sent 0x%x, Msr 0x%x\n",
4433                                     fdc->c_csb.csb_cmds[i], Msr(fdc)));
4434                         }
4435 
4436                         /* reenable DMA */
4437                         if ((!not_cheerio) && (!done))
4438                                 set_dma_control_register(fdc, tmp_dcsr |
4439                                     DCSR_EN_DMA);
4440                         break;
4441 
4442                 case 0x2:
4443                 /* seek/recal type cmd */
4444                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4445                             (C, "fintr_dma: opmode 2\n"));
4446 
4447                         /*
4448                          *  See if the interrupt is from the DMA engine,
4449                          *  which will only interrupt if there was an error.
4450                          */
4451                         if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
4452                                 res = DDI_INTR_CLAIMED;
4453                                 done = 1;
4454                                 fdc->c_csb.csb_dcsr_rslt = 1;
4455                                 reset_dma_controller(fdc);
4456                                 set_dma_control_register(fdc, DCSR_INIT_BITS);
4457 
4458                                 break;
4459                         }
4460 
4461 
4462                         /* See if the interrupt is from the floppy controller */
4463                         if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
4464 
4465                                 res = DDI_INTR_CLAIMED;
4466 
4467 
4468                                 /*
4469                                  * Wait until there's no longer a command
4470                                  * in progress
4471                                  */
4472 
4473                                 FDERRPRINT(FDEP_L1, FDEM_INTR,
4474                                     (C, "fdintr_dma: interrupt pending\n"));
4475                                 i = 0;
4476                                 while (((Msr(fdc) & CB)) && (i < 10000)) {
4477                                         i++;
4478                                 }
4479 
4480                                 if (i == 10000)
4481                                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4482                                             (C, "2nd loop overran !!!\n"));
4483 
4484                                 /*
4485                                  * Check the RQM bit to see if the controller is
4486                                  * ready to transfer status of the command.
4487                                  */
4488                                 i = 0;
4489                                 while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
4490                                         i++;
4491                                 }
4492 
4493                                 if (i == 10000)
4494                                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4495                                             (C, "3rd loop overran !!!\n"));
4496 
4497                                 /*
4498                                  * Issue the Sense Interrupt Status Command
4499                                  */
4500                                 Set_Fifo(fdc, SNSISTAT);
4501 
4502                                 i = 0;
4503                                 while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
4504                                         i++;
4505                                 }
4506                                 if (i == 10000)
4507                                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4508                                             (C, "4th loop overran !!!\n"));
4509 
4510                                 /* Store the first result byte */
4511                                 fdc->c_csb.csb_rslt[0] = Fifo(fdc);
4512 
4513                                 i = 0;
4514                                 while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
4515                                         i++;
4516                                 }
4517                                 if (i == 10000)
4518                                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4519                                             (C, "5th loop overran !!!\n"));
4520 
4521                                 /* Store the second  result byte */
4522                                 fdc->c_csb.csb_rslt[1] = Fifo(fdc);
4523 
4524                                 done = 1;
4525                         }
4526 
4527                 }
4528 
4529         /*
4530          * We are done with the actual interrupt handling here.
4531          * The portion below should be actually be done by fd_lointr().
4532          * We should be triggering the fd_lointr here and exiting.
4533          * However for want of time this will be done in the next FIX.
4534          *
4535          * Hence for now we will release hilock only and keep the remaining
4536          * code as it is.
4537          * Releasing of hilock ensures that we don't hold on to the
4538          * lolock and hilock at the same time.
4539          * hilock is acquired each time dma related  registers are accessed.
4540          */
4541         mutex_exit(&fdc->c_hilock);
4542         /* Make signal and get out of interrupt handler */
4543         if (done) {
4544                 mutex_enter(&fdc->c_lolock);
4545 
4546                 fdc->c_csb.csb_opmode = 0;
4547 
4548                 /*  reset watchdog timer if armed and not already triggered */
4549 
4550 
4551                 if (fdc->c_timeid) {
4552                         timeout_id_t timeid = fdc->c_timeid;
4553                         fdc->c_timeid = 0;
4554                         mutex_exit(&fdc->c_lolock);
4555                         (void) untimeout(timeid);
4556                         mutex_enter(&fdc->c_lolock);
4557                 }
4558 
4559 
4560                 if (fdc->c_flags & FDCFLG_WAITING) {
4561                         /*
4562                          * somebody's waiting on finish of fdctlr/csb,
4563                          * wake them
4564                          */
4565 
4566                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4567                             (C, "fdintr_dma: signal the waiter\n"));
4568 
4569                         fdc->c_flags ^= FDCFLG_WAITING;
4570                         cv_signal(&fdc->c_iocv);
4571 
4572                         /*
4573                          * FDCFLG_BUSY is NOT cleared, NOR is the csb given
4574                          * back; the operation just finished can look at the csb
4575                          */
4576                 } else {
4577                         FDERRPRINT(FDEP_L1, FDEM_INTR,
4578                             (C, "fdintr_dma: nobody sleeping (%x %x %x)\n",
4579                             fdc->c_csb.csb_rslt[0], fdc->c_csb.csb_rslt[1],
4580                             fdc->c_csb.csb_rslt[2]));
4581                 }
4582                 mutex_exit(&fdc->c_lolock);
4583         }
4584         /* update high level interrupt counter */
4585         if (fdc->c_intrstat)
4586                 KIOIP->intrs[KSTAT_INTR_HARD]++;
4587 
4588 
4589         FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr_dma: done\n"));
4590         return (res);
4591 }
4592 
4593 /*
4594  * fd_lointr
4595  *      This is the low level SW interrupt handler triggered by the high
4596  *      level interrupt handler (or by fdwatch).
4597  */
4598 static uint_t
4599 fd_lointr(caddr_t arg)
4600 {
4601         struct fdctlr *fdc = (struct fdctlr *)arg;
4602         struct fdcsb *csb;
4603 
4604         csb = &fdc->c_csb;
4605         FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr: opmode %d\n",
4606             csb->csb_opmode));
4607         /*
4608          * Check that lowlevel interrupt really meant to trigger us.
4609          */
4610         if (csb->csb_opmode != 4) {
4611                 /*
4612                  * This should probably be protected, but, what the
4613                  * heck...the cost isn't worth the accuracy for this
4614                  * statistic.
4615                  */
4616                 if (fdc->c_intrstat)
4617                         KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
4618                 return (DDI_INTR_UNCLAIMED);
4619         }
4620 
4621         mutex_enter(&fdc->c_lolock);
4622         csb->csb_opmode = 0;
4623 
4624         /*  reset watchdog timer if armed and not already triggered */
4625         if (fdc->c_timeid) {
4626                 timeout_id_t timeid = fdc->c_timeid;
4627                 fdc->c_timeid = 0;
4628                 mutex_exit(&fdc->c_lolock);
4629                 (void) untimeout(timeid);
4630                 mutex_enter(&fdc->c_lolock);
4631 
4632         }
4633 
4634         if (fdc->c_flags & FDCFLG_WAITING) {
4635                 /*
4636                  * somebody's waiting on finish of fdctlr/csb, wake them
4637                  */
4638                 fdc->c_flags ^= FDCFLG_WAITING;
4639                 cv_signal(&fdc->c_iocv);
4640 
4641                 /*
4642                  * FDCFLG_BUSY is NOT cleared, NOR is the csb given back; so
4643                  * the operation just finished can look at the csb
4644                  */
4645         } else {
4646                 FDERRPRINT(FDEP_L3, FDEM_INTR,
4647                     (C, "fdintr: nobody sleeping (%x %x %x)\n",
4648                     csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
4649         }
4650         if (fdc->c_intrstat)
4651                 KIOIP->intrs[KSTAT_INTR_SOFT]++;
4652         mutex_exit(&fdc->c_lolock);
4653         return (DDI_INTR_CLAIMED);
4654 }
4655 
4656 /*
4657  * fdwatch
4658  *      is called from timein() when a floppy operation has expired.
4659  */
4660 static void
4661 fdwatch(void *arg)
4662 {
4663         struct fdctlr *fdc = arg;
4664         int old_opmode;
4665         struct fdcsb *csb;
4666 
4667         FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch\n"));
4668 
4669         mutex_enter(&fdc->c_lolock);
4670         if (fdc->c_timeid == 0) {
4671                 /*
4672                  * fdintr got here first, ergo, no timeout condition..
4673                  */
4674 
4675                 FDERRPRINT(FDEP_L1, FDEM_WATC,
4676                     (C, "fdwatch: no timeout\n"));
4677 
4678                 mutex_exit(&fdc->c_lolock);
4679                 return;
4680         }
4681         fdc->c_timeid = 0;
4682         csb = &fdc->c_csb;
4683 
4684         mutex_enter(&fdc->c_hilock);
4685         /*
4686          * XXXX: We should probably reset the bloody chip
4687          */
4688         old_opmode = csb->csb_opmode;
4689 
4690         FDERRPRINT(FDEP_L1, FDEM_WATC,
4691             (C, "fd%d: timeout, opmode:%d\n", csb->csb_unit, old_opmode));
4692 
4693         csb->csb_opmode = 4;
4694         mutex_exit(&fdc->c_hilock);
4695 
4696         FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch: cmd %s timed out\n",
4697             fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
4698         fdc->c_flags |= FDCFLG_TIMEDOUT;
4699         csb->csb_status = CSB_CMDTO;
4700 
4701         if ((fdc->c_fdtype & FDCTYPE_DMA) == 0) {
4702                 ddi_trigger_softintr(fdc->c_softid);
4703                 KIOIP->intrs[KSTAT_INTR_WATCHDOG]++;
4704                 mutex_exit(&fdc->c_lolock);
4705         } else {
4706                 mutex_exit(&fdc->c_lolock);
4707                 (void) fd_lointr((caddr_t)fdctlrs);
4708         }
4709 }
4710 
4711 /*
4712  * fdgetcsb
4713  *      wait until the csb is free
4714  */
4715 static void
4716 fdgetcsb(struct fdctlr *fdc)
4717 {
4718         FDERRPRINT(FDEP_L1, FDEM_GETC, (C, "fdgetcsb\n"));
4719         ASSERT(mutex_owned(&fdc->c_lolock));
4720         while (fdc->c_flags & FDCFLG_BUSY) {
4721                 fdc->c_flags |= FDCFLG_WANT;
4722                 cv_wait(&fdc->c_csbcv, &fdc->c_lolock);
4723         }
4724         fdc->c_flags |= FDCFLG_BUSY; /* got it! */
4725 }
4726 
4727 /*
4728  * fdretcsb
4729  *      return csb
4730  */
4731 static void
4732 fdretcsb(struct fdctlr *fdc)
4733 {
4734 
4735         ASSERT(mutex_owned(&fdc->c_lolock));
4736         FDERRPRINT(FDEP_L1, FDEM_RETC, (C, "fdretcsb\n"));
4737         fdc->c_flags &= ~FDCFLG_BUSY; /* let go */
4738 
4739         fdc->c_csb.csb_read = 0;
4740 
4741         if (fdc->c_flags & FDCFLG_WANT) {
4742                 fdc->c_flags ^= FDCFLG_WANT;
4743                 /*
4744                  * broadcast the signal.  One thread will wake up and
4745                  * set the flags to FDCFLG_BUSY.  If more than one thread is
4746                  * waiting then each thread will wake up in turn.  The first
4747                  * thread to wake-up will set the FDCFLG_BUSY flag and the
4748                  * subsequent threads will will wake-up, but reset the
4749                  * flag to FDCFLG_WANT because the FDCFLG_BUSY bit is set.
4750                  */
4751                 cv_broadcast(&fdc->c_csbcv);
4752         }
4753 }
4754 
4755 
4756 /*
4757  * fdreset
4758  *      reset THE controller, and configure it to be
4759  *      the way it ought to be
4760  * ASSUMES: that it already owns the csb/fdctlr!
4761  *
4762  *      - called with the low level lock held
4763  */
4764 static int
4765 fdreset(struct fdctlr *fdc)
4766 {
4767         struct fdcsb *csb;
4768         clock_t local_lbolt = 0;
4769         timeout_id_t timeid;
4770 
4771         FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset\n"));
4772 
4773         ASSERT(mutex_owned(&fdc->c_lolock));
4774 
4775         /* count resets */
4776         fdc->fdstats.reset++;
4777 
4778         /*
4779          * On the 82077, the DSR will clear itself after a reset.  Upon exiting
4780          * the reset, a polling interrupt will be generated.  If the floppy
4781          * interrupt is enabled, it's possible for cv_signal() to be called
4782          * before cv_wait().  This will cause the system to hang.  Turn off
4783          * the floppy interrupt to avoid this race condition
4784          */
4785         if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
4786                 /*
4787                  * We need to perform any timeouts before we Reset the
4788                  * controller. We cannot afford to drop the c_lolock mutex after
4789                  * Resetting the controller. The reason is that we get a spate
4790                  * of interrupts until we take the controller out of reset.
4791                  * The way we avoid this spate of continuous interrupts is by
4792                  * holding on to the c_lolock and forcing the fdintr_dma routine
4793                  * to go to sleep waiting for this mutex.
4794                  */
4795                 /* Do not hold the mutex across the untimeout call */
4796                 timeid = fdc->c_mtimeid;
4797                 fdc->c_mtimeid = 0;
4798                 if (timeid) {
4799                         mutex_exit(&fdc->c_lolock);
4800                         (void) untimeout(timeid);
4801                         mutex_enter(&fdc->c_lolock);
4802                 }
4803                 /* LINTED */
4804                 Set_dor(fdc, DMAGATE, 0);
4805                 FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset: set dor\n"));
4806         }
4807 
4808         /* toggle software reset */
4809         Dsr(fdc, SWR);
4810 
4811         drv_usecwait(5);
4812 
4813         FDERRPRINT(FDEP_L1, FDEM_RESE,
4814             (C, "fdreset: toggled software reset\n"));
4815 
4816         /*
4817          * This sets the data rate to 500Kbps (for high density)
4818          * XXX should use current characteristics instead XXX
4819          */
4820         Dsr(fdc, 0);
4821         drv_usecwait(5);
4822         switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
4823         case FDCTYPE_82077:
4824                 /*
4825                  * when we bring the controller out of reset it will generate
4826                  * a polling interrupt. fdintr() will field it and schedule
4827                  * fd_lointr(). There will be no one sleeping but we are
4828                  * expecting an interrupt so....
4829                  */
4830                 fdc->c_flags |= FDCFLG_WAITING;
4831 
4832                 /*
4833                  * The reset bit must be cleared to take the 077 out of
4834                  * reset state and the DMAGATE bit must be high to enable
4835                  * interrupts.
4836                  */
4837                 /* LINTED */
4838                 Set_dor(fdc, DMAGATE|RESET, 1);
4839 
4840                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
4841                     (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
4842 
4843                 local_lbolt = ddi_get_lbolt();
4844                 if (cv_timedwait(&fdc->c_iocv, &fdc->c_lolock,
4845                     local_lbolt + drv_usectohz(1000000)) == -1) {
4846                         return (-1);
4847                 }
4848                 break;
4849 
4850         default:
4851                 fdc->c_flags |= FDCFLG_WAITING;
4852 
4853                 /*
4854                  * A timed wait is not used because it's possible for the timer
4855                  * to go off before the controller has a chance to interrupt.
4856                  */
4857                 cv_wait(&fdc->c_iocv, &fdc->c_lolock);
4858                 break;
4859         }
4860         csb = &fdc->c_csb;
4861 
4862         /* setup common things in csb */
4863         csb->csb_unit = fdc->c_un->un_unit_no;
4864         csb->csb_nrslts = 0;
4865         csb->csb_opflags = CSB_OFNORESULTS;
4866         csb->csb_maxretry = 0;
4867         csb->csb_retrys = 0;
4868 
4869         csb->csb_read = CSB_NULL;
4870 
4871         /* send SPECIFY command to fdc */
4872         /* csb->unit is don't care */
4873         csb->csb_cmds[0] = FDRAW_SPECIFY;
4874         csb->csb_cmds[1] = fdspec[0]; /* step rate, head unload time */
4875         if (fdc->c_fdtype & FDCTYPE_DMA)
4876                 csb->csb_cmds[2] =  SPEC_DMA_MODE;
4877         else
4878                 csb->csb_cmds[2] = fdspec[1];  /* head load time, DMA mode */
4879 
4880         csb->csb_ncmds = 3;
4881 
4882         /* XXX for now ignore errors, they "CAN'T HAPPEN" */
4883         (void) fdexec(fdc, 0);  /* no FDXC_CHECKCHG, ... */
4884         /* no results */
4885 
4886         /* send CONFIGURE command to fdc */
4887         /* csb->unit is don't care */
4888         csb->csb_cmds[0] = CONFIGURE;
4889         csb->csb_cmds[1] = fdconf[0]; /* motor info, motor delays */
4890         csb->csb_cmds[2] = fdconf[1]; /* enaimplsk, disapoll, fifothru */
4891         csb->csb_cmds[3] = fdconf[2]; /* track precomp */
4892         csb->csb_ncmds = 4;
4893 
4894         csb->csb_read = CSB_NULL;
4895 
4896         csb->csb_retrys = 0;
4897 
4898         /* XXX for now ignore errors, they "CAN'T HAPPEN" */
4899         (void) fdexec(fdc, 0); /* no FDXC_CHECKCHG, ... */
4900         return (0);
4901 }
4902 
4903 /*
4904  * fdrecalseek
4905  *      performs recalibrates or seeks if the "arg" is -1 does a
4906  *      recalibrate on a drive, else it seeks to the cylinder of
4907  *      the drive.  The recalibrate is also used to find a drive,
4908  *      ie if the drive is not there, the controller says "error"
4909  *      on the operation
4910  * NOTE: that there is special handling of this operation in the hardware
4911  * interrupt routine - it causes the operation to appear to have results;
4912  * ie the results of the SENSE INTERRUPT STATUS that the hardware interrupt
4913  * function did for us.
4914  * NOTE: because it uses sleep/wakeup it must be protected in a critical
4915  * section so create one before calling it!
4916  *
4917  * RETURNS: 0 for ok,
4918  *      else    errno from fdexec,
4919  *      or      ENODEV if error (infers hardware type error)
4920  *
4921  *      - called with the low level lock held
4922  */
4923 static int
4924 fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg)
4925 {
4926         struct fdcsb *csb;
4927         int result;
4928 
4929         ASSERT(fdc->c_un->un_unit_no == unit);
4930 
4931         FDERRPRINT(FDEP_L1, FDEM_RECA, (C, "fdrecalseek to %d\n", arg));
4932 
4933         /* XXX TODO: check see argument for <= num cyls OR < 256 */
4934 
4935         csb = &fdc->c_csb;
4936         csb->csb_unit = (uchar_t)unit;
4937         csb->csb_cmds[1] = unit & 0x03;
4938 
4939         if (arg == -1) {                        /* is recal... */
4940                 csb->csb_cmds[0] = FDRAW_REZERO;
4941                 csb->csb_ncmds = 2;
4942         } else {
4943                 csb->csb_cmds[0] = FDRAW_SEEK;
4944                 csb->csb_cmds[2] = (uchar_t)arg;
4945                 csb->csb_ncmds = 3;
4946         }
4947         csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */
4948         csb->csb_opflags = CSB_OFSEEKOPS | CSB_OFTIMEIT;
4949         /*
4950          * MAYBE NYD need to set retries to different values? - depending on
4951          * drive characteristics - if we get to high capacity drives
4952          */
4953         csb->csb_maxretry = skretry;
4954         csb->csb_retrys = 0;
4955 
4956         /* send cmd off to fdexec */
4957         if (result = fdexec(fdc, FDXC_SLEEP | execflg)) {
4958                 goto out;
4959         }
4960 
4961         /*
4962          * if recal, test for equipment check error
4963          * ASSUMES result = 0 from above call
4964          */
4965         if (arg == -1) {
4966                 result = 0;
4967         } else {
4968                 /* for seeks, any old error will do */
4969                 if ((csb->csb_rslt[0] & IC_SR0) || csb->csb_cmdstat)
4970                         result = ENODEV;
4971         }
4972 
4973 out:
4974         return (result);
4975 }
4976 
4977 /*
4978  * fdsensedrv
4979  *      do a sense_drive command.  used by fdopen and fdcheckdisk.
4980  *
4981  *      - called with the lock held
4982  */
4983 static int
4984 fdsensedrv(struct fdctlr *fdc, int unit)
4985 {
4986         struct fdcsb *csb;
4987 
4988         ASSERT(fdc->c_un->un_unit_no == unit);
4989 
4990         csb = &fdc->c_csb;
4991 
4992         /* setup common things in csb */
4993         csb->csb_unit = (uchar_t)unit;
4994         csb->csb_opflags = CSB_OFIMMEDIATE;
4995         csb->csb_cmds[0] = FDRAW_SENSE_DRV;
4996         /* MOT bit set means don't delay */
4997         csb->csb_cmds[1] = MOT | (unit & 0x03);
4998         csb->csb_ncmds = 2;
4999         csb->csb_nrslts = 1;
5000         csb->csb_maxretry = skretry;
5001         csb->csb_retrys = 0;
5002 
5003         /* XXX for now ignore errors, they "CAN'T HAPPEN" */
5004         (void) fdexec(fdc, 0);  /* DON't check changed!, no sleep */
5005 
5006         FDERRPRINT(FDEP_L1, FDEM_CHEK,
5007             (C, "fdsensedrv: result 0x%x", csb->csb_rslt[0]));
5008 
5009         return (csb->csb_rslt[0]); /* return status byte 3 */
5010 }
5011 
5012 /*
5013  * fdcheckdisk
5014  *      check to see if the disk is still there - do a recalibrate,
5015  *      then see if DSKCHG line went away, if so, diskette is in; else
5016  *      it's (still) out.
5017  */
5018 
5019 static int
5020 fdcheckdisk(struct fdctlr *fdc, int unit)
5021 {
5022         auto struct fdcsb savecsb;
5023         struct fdcsb *csb;
5024         int     err, st3;
5025         int     seekto;                 /* where to seek for reset of DSKCHG */
5026 
5027         FDERRPRINT(FDEP_L1, FDEM_CHEK,
5028             (C, "fdcheckdisk, unit %d\n", unit));
5029 
5030         ASSERT(fdc->c_un->un_unit_no == unit);
5031 
5032         /*
5033          * save old csb
5034          */
5035 
5036         csb = &fdc->c_csb;
5037         savecsb = fdc->c_csb;
5038         bzero((caddr_t)csb, sizeof (*csb));
5039 
5040         /*
5041          * Read drive status to see if at TRK0, if so, seek to cyl 1,
5042          * else seek to cyl 0.  We do this because the controller is
5043          * "smart" enough to not send any step pulses (which are how
5044          * the DSKCHG line gets reset) if it sees TRK0 'cause it
5045          * knows the drive is already recalibrated.
5046          */
5047         st3 = fdsensedrv(fdc, unit);
5048 
5049         /* check TRK0 bit in status */
5050         if (st3 & T0_SR3)
5051                 seekto = 1;     /* at TRK0, seek out */
5052         else
5053                 seekto = 0;
5054 
5055         /*
5056          * DON'T recurse check changed
5057          */
5058         err = fdrecalseek(fdc, unit, seekto, 0);
5059 
5060         /* "restore" old csb, check change state */
5061         fdc->c_csb = savecsb;
5062 
5063         /* any recal/seek errors are too serious to attend to */
5064         if (err) {
5065                 FDERRPRINT(FDEP_L2, FDEM_CHEK,
5066                     (C, "fdcheckdisk err %d\n", err));
5067                 return (err);
5068         }
5069 
5070         /*
5071          * if disk change still asserted, no diskette in drive!
5072          */
5073         if (fdsense_chng(fdc, csb->csb_unit)) {
5074                 FDERRPRINT(FDEP_L2, FDEM_CHEK,
5075                     (C, "fdcheckdisk no disk\n"));
5076                 return (1);
5077         }
5078         return (0);
5079 }
5080 
5081 /*
5082  *      fdselect() - select drive, needed for external to chip select logic
5083  *      fdeject() - ejects drive, must be previously selected
5084  *      fdsense_chng() - sense disk changed line from previously selected drive
5085  *              return s 1 is signal asserted, else 0
5086  */
5087 /* ARGSUSED */
5088 static void
5089 fdselect(struct fdctlr *fdc, int unit, int on)
5090 {
5091 
5092         ASSERT(fdc->c_un->un_unit_no == unit);
5093 
5094         FDERRPRINT(FDEP_L1, FDEM_DSEL,
5095             (C, "fdselect, unit %d, on = %d\n", unit, on));
5096 
5097         switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
5098         case FDCTYPE_MACHIO:
5099                 set_auxioreg(AUX_DRVSELECT, on);
5100                 break;
5101 
5102         case FDCTYPE_SLAVIO:
5103         case FDCTYPE_CHEERIO:
5104                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
5105                     (C, "fdselect: (before) Dor 0x%x\n", Dor(fdc)));
5106 
5107                 if (unit == 0) {
5108                         Set_dor(fdc, DRVSEL, !on);
5109                 } else {
5110                         Set_dor(fdc, DRVSEL, on);
5111                 }
5112 
5113                 FDERRPRINT(FDEP_L1, FDEM_ATTA,
5114                     (C, "fdselect: Dor 0x%x\n", Dor(fdc)));
5115 
5116                 break;
5117 
5118         default:
5119                 break;
5120         }
5121 }
5122 
5123 /* ARGSUSED */
5124 static void
5125 fdeject(struct fdctlr *fdc, int unit)
5126 {
5127         struct fdunit *un;
5128 
5129         ASSERT(fdc->c_un->un_unit_no == unit);
5130 
5131         un = fdc->c_un;
5132 
5133         FDERRPRINT(FDEP_L1, FDEM_EJEC, (C, "fdeject\n"));
5134         /*
5135          * assume delay of function calling sufficient settling time
5136          * eject line is NOT driven by inverter so it is true low
5137          */
5138         switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
5139         case FDCTYPE_MACHIO:
5140                 set_auxioreg(AUX_EJECT, 0);
5141                 drv_usecwait(2);
5142                 set_auxioreg(AUX_EJECT, 1);
5143                 break;
5144 
5145         case FDCTYPE_SLAVIO:
5146                 if (!(Dor(fdc) & MOTEN(unit))) {
5147                         /* LINTED */
5148                         Set_dor(fdc, MOTEN(unit), 1);
5149                 }
5150                 drv_usecwait(2);        /* just to settle */
5151                 /* LINTED */
5152                 Set_dor(fdc, EJECT, 1);
5153                 drv_usecwait(2);
5154                 /* LINTED */
5155                 Set_dor(fdc, EJECT, 0);
5156                 break;
5157         case FDCTYPE_CHEERIO:
5158                 if (!(Dor(fdc) & MOTEN(unit))) {
5159                         /* LINTED */
5160                         Set_dor(fdc, MOTEN(unit), 1);
5161                 }
5162                 drv_usecwait(2);        /* just to settle */
5163                 /* LINTED */
5164                 Set_dor(fdc, EJECT_DMA, 1);
5165                 drv_usecwait(2);
5166                 /* LINTED */
5167                 Set_dor(fdc, EJECT_DMA, 0);
5168                 break;
5169         }
5170         /*
5171          * XXX set ejected state?
5172          */
5173         un->un_ejected = 1;
5174 }
5175 
5176 /* ARGSUSED */
5177 static int
5178 fdsense_chng(struct fdctlr *fdc, int unit)
5179 {
5180         int changed = 0;
5181 
5182         FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:start\n"));
5183 
5184         ASSERT(fdc->c_un->un_unit_no == unit);
5185 
5186         /*
5187          * Do not turn on the motor of a pollable drive
5188          */
5189         if (fd_pollable) {
5190         FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "pollable: don't turn on motor\n"));
5191                 /*
5192                  * Invert the sense of the DSKCHG for pollable drives
5193                  */
5194                 if (Dir(fdc) & DSKCHG)
5195                         changed = 0;
5196                 else
5197                         changed = 1;
5198 
5199                 return (changed);
5200         }
5201 
5202         switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
5203         case FDCTYPE_MACHIO:
5204                 if (*fdc->c_auxiova & AUX_DISKCHG)
5205                         changed = 1;
5206                 break;
5207 
5208         case FDCTYPE_SB:
5209         case FDCTYPE_SLAVIO:
5210         case FDCTYPE_CHEERIO:
5211                 if (!(Dor(fdc) & MOTEN(unit))) {
5212                         /* LINTED */
5213                         Set_dor(fdc, MOTEN(unit), 1);
5214                 }
5215                 drv_usecwait(2);        /* just to settle */
5216                 if (Dir(fdc) & DSKCHG)
5217                         changed = 1;
5218                 break;
5219         }
5220 
5221         FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:end\n"));
5222 
5223         return (changed);
5224 }
5225 
5226 /*
5227  *      if it can read a valid label it does so, else it will use a
5228  *      default.  If it can`t read the diskette - that is an error.
5229  *
5230  * RETURNS: 0 for ok - meaning that it could at least read the device,
5231  *      !0 for error XXX TBD NYD error codes
5232  *
5233  *      - called with the low level lock held
5234  */
5235 static int
5236 fdgetlabel(struct fdctlr *fdc, int unit)
5237 {
5238         struct dk_label *label = NULL;
5239         struct fdunit *un;
5240         short *sp;
5241         short count;
5242         short xsum;                     /* checksum */
5243         int     i, tries;
5244         int     err = 0;
5245         short   oldlvl;
5246 
5247         FDERRPRINT(FDEP_L1, FDEM_GETL,
5248             (C, "fdgetlabel: unit %d\n", unit));
5249 
5250         un = fdc->c_un;
5251         un->un_flags &= ~(FDUNIT_UNLABELED);
5252 
5253         ASSERT(fdc->c_un->un_unit_no == unit);
5254 
5255         /* Do not print errors since this is a private cmd */
5256 
5257         oldlvl = fderrlevel;
5258 
5259 
5260         fderrlevel = FDEP_L4;
5261 
5262         label = (struct dk_label *)
5263             kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
5264 
5265         /*
5266          * try different characteristics (ie densities) by attempting to read
5267          * from the diskette.  The diskette may not be present or
5268          * is unformatted.
5269          *
5270          * First, the last sector of the first track is read.  If this
5271          * passes, attempt to read the last sector + 1 of the first track.
5272          * For example, for a high density diskette, sector 18 is read.  If
5273          * the diskette is high density, this will pass.  Next, try to
5274          * read sector 19 of the first track.  This should fail.  If it
5275          * passes, this is not a high density diskette.  Finally, read
5276          * the first sector which should contain a label.
5277          *
5278          * if un->un_curfdtype is -1 then the current characteristics
5279          * were set by FDIOSCHAR and need to try it as well as everything
5280          * in the table
5281          */
5282         if (un->un_curfdtype == -1) {
5283                 tries = nfdtypes+1;
5284                 FDERRPRINT(FDEP_L1, FDEM_GETL,
5285                     (C, "fdgetl: un_curfdtype is -1\n"));
5286 
5287         } else {
5288                 tries = nfdtypes;
5289 
5290                 /* Always start with the highest density (1.7MB) */
5291                 un->un_curfdtype = 0;
5292                 *(un->un_chars) = fdtypes[un->un_curfdtype];
5293         }
5294 
5295         FDERRPRINT(FDEP_L1, FDEM_GETL,
5296             (C, "fdgetl: no. of tries %d\n", tries));
5297         FDERRPRINT(FDEP_L1, FDEM_GETL,
5298             (C, "fdgetl: no. of curfdtype %d\n", un->un_curfdtype));
5299 
5300         for (i = 0; i < tries; i++) {
5301                 FDERRPRINT(FDEP_L1, FDEM_GETL,
5302                     (C, "fdgetl: trying %d\n", i));
5303 
5304                 if (!(err = fdrw(fdc, unit, FDREAD, 0, 0,
5305                     un->un_chars->fdc_secptrack, (caddr_t)label,
5306                     sizeof (struct dk_label))) &&
5307 
5308                     fdrw(fdc, unit, FDREAD, 0, 0,
5309                     un->un_chars->fdc_secptrack + 1,
5310                     (caddr_t)label, sizeof (struct dk_label)) &&
5311 
5312                     !(err = fdrw(fdc, unit, FDREAD, 0, 0, 1, (caddr_t)label,
5313                     sizeof (struct dk_label)))) {
5314 
5315                         FDERRPRINT(FDEP_L1, FDEM_GETL,
5316                                 (C, "fdgetl: succeeded\n"));
5317 
5318                         break;
5319                 }
5320 
5321                 /*
5322                  * try the next entry in the characteristics tbl
5323                  * If curfdtype is -1, the nxt entry in tbl is 0 (the first).
5324                  */
5325 
5326                 un->un_curfdtype = (un->un_curfdtype + 1) % nfdtypes;
5327                 *(un->un_chars) = fdtypes[un->un_curfdtype];
5328 
5329 
5330         }
5331 
5332         /* print errors again */
5333         fderrlevel = oldlvl;
5334 
5335         /* Couldn't read anything */
5336         if (err) {
5337 
5338                 /* The default characteristics are high density (1.4MB) */
5339                 un->un_curfdtype = 1;
5340                 *(un->un_chars) = fdtypes[un->un_curfdtype];
5341 
5342                 fdunpacklabel(&fdlbl_high_80, &un->un_label);
5343 
5344                 FDERRPRINT(FDEP_L1, FDEM_GETL,
5345                     (C, "fdgetl: Can't autosense diskette\n"));
5346 
5347                 goto out;
5348         }
5349 
5350         FDERRPRINT(FDEP_L1, FDEM_GETL,
5351             (C, "fdgetl: fdtype=%d !!!\n", un->un_curfdtype));
5352         FDERRPRINT(FDEP_L1, FDEM_GETL,
5353             (C, "fdgetl: rate=%d ssize=%d !!!\n",
5354             un->un_chars->fdc_transfer_rate, un->un_chars->fdc_sec_size));
5355 
5356         /*
5357          * _something_ was read  -  look for unixtype label
5358          */
5359         if (label->dkl_magic != DKL_MAGIC) {
5360 
5361                 /*
5362                  * The label isn't a unix label.  However, the diskette
5363                  * is formatted because we were able to read the first
5364                  * cylinder.
5365                  */
5366 
5367                 FDERRPRINT(FDEP_L1, FDEM_GETL,
5368                     (C, "fdgetl: not unix label\n"));
5369 
5370                 goto nolabel;
5371         }
5372 
5373         /*
5374          * Checksum the label
5375          */
5376         count = sizeof (struct dk_label)/sizeof (short);
5377         sp = (short *)label;
5378         xsum = 0;
5379         while (count--)
5380                 xsum ^= *sp++;  /* should add up to 0 */
5381         if (xsum) {
5382 
5383                 /*
5384                  * The checksum fails.  However, the diskette is formatted
5385                  * because we were able to read the first cylinder
5386                  */
5387 
5388                 FDERRPRINT(FDEP_L1, FDEM_GETL,
5389                     (C, "fdgetl: bad cksum\n"));
5390 
5391                 goto nolabel;
5392         }
5393 
5394         /*
5395          * The diskette has a unix label with a correct checksum.
5396          * Copy the label into the unit structure
5397          */
5398         un->un_label = *label;
5399 
5400         goto out;
5401 
5402 nolabel:
5403         /*
5404          * The diskette doesn't have a correct unix label, but it is formatted.
5405          * Use a default label according to the diskette's density
5406          * (mark default used)
5407          */
5408         FDERRPRINT(FDEP_L1, FDEM_GETL,
5409             (C, "fdgetlabel: unit %d\n", unit));
5410         un->un_flags |= FDUNIT_UNLABELED;
5411         switch (un->un_chars->fdc_secptrack) {
5412         case 9:
5413                 fdunpacklabel(&fdlbl_low_80, &un->un_label);
5414                 break;
5415         case 8:
5416                 fdunpacklabel(&fdlbl_medium_80, &un->un_label);
5417                 break;
5418         case 18:
5419                 fdunpacklabel(&fdlbl_high_80, &un->un_label);
5420                 break;
5421         case 21:
5422                 fdunpacklabel(&fdlbl_high_21, &un->un_label);
5423                 break;
5424         default:
5425                 fdunpacklabel(&fdlbl_high_80, &un->un_label);
5426                 break;
5427         }
5428 
5429 out:
5430         if (label != NULL)
5431                 kmem_free((caddr_t)label, sizeof (struct dk_label));
5432         return (err);
5433 }
5434 
5435 /*
5436  * fdrw- used only for reading labels  and for DKIOCSVTOC ioctl
5437  *       which reads the 1 sector.
5438  */
5439 static int
5440 fdrw(struct fdctlr *fdc, int unit, int rw, int cyl, int head,
5441     int sector, caddr_t bufp, uint_t len)
5442 {
5443         struct fdcsb *csb;
5444         struct  fd_char *ch;
5445         int     cmdresult = 0;
5446         caddr_t dma_addr;
5447         size_t  real_length;
5448         int     res;
5449         ddi_device_acc_attr_t attr;
5450         ddi_acc_handle_t        mem_handle = NULL;
5451 
5452         FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw\n"));
5453 
5454         ASSERT(fdc->c_un->un_unit_no == unit);
5455 
5456         CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
5457 
5458         if (fdc->c_un->un_state == FD_STATE_STOPPED) {
5459                 mutex_exit(&fdc->c_lolock);
5460                 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
5461                     != DDI_SUCCESS) {
5462                         FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
5463                             failed. \n"));
5464                         mutex_enter(&fdc->c_lolock);
5465                         return (EIO);
5466                 }
5467 
5468                 mutex_enter(&fdc->c_lolock);
5469         }
5470 
5471         fdgetcsb(fdc);
5472         csb = &fdc->c_csb;
5473         ch = fdc->c_un->un_chars;
5474         if (rw == FDREAD) {
5475                 if (fdc->c_fdtype & FDCTYPE_TCBUG) {
5476                         /*
5477                          * kludge for lack of Multitrack functionality
5478                          */
5479                         csb->csb_cmds[0] = SK + FDRAW_RDCMD;
5480                 } else
5481                         csb->csb_cmds[0] = MT + SK + FDRAW_RDCMD;
5482         } else { /* write */
5483                 if (fdc->c_fdtype & FDCTYPE_TCBUG) {
5484                         /*
5485                          * kludge for lack of Multitrack functionality
5486                          */
5487                         csb->csb_cmds[0] = FDRAW_WRCMD;
5488                 } else
5489                         csb->csb_cmds[0] = MT + FDRAW_WRCMD;
5490         }
5491 
5492         if (rw == FDREAD)
5493                 fdc->c_csb.csb_read = CSB_READ;
5494         else
5495                 fdc->c_csb.csb_read = CSB_WRITE;
5496 
5497         /* always or in MFM bit */
5498         csb->csb_cmds[0] |= MFM;
5499         csb->csb_cmds[1] = (uchar_t)(unit | ((head & 0x1) << 2));
5500         if (fdc->c_fdtype & FDCTYPE_SB)
5501                 csb->csb_cmds[1] |= IPS;
5502         csb->csb_cmds[2] = (uchar_t)cyl;
5503         csb->csb_cmds[3] = (uchar_t)head;
5504         csb->csb_cmds[4] = (uchar_t)sector;
5505         csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size code */
5506         /*
5507          * kludge for end-of-cylinder error.
5508          */
5509         if (fdc->c_fdtype & FDCTYPE_TCBUG)
5510                 csb->csb_cmds[6] = sector + (len / ch->fdc_sec_size) - 1;
5511         else
5512                 csb->csb_cmds[6] =
5513                     (uchar_t)max(fdc->c_un->un_chars->fdc_secptrack, sector);
5514         csb->csb_len = len;
5515         csb->csb_cmds[7] = GPLN;
5516         csb->csb_cmds[8] = SSSDTL;
5517         csb->csb_ncmds = NCBRW;
5518         csb->csb_len = len;
5519         csb->csb_maxretry = 2;
5520         csb->csb_retrys = 0;
5521         bzero(csb->csb_rslt, NRBRW);
5522         csb->csb_nrslts = NRBRW;
5523         csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
5524 
5525         /* If platform supports DMA, set up DMA resources */
5526         if (fdc->c_fdtype & FDCTYPE_DMA) {
5527 
5528                 mutex_enter(&fdc->c_hilock);
5529 
5530                 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5531                 attr.devacc_attr_endian_flags  = DDI_STRUCTURE_BE_ACC;
5532                 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5533 
5534                 res = ddi_dma_mem_alloc(fdc->c_dmahandle, len,
5535                     &attr, DDI_DMA_STREAMING,
5536                     DDI_DMA_DONTWAIT, 0, &dma_addr, &real_length,
5537                     &mem_handle);
5538 
5539                 if (res != DDI_SUCCESS) {
5540                         FDERRPRINT(FDEP_L1, FDEM_RW,
5541                             (C, "fdrw: dma mem alloc failed\n"));
5542 
5543                         fdretcsb(fdc);
5544                         mutex_exit(&fdc->c_hilock);
5545                         return (EIO);
5546                 }
5547 
5548                 FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: allocated memory"));
5549 
5550                 if (fdstart_dma(fdc, dma_addr, len) != 0) {
5551                         fdretcsb(fdc);
5552                         ddi_dma_mem_free(&mem_handle);
5553                         mutex_exit(&fdc->c_hilock);
5554                         return (-1);
5555 
5556                 }
5557 
5558                 /*
5559                  * If the command is a write, copy the data to be written to
5560                  * dma_addr.
5561                  */
5562 
5563                 if (fdc->c_csb.csb_read == CSB_WRITE) {
5564                         bcopy((char *)bufp, (char *)dma_addr, len);
5565                 }
5566 
5567                 csb->csb_addr = dma_addr;
5568                 mutex_exit(&fdc->c_hilock);
5569         } else {
5570                 csb->csb_addr = bufp;
5571         }
5572 
5573 
5574         FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: call fdexec\n"));
5575 
5576         if (fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG) != 0) {
5577                 fdretcsb(fdc);
5578 
5579                 if (mem_handle)
5580                         ddi_dma_mem_free(&mem_handle);
5581 
5582                 return (EIO);
5583 
5584         }
5585 
5586         FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: fdexec returned\n"));
5587 
5588         /*
5589          * if DMA was used and the command was a read
5590          * copy the results into bufp
5591          */
5592         if (fdc->c_fdtype & FDCTYPE_DMA) {
5593                 if (fdc->c_csb.csb_read == CSB_READ) {
5594                         bcopy((char *)dma_addr, (char *)bufp, len);
5595                 }
5596                 ddi_dma_mem_free(&mem_handle);
5597         }
5598 
5599         if (csb->csb_cmdstat)
5600                 cmdresult = EIO;        /* XXX TBD NYD for now */
5601 
5602         fdretcsb(fdc);
5603         return (cmdresult);
5604 }
5605 
5606 /*
5607  * fdunpacklabel
5608  *      this unpacks a (packed) struct dk_label into a standard dk_label.
5609  */
5610 static void
5611 fdunpacklabel(struct packed_label *from, struct dk_label *to)
5612 {
5613         FDERRPRINT(FDEP_L1, FDEM_PACK, (C, "fdpacklabel\n"));
5614         bzero((caddr_t)to, sizeof (*to));
5615         bcopy((caddr_t)&from->dkl_vname, (caddr_t)to->dkl_asciilabel,
5616             sizeof (to->dkl_asciilabel));
5617         to->dkl_rpm = from->dkl_rpm;      /* rotations per minute */
5618         to->dkl_pcyl = from->dkl_pcyl;    /* # physical cylinders */
5619         to->dkl_apc = from->dkl_apc;      /* alternates per cylinder */
5620         to->dkl_intrlv = from->dkl_intrlv;        /* interleave factor */
5621         to->dkl_ncyl = from->dkl_ncyl;    /* # of data cylinders */
5622         to->dkl_acyl = from->dkl_acyl;    /* # of alternate cylinders */
5623         to->dkl_nhead = from->dkl_nhead; /* # of heads in this partition */
5624         to->dkl_nsect = from->dkl_nsect; /* # of 512 byte sectors per track */
5625         /* logical partitions */
5626         bcopy((caddr_t)from->dkl_map, (caddr_t)to->dkl_map,
5627             sizeof (struct dk_map32) * NDKMAP);
5628         to->dkl_vtoc = from->dkl_vtoc;
5629 }
5630 
5631 static struct fdctlr *
5632 fd_getctlr(dev_t dev)
5633 {
5634 
5635         struct fdctlr *fdc = fdctlrs;
5636         int ctlr = FDCTLR(dev);
5637 
5638         while (fdc) {
5639                 if (ddi_get_instance(fdc->c_dip) == ctlr)
5640                         return (fdc);
5641                 fdc = fdc->c_next;
5642         }
5643         return (fdc);
5644 }
5645 
5646 static int
5647 fd_unit_is_open(struct fdunit *un)
5648 {
5649         int i;
5650         for (i = 0; i < NDKMAP; i++)
5651                 if (un->un_lyropen[i])
5652                         return (1);
5653         for (i = 0; i < OTYPCNT - 1; i++)
5654                 if (un->un_regopen[i])
5655                         return (1);
5656         return (0);
5657 }
5658 
5659 /*
5660  * Return the a vtoc structure in *vtoc.
5661  * The vtoc is built from information in
5662  * the diskette's label.
5663  */
5664 static void
5665 fd_build_user_vtoc(struct fdunit *un, struct vtoc *vtoc)
5666 {
5667         int i;
5668         int nblks;                      /* DEV_BSIZE sectors per cylinder */
5669         struct dk_map2 *lpart;
5670         struct dk_map32 *lmap;
5671         struct partition *vpart;
5672 
5673         bzero(vtoc, sizeof (struct vtoc));
5674 
5675         /* Initialize info. needed by mboot.  (unsupported) */
5676         vtoc->v_bootinfo[0] = un->un_label.dkl_vtoc.v_bootinfo[0];
5677         vtoc->v_bootinfo[1] = un->un_label.dkl_vtoc.v_bootinfo[1];
5678         vtoc->v_bootinfo[2] = un->un_label.dkl_vtoc.v_bootinfo[2];
5679 
5680         /* Fill in vtoc sanity and version information */
5681         vtoc->v_sanity               = un->un_label.dkl_vtoc.v_sanity;
5682         vtoc->v_version              = un->un_label.dkl_vtoc.v_version;
5683 
5684         /* Copy the volume name */
5685         bcopy(un->un_label.dkl_vtoc.v_volume,
5686             vtoc->v_volume, LEN_DKL_VVOL);
5687 
5688         /*
5689          * The dk_map32 structure is based on DEV_BSIZE byte blocks.
5690          * However, medium density diskettes have 1024 byte blocks.
5691          * The number of sectors per partition listed in the dk_map32 structure
5692          * accounts for this by multiplying the number of 1024 byte
5693          * blocks by 2.  (See the packed_label initializations.)  The
5694          * 1024 byte block size can not be listed for medium density
5695          * diskettes because the kernel is hard coded for DEV_BSIZE
5696          * blocks.
5697          */
5698         vtoc->v_sectorsz = DEV_BSIZE;
5699         vtoc->v_nparts = un->un_label.dkl_vtoc.v_nparts;
5700 
5701         /* Copy the reserved space */
5702         bcopy(un->un_label.dkl_vtoc.v_reserved,
5703             vtoc->v_reserved, sizeof (un->un_label.dkl_vtoc.v_reserved));
5704         /*
5705          * Convert partitioning information.
5706          *
5707          * Note the conversion from starting cylinder number
5708          * to starting sector number.
5709          */
5710         lmap = un->un_label.dkl_map;
5711         lpart = un->un_label.dkl_vtoc.v_part;
5712         vpart = vtoc->v_part;
5713 
5714         nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
5715             un->un_chars->fdc_sec_size) / DEV_BSIZE;
5716 
5717         for (i = 0; i < V_NUMPAR; i++) {
5718                 vpart->p_tag = lpart->p_tag;
5719                 vpart->p_flag        = lpart->p_flag;
5720                 vpart->p_start       = lmap->dkl_cylno * nblks;
5721                 vpart->p_size        = lmap->dkl_nblk;
5722 
5723                 lmap++;
5724                 lpart++;
5725                 vpart++;
5726         }
5727 
5728         /* Initialize timestamp and label */
5729         bcopy(un->un_label.dkl_vtoc.v_timestamp,
5730             vtoc->timestamp, sizeof (vtoc->timestamp));
5731 
5732         bcopy(un->un_label.dkl_asciilabel,
5733             vtoc->v_asciilabel, LEN_DKL_ASCII);
5734 }
5735 
5736 /*
5737  * Build a label out of a vtoc structure.
5738  */
5739 static int
5740 fd_build_label_vtoc(struct fdunit *un, struct vtoc *vtoc)
5741 {
5742         struct dk_map32         *lmap;
5743         struct dk_map2          *lpart;
5744         struct partition        *vpart;
5745         int                     nblks;  /* no. blocks per cylinder */
5746         int                     ncyl;
5747         int                     i;
5748         short    sum, *sp;
5749 
5750         /* Sanity-check the vtoc */
5751         if ((vtoc->v_sanity != VTOC_SANE) ||
5752             (vtoc->v_nparts > NDKMAP) || (vtoc->v_nparts <= 0)) {
5753                 FDERRPRINT(FDEP_L1, FDEM_IOCT,
5754                     (C, "fd_build_label:  sanity check on vtoc failed\n"));
5755                 return (EINVAL);
5756         }
5757 
5758         nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
5759             un->un_chars->fdc_sec_size) / DEV_BSIZE;
5760 
5761         vpart = vtoc->v_part;
5762 
5763         /*
5764          * Check the partition information in the vtoc.  The starting sectors
5765          * must lie along partition boundaries. (NDKMAP entries are checked
5766          * to ensure that the unused entries are set to 0 if vtoc->v_nparts
5767          * is less than NDKMAP)
5768          */
5769 
5770         for (i = 0; i < NDKMAP; i++) {
5771                 if ((vpart->p_start % nblks) != 0) {
5772                         return (EINVAL);
5773                 }
5774                 ncyl = vpart->p_start % nblks;
5775                 ncyl += vpart->p_size % nblks;
5776                 if ((vpart->p_size % nblks) != 0)
5777                         ncyl++;
5778                 if (ncyl > un->un_chars->fdc_ncyl) {
5779                         return (EINVAL);
5780                 }
5781                 vpart++;
5782         }
5783 
5784         /*
5785          * reinitialize the existing label
5786          */
5787         bzero(&un->un_label, sizeof (un->un_label));
5788 
5789         /* Put appropriate vtoc structure fields into the disk label */
5790         un->un_label.dkl_vtoc.v_bootinfo[0] = (uint32_t)vtoc->v_bootinfo[0];
5791         un->un_label.dkl_vtoc.v_bootinfo[1] = (uint32_t)vtoc->v_bootinfo[1];
5792         un->un_label.dkl_vtoc.v_bootinfo[2] = (uint32_t)vtoc->v_bootinfo[2];
5793 
5794         un->un_label.dkl_vtoc.v_sanity = vtoc->v_sanity;
5795         un->un_label.dkl_vtoc.v_version = vtoc->v_version;
5796 
5797         bcopy(vtoc->v_volume, un->un_label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
5798 
5799         un->un_label.dkl_vtoc.v_nparts = vtoc->v_nparts;
5800 
5801         bcopy(vtoc->v_reserved, un->un_label.dkl_vtoc.v_reserved,
5802             sizeof (un->un_label.dkl_vtoc.v_reserved));
5803 
5804         /*
5805          * Initialize cylinder information in the label.
5806          * Note the conversion from starting sector number
5807          * to starting cylinder number.
5808          * Return error if division results in a remainder.
5809          */
5810         lmap = un->un_label.dkl_map;
5811         lpart = un->un_label.dkl_vtoc.v_part;
5812         vpart = vtoc->v_part;
5813 
5814         for (i = 0; i < (int)vtoc->v_nparts; i++) {
5815                 lpart->p_tag  = vtoc->v_part[i].p_tag;
5816                 lpart->p_flag = vtoc->v_part[i].p_flag;
5817                 lmap->dkl_cylno = vpart->p_start / nblks;
5818                 lmap->dkl_nblk = vpart->p_size;
5819 
5820                 lmap++;
5821                 lpart++;
5822                 vpart++;
5823         }
5824 
5825         /* Copy the timestamp and ascii label */
5826         for (i = 0; i < NDKMAP; i++) {
5827                 un->un_label.dkl_vtoc.v_timestamp[i] = vtoc->timestamp[i];
5828         }
5829 
5830 
5831         bcopy(vtoc->v_asciilabel, un->un_label.dkl_asciilabel, LEN_DKL_ASCII);
5832 
5833         FDERRPRINT(FDEP_L1, FDEM_IOCT,
5834             (C, "fd_build_label: asciilabel %s\n",
5835             un->un_label.dkl_asciilabel));
5836 
5837         /* Initialize the magic number */
5838         un->un_label.dkl_magic = DKL_MAGIC;
5839 
5840         un->un_label.dkl_pcyl = un->un_chars->fdc_ncyl;
5841 
5842         /*
5843          * The fdc_secptrack filed of the fd_char structure is the number
5844          * of sectors per track where the sectors are fdc_sec_size.  The
5845          * dkl_nsect field of the dk_label structure is the number of
5846          * 512 (DEVBSIZE) byte sectors per track.
5847          */
5848         un->un_label.dkl_nsect = (un->un_chars->fdc_secptrack *
5849             un->un_chars->fdc_sec_size) / DEV_BSIZE;
5850 
5851 
5852         un->un_label.dkl_ncyl = un->un_label.dkl_pcyl;
5853         un->un_label.dkl_nhead = un->un_chars->fdc_nhead;
5854         un->un_label.dkl_rpm = un->un_chars->fdc_medium ? 360 : 300;
5855         un->un_label.dkl_intrlv = 1;
5856 
5857         /* Create the checksum */
5858         sum = 0;
5859         un->un_label.dkl_cksum = 0;
5860         sp = (short *)&un->un_label;
5861         i = sizeof (struct dk_label)/sizeof (short);
5862         while (i--) {
5863                 sum ^= *sp++;
5864         }
5865         un->un_label.dkl_cksum = sum;
5866 
5867         return (0);
5868 }
5869 
5870 /*
5871  * Check for auxio register node
5872  */
5873 
5874 int
5875 fd_isauxiodip(dev_info_t *dip)
5876 {
5877         if (strcmp(ddi_get_name(dip), "auxio") == 0 ||
5878             strcmp(ddi_get_name(dip), "auxiliary-io") == 0) {
5879                 return (1);
5880         }
5881         return (0);
5882 }
5883 
5884 /*
5885  * Search for auxio register node, then for address property
5886  */
5887 
5888 caddr_t
5889 fd_getauxiova(dev_info_t *dip)
5890 {
5891         dev_info_t *auxdip;
5892         caddr_t addr;
5893 
5894         /*
5895          * Search sibling list, which happens to be safe inside attach
5896          */
5897         auxdip = ddi_get_child(ddi_get_parent(dip));
5898         while (auxdip) {
5899                 if (fd_isauxiodip(auxdip))
5900                         break;
5901                 auxdip = ddi_get_next_sibling(auxdip);
5902         }
5903 
5904         if (auxdip == NULL)
5905                 return (NULL);
5906 
5907         addr = (caddr_t)(uintptr_t)(caddr32_t)ddi_getprop(DDI_DEV_T_ANY,
5908             auxdip, DDI_PROP_DONTPASS, "address", 0);
5909 
5910         return (addr);
5911 }
5912 
5913 
5914 /*
5915  * set_rotational speed
5916  * 300 rpm for high and low density.
5917  * 360 rpm for medium density.
5918  * for now, we assume that 3rd density is supported only for Sun4M,
5919  * not for Clones. (else we would have to check for 82077, and do
5920  * specific things for the MEDIUM_DENSITY BIT for clones.
5921  * this code should not break CLONES.
5922  *
5923  * REMARK: there is a SOny requirement, to deselect the drive then
5924  * select it again after the medium density change, since the
5925  * leading edge of the select line latches the rotational Speed.
5926  * then after that, we have to wait 500 ms for the rotation to
5927  * stabilize.
5928  *
5929  */
5930 static void
5931 set_rotational_speed(struct fdctlr *fdc, int unit)
5932 {
5933         int check;
5934         int is_medium;
5935 
5936         ASSERT(fdc->c_un->un_unit_no == unit);
5937 
5938         /*
5939          * if we do not have a Sun4m, medium density is not supported.
5940          */
5941         if (fdc->c_fdtype & FDCTYPE_MACHIO)
5942                 return;
5943 
5944         /*
5945          * if FDUNIT_SET_SPEED is set, set the speed.
5946          * else,
5947          *      if there is a change, do it, if not leave it alone.
5948          *      there is a change if un->un_chars->fdc_medium does not match
5949          *      un->un_flags & FDUNIT_MEDIUM
5950          *      un->un_flags & FDUNIT_MEDIUM specifies the last setting.
5951          *      un->un_chars->fdc_medium specifies next setting.
5952          *      if there is a change, wait 500ms according to Sony spec.
5953          */
5954 
5955         is_medium = fdc->c_un->un_chars->fdc_medium;
5956 
5957         if (fdc->c_un->un_flags & FDUNIT_SET_SPEED) {
5958                 check = 1;
5959         } else {
5960                 check = is_medium ^
5961                     ((fdc->c_un->un_flags & FDUNIT_MEDIUM) ? 1 : 0);
5962 
5963                 /* Set the un_flags if necessary */
5964 
5965                 if (check)
5966                         fdc->c_un->un_flags ^= FDUNIT_MEDIUM;
5967         }
5968 
5969         fdc->c_un->un_flags &= ~FDUNIT_SET_SPEED;
5970 
5971 
5972         if (check) {
5973 
5974                 fdselect(fdc, unit, 0);
5975                 drv_usecwait(5);
5976 
5977                 if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_SLAVIO) {
5978                         Set_dor(fdc, MEDIUM_DENSITY, is_medium);
5979                 }
5980 
5981                 if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_CHEERIO) {
5982                         if (is_medium) {
5983                                 Set_auxio(fdc, AUX_MEDIUM_DENSITY);
5984                         } else {
5985                                 Set_auxio(fdc, AUX_HIGH_DENSITY);
5986                         }
5987 
5988                 }
5989 
5990                 if (is_medium) {
5991                         drv_usecwait(5);
5992                 }
5993 
5994                 fdselect(fdc, unit, 1); /* Sony requirement */
5995                 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "rotation:medium\n"));
5996                 drv_usecwait(500000);
5997         }
5998 }
5999 
6000 static void
6001 fd_media_watch(void *arg)
6002 {
6003         dev_t           dev;
6004         struct fdunit *un;
6005         struct fdctlr *fdc;
6006         int             unit;
6007 
6008         dev = (dev_t)arg;
6009         fdc = fd_getctlr(dev);
6010         unit = fdc->c_un->un_unit_no;
6011         un = fdc->c_un;
6012 
6013         mutex_enter(&fdc->c_lolock);
6014 
6015         if (un->un_media_timeout_id == 0) {
6016                 /*
6017                  * Untimeout is about to be called.
6018                  * Don't call fd_get_media_state again
6019                  */
6020                 mutex_exit(&fdc->c_lolock);
6021                 return;
6022         }
6023 
6024 
6025         un->un_media_state = fd_get_media_state(fdc, unit);
6026         cv_broadcast(&fdc->c_statecv);
6027 
6028         mutex_exit(&fdc->c_lolock);
6029 
6030         if (un->un_media_timeout) {
6031                 un->un_media_timeout_id = timeout(fd_media_watch,
6032                     (void *)(ulong_t)dev, un->un_media_timeout);
6033         }
6034 }
6035 
6036 enum dkio_state
6037 fd_get_media_state(struct fdctlr *fdc, int unit)
6038 {
6039         enum dkio_state state;
6040 
6041         ASSERT(fdc->c_un->un_unit_no == unit);
6042 
6043         if (fdsense_chng(fdc, unit)) {
6044                 /* check disk only if DSKCHG "high" */
6045                 if (fdcheckdisk(fdc, unit)) {
6046                         state = DKIO_EJECTED;
6047                 } else {
6048                         state = DKIO_INSERTED;
6049                 }
6050         } else {
6051                 state = DKIO_INSERTED;
6052         }
6053         return (state);
6054 }
6055 
6056 static int
6057 fd_check_media(dev_t dev, enum dkio_state state)
6058 {
6059         struct fdunit *un;
6060         struct fdctlr *fdc;
6061         int             unit;
6062 
6063         FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: start\n"));
6064 
6065         fdc = fd_getctlr(dev);
6066         unit = fdc->c_un->un_unit_no;
6067         un = fdc->c_un;
6068 
6069         mutex_enter(&fdc->c_lolock);
6070 
6071         CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
6072 
6073         if (fdc->c_un->un_state == FD_STATE_STOPPED) {
6074                 mutex_exit(&fdc->c_lolock);
6075                 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
6076                     != DDI_SUCCESS) {
6077                         FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
6078                             failed. \n"));
6079 
6080                         (void) pm_idle_component(fdc->c_dip, 0);
6081                         return (EIO);
6082                 }
6083 
6084                 mutex_enter(&fdc->c_lolock);
6085         }
6086 
6087         un->un_media_state = fd_get_media_state(fdc, unit);
6088 
6089         /* turn on timeout */
6090         un->un_media_timeout = drv_usectohz(fd_check_media_time);
6091         un->un_media_timeout_id = timeout(fd_media_watch,
6092             (void *)(ulong_t)dev, un->un_media_timeout);
6093 
6094         while (un->un_media_state == state) {
6095                 if (cv_wait_sig(&fdc->c_statecv, &fdc->c_lolock) == 0) {
6096                         un->un_media_timeout = 0;
6097                         mutex_exit(&fdc->c_lolock);
6098                         return (EINTR);
6099                 }
6100         }
6101 
6102         if (un->un_media_timeout_id) {
6103                 timeout_id_t timeid = un->un_media_timeout_id;
6104                 un->un_media_timeout_id = 0;
6105 
6106                 mutex_exit(&fdc->c_lolock);
6107                 (void) untimeout(timeid);
6108                 mutex_enter(&fdc->c_lolock);
6109         }
6110 
6111         if (un->un_media_state == DKIO_INSERTED) {
6112                 if (fdgetlabel(fdc, unit)) {
6113                         mutex_exit(&fdc->c_lolock);
6114                         return (EIO);
6115                 }
6116         }
6117         mutex_exit(&fdc->c_lolock);
6118 
6119         FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: end\n"));
6120         return (0);
6121 }
6122 
6123 /*
6124  * fd_get_media_info :
6125  *      Collects medium information for
6126  *      DKIOCGMEDIAINFO ioctl.
6127  */
6128 
6129 static int
6130 fd_get_media_info(struct fdunit *un, caddr_t buf, int flag)
6131 {
6132         struct dk_minfo media_info;
6133         int err = 0;
6134 
6135         media_info.dki_media_type = DK_FLOPPY;
6136         media_info.dki_lbsize = un->un_chars->fdc_sec_size;
6137         media_info.dki_capacity = un->un_chars->fdc_ncyl *
6138             un->un_chars->fdc_secptrack * un->un_chars->fdc_nhead;
6139 
6140         if (ddi_copyout((caddr_t)&media_info, buf,
6141             sizeof (struct dk_minfo), flag))
6142                 err = EFAULT;
6143         return (err);
6144 }
6145 
6146 /*
6147  * fd_power :
6148  *      Power entry point of fd driver.
6149  */
6150 
6151 static int
6152 fd_power(dev_info_t *dip, int component, int level)
6153 {
6154 
6155         struct fdctlr *fdc;
6156         int instance;
6157         int rval;
6158 
6159         if ((level < PM_LEVEL_OFF) || (level > PM_LEVEL_ON) ||
6160             (component != 0)) {
6161                 return (DDI_FAILURE);
6162         }
6163 
6164         instance = ddi_get_instance(dip);
6165         fdc = fd_getctlr(instance << FDINSTSHIFT);
6166         if (fdc->c_un == NULL)
6167                 return (DDI_FAILURE);
6168 
6169         if (level == PM_LEVEL_OFF) {
6170                 rval = fd_pm_lower_power(fdc);
6171         }
6172         if (level == PM_LEVEL_ON) {
6173                 rval = fd_pm_raise_power(fdc);
6174         }
6175         return (rval);
6176 }
6177 
6178 /*
6179  * fd_pm_lower_power :
6180  *      This function is called only during pm suspend. At this point,
6181  *      the power management framework thinks the device is idle for
6182  *      long enough to go to a low power mode. If the device is busy,
6183  *      then this function returns DDI_FAILURE.
6184  */
6185 
6186 static int
6187 fd_pm_lower_power(struct fdctlr *fdc)
6188 {
6189 
6190         mutex_enter(&fdc->c_lolock);
6191 
6192         if ((fdc->c_un->un_state == FD_STATE_SUSPENDED) ||
6193             (fdc->c_un->un_state == FD_STATE_STOPPED)) {
6194                 mutex_exit(&fdc->c_lolock);
6195                 return (DDI_SUCCESS);
6196         }
6197 
6198 
6199         FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_lower_power called\n"));
6200 
6201         /* if the device is busy then we fail the lower power request */
6202         if (fdc->c_flags & FDCFLG_BUSY) {
6203                 FDERRPRINT(FDEP_L2, FDEM_PWR, (C, "fd_pm_lower_power : \
6204 controller is busy.\n"));
6205                 mutex_exit(&fdc->c_lolock);
6206                 return (DDI_FAILURE);
6207         }
6208 
6209         fdc->c_un->un_state = FD_STATE_STOPPED;
6210 
6211         mutex_exit(&fdc->c_lolock);
6212         return (DDI_SUCCESS);
6213 }
6214 
6215 /*
6216  * fd_pm_raise_power :
6217  *      This function performs the necessary steps for resuming a
6218  *      device, either from pm suspend or CPR. Here the controller
6219  *      is reset, initialized and the state is set to FD_STATE_NORMAL.
6220  */
6221 
6222 static int
6223 fd_pm_raise_power(struct fdctlr *fdc)
6224 {
6225 
6226         struct fdunit *un = fdc->c_un;
6227         int unit;
6228 
6229         FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_raise_power called\n"));
6230         mutex_enter(&fdc->c_lolock);
6231         fdgetcsb(fdc);
6232 
6233         /* Reset the dma engine */
6234         if (fdc->c_fdtype & FDCTYPE_DMA) {
6235                 mutex_enter(&fdc->c_hilock);
6236                 reset_dma_controller(fdc);
6237                 set_dma_control_register(fdc, DCSR_INIT_BITS);
6238                 mutex_exit(&fdc->c_hilock);
6239         }
6240 
6241         /*
6242          * Force a rotational speed set in the next
6243          * call to set_rotational_speed().
6244          */
6245 
6246         fdc->c_un->un_flags |= FDUNIT_SET_SPEED;
6247 
6248         /* Reset and configure the controller */
6249         (void) fdreset(fdc);
6250 
6251         unit = fdc->c_un->un_unit_no;
6252 
6253         /* Recalibrate the drive */
6254         if (fdrecalseek(fdc, unit, -1, 0) != 0) {
6255                 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "raise_power : recalibrate \
6256 failed\n"));
6257                 fdretcsb(fdc);
6258                 mutex_exit(&fdc->c_lolock);
6259                 return (DDI_FAILURE);
6260         }
6261 
6262         /* Select the drive through the AUXIO registers */
6263         fdselect(fdc, unit, 0);
6264         un->un_state = FD_STATE_NORMAL;
6265         fdretcsb(fdc);
6266         mutex_exit(&fdc->c_lolock);
6267         return (DDI_SUCCESS);
6268 }
6269 
6270 /*
6271  * create_pm_components :
6272  *      creates the power management components for auto pm framework.
6273  */
6274 
6275 static void
6276 create_pm_components(dev_info_t *dip)
6277 {
6278         char    *un_pm_comp[] = { "NAME=spindle-motor", "0=off", "1=on"};
6279 
6280         if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
6281             "pm-components", un_pm_comp, 3) == DDI_PROP_SUCCESS) {
6282 
6283                 (void) pm_raise_power(dip, 0, PM_LEVEL_ON);
6284         }
6285 }
6286 
6287 /*
6288  * set_data_count_register(struct fdctlr *fdc, uint32_t count)
6289  *      Set the data count in appropriate dma register.
6290  */
6291 
6292 static void
6293 set_data_count_register(struct fdctlr *fdc, uint32_t count)
6294 {
6295         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6296                 struct cheerio_dma_reg *dma_reg;
6297                 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6298                 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr, count);
6299         } else if (fdc->c_fdtype & FDCTYPE_SB) {
6300                 struct sb_dma_reg *dma_reg;
6301                 count = count - 1; /* 8237 needs it */
6302                 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6303                 switch (fdc->sb_dma_channel) {
6304                 case 0 :
6305                         ddi_put16(fdc->c_handlep_dma,
6306                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT],
6307                             count & 0xFFFF);
6308                         break;
6309                 case 1 :
6310                         ddi_put16(fdc->c_handlep_dma,
6311                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT],
6312                             count & 0xFFFF);
6313                         break;
6314                 case 2 :
6315                         ddi_put16(fdc->c_handlep_dma,
6316                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT],
6317                             count & 0xFFFF);
6318                         break;
6319                 case 3 :
6320                         ddi_put16(fdc->c_handlep_dma,
6321                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT],
6322                             count & 0xFFFF);
6323                         break;
6324                 default :
6325                         FDERRPRINT(FDEP_L3, FDEM_SDMA,
6326                             (C, "set_data_count: wrong channel %x\n",
6327                             fdc->sb_dma_channel));
6328                         break;
6329                 }
6330         }
6331 }
6332 
6333 /*
6334  * get_data_count_register(struct fdctlr *fdc)
6335  *      Read the data count from appropriate dma register.
6336  */
6337 
6338 static uint32_t
6339 get_data_count_register(struct fdctlr *fdc)
6340 {
6341         uint32_t retval = 0;
6342         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6343                 struct cheerio_dma_reg *dma_reg;
6344                 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6345                 retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr);
6346         } else if (fdc->c_fdtype & FDCTYPE_SB) {
6347                 struct sb_dma_reg *dma_reg;
6348                 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6349                 switch (fdc->sb_dma_channel) {
6350                 case 0 :
6351                         retval = ddi_get16(fdc->c_handlep_dma,
6352                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT]);
6353                         break;
6354                 case 1 :
6355                         retval = ddi_get16(fdc->c_handlep_dma,
6356                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT]);
6357                         break;
6358                 case 2 :
6359                         retval = ddi_get16(fdc->c_handlep_dma,
6360                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT]);
6361                         break;
6362                 case 3 :
6363                         retval = ddi_get16(fdc->c_handlep_dma,
6364                             (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT]);
6365                         break;
6366                 default :
6367                         FDERRPRINT(FDEP_L3, FDEM_SDMA,
6368                             (C, "get_data_count: wrong channel %x\n",
6369                             fdc->sb_dma_channel));
6370                         break;
6371                 }
6372                 retval = (uint32_t)((uint16_t)(retval +1));
6373         }
6374 
6375         return (retval);
6376 
6377 }
6378 
6379 /*
6380  * reset_dma_controller(struct fdctlr *fdc)
6381  *      Reset and initialize the dma controller.
6382  */
6383 
6384 static void
6385 reset_dma_controller(struct fdctlr *fdc)
6386 {
6387         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6388                 struct cheerio_dma_reg *dma_reg;
6389                 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6390                 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, DCSR_RESET);
6391                 while (get_dma_control_register(fdc) & DCSR_CYC_PEND)
6392                         ;
6393                 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, 0);
6394         } else if (fdc->c_fdtype & FDCTYPE_SB) {
6395                 struct sb_dma_reg *dma_reg;
6396                 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6397                 ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MASK],
6398                     (fdc->sb_dma_channel & 0x3));
6399 
6400         }
6401 }
6402 
6403 /*
6404  * Get the DMA control register for CHEERIO.
6405  * For SouthBridge 8237 DMA controller, this register is not valid.
6406  * So, just return 0.
6407  */
6408 static uint32_t
6409 get_dma_control_register(struct fdctlr *fdc)
6410 {
6411         uint32_t retval = 0;
6412         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6413                 struct cheerio_dma_reg *dma_reg;
6414                 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6415                 retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr);
6416         }
6417 
6418         return (retval);
6419 }
6420 
6421 
6422 /*
6423  * set_data_address_register(struct fdctlr *fdc)
6424  *      Set the data address in appropriate dma register.
6425  */
6426 static void
6427 set_data_address_register(struct fdctlr *fdc, uint32_t address)
6428 {
6429         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6430                 struct cheerio_dma_reg *dma_reg;
6431                 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6432                 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dacr, address);
6433         } else if (fdc->c_fdtype & FDCTYPE_SB) {
6434                 struct sb_dma_reg *dma_reg;
6435                 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6436                 switch (fdc->sb_dma_channel) {
6437                         case 0 :
6438                                 ddi_put8(fdc->c_handlep_dma,
6439                                     &dma_reg->sb_dma_regs[DMA_0PAGE],
6440                                     (address & 0xFF0000) >>16);
6441                                 ddi_put8(fdc->c_handlep_dma,
6442                                     &dma_reg->sb_dma_regs[DMA_0HPG],
6443                                     (address & 0xFF000000) >>24);
6444                                 ddi_put16(fdc->c_handlep_dma,
6445                                     (ushort_t *)&dma_reg->sb_dma_regs[DMA_0ADR],
6446                                     address & 0xFFFF);
6447                                 break;
6448                         case 1 :
6449                                 ddi_put8(fdc->c_handlep_dma,
6450                                     &dma_reg->sb_dma_regs[DMA_1PAGE],
6451                                     (address & 0xFF0000) >>16);
6452                                 ddi_put8(fdc->c_handlep_dma,
6453                                     &dma_reg->sb_dma_regs[DMA_1HPG],
6454                                     (address & 0xFF000000) >>24);
6455                                 ddi_put16(fdc->c_handlep_dma,
6456                                     (ushort_t *)&dma_reg->sb_dma_regs[DMA_1ADR],
6457                                     address & 0xFFFF);
6458                                 break;
6459                         case 2 :
6460                                 ddi_put8(fdc->c_handlep_dma,
6461                                     &dma_reg->sb_dma_regs[DMA_2PAGE],
6462                                     (address & 0xFF0000) >>16);
6463                                 ddi_put8(fdc->c_handlep_dma,
6464                                     &dma_reg->sb_dma_regs[DMA_2HPG],
6465                                     (address & 0xFF000000) >>24);
6466                                 ddi_put16(fdc->c_handlep_dma,
6467                                     (ushort_t *)&dma_reg->sb_dma_regs[DMA_2ADR],
6468                                     address & 0xFFFF);
6469                                 break;
6470                         case 3 :
6471                                 ddi_put8(fdc->c_handlep_dma,
6472                                     &dma_reg->sb_dma_regs[DMA_3PAGE],
6473                                     (address & 0xFF0000) >>16);
6474                                 ddi_put8(fdc->c_handlep_dma,
6475                                     &dma_reg->sb_dma_regs[DMA_3HPG],
6476                                     (address & 0xFF000000) >>24);
6477                                 ddi_put16(fdc->c_handlep_dma,
6478                                     (ushort_t *)&dma_reg->sb_dma_regs[DMA_3ADR],
6479                                     address & 0xFFFF);
6480                                 break;
6481                         default :
6482                                 FDERRPRINT(FDEP_L3, FDEM_SDMA,
6483                                     (C, "set_data_address: wrong channel %x\n",
6484                                     fdc->sb_dma_channel));
6485                         break;
6486                 }
6487         }
6488 
6489 }
6490 
6491 
6492 /*
6493  * set_dma_mode(struct fdctlr *fdc, int val)
6494  *      Set the appropriate dma direction and registers.
6495  */
6496 static void
6497 set_dma_mode(struct fdctlr *fdc, int val)
6498 {
6499         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6500                 struct cheerio_dma_reg *dma_reg;
6501                 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6502                 if (val == CSB_READ)
6503                         ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
6504                             DCSR_INIT_BITS|DCSR_WRITE);
6505                 else
6506                         ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
6507                             DCSR_INIT_BITS);
6508 
6509         } else if (fdc->c_fdtype & FDCTYPE_SB) {
6510                 uint8_t mode_reg_val, chn_mask;
6511                 struct sb_dma_reg *dma_reg;
6512                 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6513 
6514                 if (val == CSB_READ) {
6515                         mode_reg_val = fdc->sb_dma_channel | DMAMODE_READ
6516                             | DMAMODE_SINGLE;
6517                 } else { /* Read operation */
6518                         mode_reg_val = fdc->sb_dma_channel | DMAMODE_WRITE
6519                             | DMAMODE_SINGLE;
6520                 }
6521                 ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MODE],
6522                     mode_reg_val);
6523                 chn_mask = 1 << (fdc->sb_dma_channel & 0x3);
6524                 ddi_put8(fdc->c_handlep_dma,
6525                     &dma_reg->sb_dma_regs[DMAC1_ALLMASK], ~chn_mask);
6526                 fdc->sb_dma_lock = 1;
6527         }
6528 }
6529 
6530 /*
6531  * This function is valid only for CHEERIO/RIO based
6532  * controllers. The control register for the dma channel
6533  * is initialized by this function.
6534  */
6535 
6536 static void
6537 set_dma_control_register(struct fdctlr *fdc, uint32_t val)
6538 {
6539         if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6540                 struct cheerio_dma_reg *dma_reg;
6541                 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6542                 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, val);
6543         }
6544 }
6545 
6546 static void
6547 release_sb_dma(struct fdctlr *fdc)
6548 {
6549         struct sb_dma_reg *dma_reg;
6550         dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6551         /* Unmask all the channels to release the DMA controller */
6552         ddi_put8(fdc->c_handlep_dma,
6553             &dma_reg->sb_dma_regs[DMAC1_ALLMASK], NULL);
6554         fdc->sb_dma_lock = 0;
6555 }
6556 
6557 static void
6558 quiesce_fd_interrupt(struct fdctlr *fdc)
6559 {
6560         /*
6561          * The following code is put here to take care of HW problem.
6562          * The HW problem is as follows:
6563          *
6564          *      After poweron the Southbridge floppy controller asserts the
6565          * interrupt in tristate. This causes continuous interrupts to
6566          * be generated.
6567          * Until the Hardware is FIXED we will have to use the following code
6568          * to set the interrupt line to proper state after poweron.
6569          */
6570         if (fdc->c_fdtype & FDCTYPE_SB) {
6571                 ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
6572                     0x0);
6573                 drv_usecwait(200);
6574                 ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
6575                     0xC);
6576                 drv_usecwait(200);
6577                 Set_Fifo(fdc, 0xE6);
6578                 drv_usecwait(200);
6579         }
6580 }