Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / dev / disk / wd / wd.c
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * William Jolitz.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *      from: @(#)wd.c  7.2 (Berkeley) 5/9/91
37  * $FreeBSD: src/sys/i386/isa/wd.c,v 1.219.2.2 2000/08/04 22:31:07 peter Exp $
38  * $DragonFly: src/sys/dev/disk/wd/Attic/wd.c,v 1.2 2003/06/17 04:28:37 dillon Exp $
39  */
40
41 /* TODO:
42  *      o Bump error count after timeout.
43  *      o Satisfy ATA timing in all cases.
44  *      o Finish merging berry/sos timeout code (bump error count...).
45  *      o Don't use polling except for initialization.  Need to
46  *        reorganize the state machine.  Then "extra" interrupts
47  *        shouldn't happen (except maybe one for initialization).
48  *      o Support extended DOS partitions.
49  *      o Support swapping to DOS partitions.
50  *      o Handle clustering, disklabelling, DOS
51  *        partitions and swapping driver-independently. 
52  *        Swapping will need new
53  *        driver entries for polled reinit and polled write).
54  */
55
56 #include "wd.h"
57 #ifdef  NWDC
58 #undef  NWDC
59 #endif
60
61 #include "wdc.h"
62
63 #if     NWDC > 0
64
65 #include "opt_hw_wdog.h"
66 #include "opt_ide_delay.h"
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/kernel.h>
71 #include <sys/conf.h>
72 #include <sys/bus.h>
73 #include <sys/disklabel.h>
74 #include <sys/diskslice.h>
75 #include <sys/buf.h>
76 #include <sys/devicestat.h>
77 #include <sys/malloc.h>
78 #include <sys/cons.h>
79 #include <machine/bootinfo.h>
80 #include <machine/clock.h>
81 #include <machine/md_var.h>
82 #include <i386/isa/isa.h>
83 #include <i386/isa/isa_device.h>
84 #include <i386/isa/wdreg.h>
85 #include <sys/syslog.h>
86 #include <vm/vm.h>
87 #include <vm/pmap.h>
88
89 #include <i386/isa/atapi.h>
90
91 extern void wdstart(int ctrlr);
92
93 #ifdef IDE_DELAY
94 #define TIMEOUT         IDE_DELAY
95 #else
96 #define TIMEOUT         10000
97 #endif
98 #define RETRIES         5       /* number of retries before giving up */
99 #define RECOVERYTIME    500000  /* usec for controller to recover after err */
100 #define MAXTRANSFER     255     /* max size of transfer in sectors */
101                                 /* correct max is 256 but some controllers */
102                                 /* can't handle that in all cases */
103 #define WDOPT_32BIT     0x8000
104 #define WDOPT_SLEEPHACK 0x4000
105 #define WDOPT_DMA       0x2000
106 #define WDOPT_LBA       0x1000
107 #define WDOPT_FORCEHD(x)        (((x)&0x0f00)>>8)
108 #define WDOPT_MULTIMASK 0x00ff
109
110 /*
111  * Drive states.  Used to initialize drive.
112  */
113
114 #define CLOSED          0       /* disk is closed. */
115 #define WANTOPEN        1       /* open requested, not started */
116 #define RECAL           2       /* doing restore */
117 #define OPEN            3       /* done with open */
118
119 #define PRIMARY         0
120
121 /*
122  * Disk geometry.  A small part of struct disklabel.
123  * XXX disklabel.5 contains an old clone of disklabel.h.
124  */
125 struct diskgeom {
126         u_long  d_secsize;              /* # of bytes per sector */
127         u_long  d_nsectors;             /* # of data sectors per track */
128         u_long  d_ntracks;              /* # of tracks per cylinder */
129         u_long  d_ncylinders;           /* # of data cylinders per unit */
130         u_long  d_secpercyl;            /* # of data sectors per cylinder */
131         u_long  d_secperunit;           /* # of data sectors per unit */
132         u_long  d_precompcyl;           /* XXX always 0 */
133 };
134
135 /*
136  * The structure of a disk drive.
137  */
138 struct disk {
139         u_int   dk_bc;          /* byte count left */
140         short   dk_skip;        /* blocks already transferred */
141         int     dk_ctrlr;       /* physical controller number */
142         int     dk_ctrlr_cmd640;/* controller number for CMD640 quirk */
143         u_int32_t       dk_unit;        /* physical unit number */
144         u_int32_t       dk_lunit;       /* logical unit number */
145         u_int32_t       dk_interface;   /* interface (two ctrlrs per interface) */
146         char    dk_state;       /* control state */
147         u_char  dk_status;      /* copy of status reg. */
148         u_char  dk_error;       /* copy of error reg. */
149         u_char  dk_timeout;     /* countdown to next timeout */
150         u_int32_t       dk_port;        /* i/o port base */
151         u_int32_t       dk_altport;     /* altstatus port base */
152         u_long  cfg_flags;      /* configured characteristics */
153         short   dk_flags;       /* drive characteristics found */
154 #define DKFL_SINGLE     0x00004 /* sector at a time mode */
155 #define DKFL_ERROR      0x00008 /* processing a disk error */
156 #define DKFL_LABELLING  0x00080 /* readdisklabel() in progress */
157 #define DKFL_32BIT      0x00100 /* use 32-bit i/o mode */
158 #define DKFL_MULTI      0x00200 /* use multi-i/o mode */
159 #define DKFL_USEDMA     0x00800 /* use DMA for data transfers */
160 #define DKFL_DMA        0x01000 /* using DMA on this transfer-- DKFL_SINGLE
161                                  * overrides this
162                                  */
163 #define DKFL_LBA        0x02000 /* use LBA for data transfers */
164         struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
165         unsigned int    dk_multi;       /* multi transfers */
166         int     dk_currentiosize;       /* current io size */
167         struct diskgeom dk_dd;  /* device configuration data */
168         struct diskslices *dk_slices;   /* virtual drives */
169         void    *dk_dmacookie;  /* handle for DMA services */
170
171         struct devstat dk_stats;        /* devstat entry */
172 };
173
174 #define WD_COUNT_RETRIES
175 static int wdtest = 0;
176
177 static struct disk *wddrives[NWD];      /* table of units */
178 static struct buf_queue_head drive_queue[NWD];  /* head of queue per drive */
179 static struct {
180         int     b_active;
181 } wdutab[NWD];
182 /*
183 static struct buf wdtab[NWDC];
184 */
185 static struct {
186         struct  buf_queue_head controller_queue;
187         int     b_errcnt;
188         int     b_active;
189 } wdtab[NWDC];
190
191 struct wddma wddma[NWDC];
192
193 #ifdef notyet
194 static struct buf rwdbuf[NWD];  /* buffers for raw IO */
195 #endif
196
197 static int wdprobe(struct isa_device *dvp);
198 static int wdattach(struct isa_device *dvp);
199 static void wdustart(struct disk *du);
200 static int wdcontrol(struct buf *bp);
201 static int wdcommand(struct disk *du, u_int cylinder, u_int head,
202                      u_int sector, u_int count, u_int command);
203 static int wdsetctlr(struct disk *du);
204 #if 0
205 static int wdwsetctlr(struct disk *du);
206 #endif
207 static int wdsetmode(int mode, void *wdinfo);
208 static int wdgetctlr(struct disk *du);
209 static void wderror(struct buf *bp, struct disk *du, char *mesg);
210 static void wdflushirq(struct disk *du, int old_ipl);
211 static int wdreset(struct disk *du);
212 static void wdsleep(int ctrlr, char *wmesg);
213 static timeout_t wdtimeout;
214 static int wdunwedge(struct disk *du);
215 static int wdwait(struct disk *du, u_char bits_wanted, int timeout);
216
217 struct isa_driver wdcdriver = {
218         wdprobe, wdattach, "wdc",
219 };
220
221
222
223 static  d_open_t        wdopen;
224 static  d_close_t       wdclose;
225 static  d_strategy_t    wdstrategy;
226 static  d_ioctl_t       wdioctl;
227 static  d_dump_t        wddump;
228 static  d_psize_t       wdsize;
229
230 #define CDEV_MAJOR 3
231 #define BDEV_MAJOR 0
232
233
234 static struct cdevsw wd_cdevsw = {
235         /* open */      wdopen,
236         /* close */     wdclose,
237         /* read */      physread,
238         /* write */     physwrite,
239         /* ioctl */     wdioctl,
240         /* poll */      nopoll,
241         /* mmap */      nommap,
242         /* strategy */  wdstrategy,
243         /* name */      "wd",
244         /* maj */       CDEV_MAJOR,
245         /* dump */      wddump,
246         /* psize */     wdsize,
247         /* flags */     D_DISK,
248         /* bmaj */      BDEV_MAJOR
249 };
250
251
252 static int      atapictrlr;
253 static int      eide_quirks;
254
255
256 /*
257  *  Here we use the pci-subsystem to find out, whether there is
258  *  a cmd640b-chip attached on this pci-bus. This public routine
259  *  will be called by ide_pci.c
260  */
261
262 void
263 wdc_pci(int quirks)
264 {
265         eide_quirks = quirks;
266 }
267
268 /*
269  * Probe for controller.
270  */
271 static int
272 wdprobe(struct isa_device *dvp)
273 {
274         int     unit = dvp->id_unit;
275         int     interface;
276         struct disk *du;
277
278         if (unit >= NWDC)
279                 return (0);
280
281         du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
282         if (du == NULL)
283                 return (0);
284         bzero(du, sizeof *du);
285         du->dk_ctrlr = dvp->id_unit;
286         interface = du->dk_ctrlr / 2;
287         du->dk_interface = interface;
288         du->dk_port = dvp->id_iobase;
289         if (wddma[interface].wdd_candma != NULL) {
290                 du->dk_dmacookie =
291                     wddma[interface].wdd_candma(dvp->id_iobase, du->dk_ctrlr,
292                     du->dk_unit);
293                 du->dk_altport =
294                     wddma[interface].wdd_altiobase(du->dk_dmacookie);
295         }
296         if (du->dk_altport == 0)
297                 du->dk_altport = du->dk_port + wd_ctlr;
298
299         /* check if we have registers that work */
300         outb(du->dk_port + wd_sdh, WDSD_IBM);   /* set unit 0 */
301         outb(du->dk_port + wd_cyl_lo, 0xa5);    /* wd_cyl_lo is read/write */
302         if (inb(du->dk_port + wd_cyl_lo) == 0xff) {     /* XXX too weak */
303                 /* There is no master, try the ATAPI slave. */
304                 du->dk_unit = 1;
305                 outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10);
306                 outb(du->dk_port + wd_cyl_lo, 0xa5);
307                 if (inb(du->dk_port + wd_cyl_lo) == 0xff)
308                         goto nodevice;
309         }
310
311         if (wdreset(du) == 0)
312                 goto reset_ok;
313         /* test for ATAPI signature */
314         outb(du->dk_port + wd_sdh, WDSD_IBM);           /* master */
315         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
316             inb(du->dk_port + wd_cyl_hi) == 0xeb)
317                 goto reset_ok;
318         du->dk_unit = 1;
319         outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10); /* slave */
320         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
321             inb(du->dk_port + wd_cyl_hi) == 0xeb)
322                 goto reset_ok;
323         DELAY(RECOVERYTIME);
324         if (wdreset(du) != 0) {
325                 goto nodevice;
326         }
327 reset_ok:
328
329         /* execute a controller only command */
330         if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
331             || wdwait(du, 0, TIMEOUT) < 0) {
332                 goto nodevice;
333         }
334
335         /*
336          * drive(s) did not time out during diagnostic :
337          * Get error status and check that both drives are OK.
338          * Table 9-2 of ATA specs suggests that we must check for
339          * a value of 0x01
340          *
341          * Strangely, some controllers will return a status of
342          * 0x81 (drive 0 OK, drive 1 failure), and then when
343          * the DRV bit is set, return status of 0x01 (OK) for
344          * drive 2.  (This seems to contradict the ATA spec.)
345          */
346         du->dk_error = inb(du->dk_port + wd_error);
347         if(du->dk_error != 0x01 && du->dk_error != 0) {
348                 if(du->dk_error & 0x80) { /* drive 1 failure */
349
350                         /* first set the DRV bit */
351                         u_int sdh;
352                         sdh = inb(du->dk_port+ wd_sdh);
353                         sdh = sdh | 0x10;
354                         outb(du->dk_port+ wd_sdh, sdh);
355
356                         /* Wait, to make sure drv 1 has completed diags */
357                         if ( wdwait(du, 0, TIMEOUT) < 0)
358                                 goto nodevice;
359
360                         /* Get status for drive 1 */
361                         du->dk_error = inb(du->dk_port + wd_error);
362                         /* printf("Error (drv 1) : %x\n", du->dk_error); */
363                         /*
364                          * Sometimes (apparently mostly with ATAPI
365                          * drives involved) 0x81 really means 0x81
366                          * (drive 0 OK, drive 1 failed).
367                          */
368                         if(du->dk_error != 0x01 && du->dk_error != 0x81)
369                                 goto nodevice;
370                 } else  /* drive 0 fail */
371                         goto nodevice;
372         }
373
374
375         free(du, M_TEMP);
376         return (IO_WDCSIZE);
377
378 nodevice:
379         free(du, M_TEMP);
380         return (0);
381 }
382
383 /*
384  * Attach each drive if possible.
385  */
386 static int
387 wdattach(struct isa_device *dvp)
388 {
389         int     unit, lunit, flags, i;
390         struct disk *du;
391         struct wdparams *wp;
392         static char buf[] = "wdcXXX";
393         static int once;
394
395         dvp->id_intr = wdintr;
396
397         if (dvp->id_unit >= NWDC)
398                 return (0);
399
400         if (!once) {
401                 cdevsw_add(&wd_cdevsw);
402                 once++;
403         }
404
405         if (eide_quirks & Q_CMD640B) {
406                 if (dvp->id_unit == PRIMARY) {
407                         printf("wdc0: CMD640B workaround enabled\n");
408                         bufq_init(&wdtab[PRIMARY].controller_queue);
409                 }
410         } else
411                 bufq_init(&wdtab[dvp->id_unit].controller_queue);
412
413         sprintf(buf, "wdc%d", dvp->id_unit);
414         for (i = resource_query_string(-1, "at", buf);
415              i != -1;
416              i = resource_query_string(i, "at", buf)) {
417                 if (strcmp(resource_query_name(i), "wd"))
418                         /* Avoid a bit of foot shooting. */
419                         continue;
420
421                 lunit = resource_query_unit(i);
422                 if (lunit >= NWD)
423                         continue;
424
425                 if (resource_int_value("wd", lunit, "drive", &unit) != 0)
426                         continue;
427                 if (resource_int_value("wd", lunit, "flags", &flags) != 0)
428                         flags = 0;
429
430                 du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
431                 if (du == NULL)
432                         continue;
433                 if (wddrives[lunit] != NULL)
434                         panic("drive attached twice");
435                 wddrives[lunit] = du;
436                 bufq_init(&drive_queue[lunit]);
437                 bzero(du, sizeof *du);
438                 du->dk_ctrlr = dvp->id_unit;
439                 if (eide_quirks & Q_CMD640B) {
440                         du->dk_ctrlr_cmd640 = PRIMARY;
441                 } else {
442                         du->dk_ctrlr_cmd640 = du->dk_ctrlr;
443                 }
444                 du->dk_unit = unit;
445                 du->dk_lunit = lunit;
446                 du->dk_port = dvp->id_iobase;
447
448                 du->dk_altport = du->dk_port + wd_ctlr;
449                 /*
450                  * Use the individual device flags or the controller
451                  * flags.
452                  */
453                 du->cfg_flags = flags |
454                         ((dvp->id_flags) >> (16 * unit));
455
456                 if (wdgetctlr(du) == 0) {
457                         /*
458                          * Print out description of drive.
459                          * wdp_model may not be null terminated.
460                          */
461                         printf("wdc%d: unit %d (wd%d): <%.*s>",
462                                 dvp->id_unit, unit, lunit,
463                                 (int)sizeof(du->dk_params.wdp_model),
464                                 du->dk_params.wdp_model);
465                         if (du->dk_flags & DKFL_LBA)
466                                 printf(", LBA");
467                         if (du->dk_flags & DKFL_USEDMA)
468                                 printf(", DMA");
469                         if (du->dk_flags & DKFL_32BIT)
470                                 printf(", 32-bit");
471                         if (du->dk_multi > 1)
472                                 printf(", multi-block-%d", du->dk_multi);
473                         if (du->cfg_flags & WDOPT_SLEEPHACK)
474                                 printf(", sleep-hack");
475                         printf("\n");
476                         if (du->dk_params.wdp_heads == 0)
477                                 printf("wd%d: size unknown, using %s values\n",
478                                        lunit, du->dk_dd.d_secperunit > 17
479                                               ? "BIOS" : "fake");
480                         printf( "wd%d: %luMB (%lu sectors), "
481                                 "%lu cyls, %lu heads, %lu S/T, %lu B/S\n",
482                                lunit,
483                                du->dk_dd.d_secperunit
484                                / ((1024L * 1024L) / du->dk_dd.d_secsize),
485                                du->dk_dd.d_secperunit,
486                                du->dk_dd.d_ncylinders,
487                                du->dk_dd.d_ntracks,
488                                du->dk_dd.d_nsectors,
489                                du->dk_dd.d_secsize);
490
491                         if (bootverbose) {
492                             wp = &du->dk_params;
493                             printf( "wd%d: ATA INQUIRE valid = %04x, "
494                                     "dmamword = %04x, apio = %04x, "
495                                     "udma = %04x\n",
496                                 du->dk_lunit,
497                                 wp->wdp_atavalid,
498                                 wp->wdp_dmamword,
499                                 wp->wdp_eidepiomodes,
500                                 wp->wdp_udmamode);
501                           }
502
503                         /*
504                          * Start timeout routine for this drive.
505                          * XXX timeout should be per controller.
506                          */
507                         wdtimeout(du);
508
509                         make_dev(&wd_cdevsw, 
510                             dkmakeminor(lunit, WHOLE_DISK_SLICE, RAW_PART),
511                             UID_ROOT, GID_OPERATOR, 0640, "rwd%d", lunit);
512
513                         /*
514                          * Export the drive to the devstat interface.
515                          */
516                         devstat_add_entry(&du->dk_stats, "wd", 
517                                           lunit, du->dk_dd.d_secsize,
518                                           DEVSTAT_NO_ORDERED_TAGS,
519                                           DEVSTAT_TYPE_DIRECT |
520                                           DEVSTAT_TYPE_IF_IDE,
521                                           DEVSTAT_PRIORITY_DISK);
522
523                 } else {
524                         free(du, M_TEMP);
525                         wddrives[lunit] = NULL;
526                 }
527         }
528         /*
529          * Probe all free IDE units, searching for ATAPI drives.
530          */
531         for (unit=0; unit<2; ++unit) {
532                 for (lunit=0; lunit<NWD; ++lunit)
533                         if (wddrives[lunit] &&
534                             wddrives[lunit]->dk_ctrlr == dvp->id_unit &&
535                             wddrives[lunit]->dk_unit == unit)
536                                 goto next;
537                 if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase))
538                         atapictrlr = dvp->id_unit;
539 next: ;
540         }
541         /*
542          * Discard any interrupts generated by wdgetctlr().  wdflushirq()
543          * doesn't work now because the ambient ipl is too high.
544          */
545         if (eide_quirks & Q_CMD640B) {
546                 wdtab[PRIMARY].b_active = 2;
547         } else {
548                 wdtab[dvp->id_unit].b_active = 2;
549         }
550
551         return (1);
552 }
553
554 /* Read/write routine for a buffer.  Finds the proper unit, range checks
555  * arguments, and schedules the transfer.  Does not wait for the transfer
556  * to complete.  Multi-page transfers are supported.  All I/O requests must
557  * be a multiple of a sector in length.
558  */
559 void
560 wdstrategy(register struct buf *bp)
561 {
562         struct disk *du;
563         int     lunit = dkunit(bp->b_dev);
564         int     s;
565
566         /* valid unit, controller, and request?  */
567         if (lunit >= NWD || bp->b_blkno < 0 || (du = wddrives[lunit]) == NULL
568             || bp->b_bcount % DEV_BSIZE != 0) {
569
570                 bp->b_error = EINVAL;
571                 bp->b_flags |= B_ERROR;
572                 goto done;
573         }
574
575         /*
576          * Do bounds checking, adjust transfer, and set b_pblkno.
577          */
578         if (dscheck(bp, du->dk_slices) <= 0)
579                 goto done;
580
581         /* queue transfer on drive, activate drive and controller if idle */
582         s = splbio();
583
584         /* Pick up changes made by readdisklabel(). */
585         if (du->dk_flags & DKFL_LABELLING && du->dk_state > RECAL) {
586                 wdsleep(du->dk_ctrlr, "wdlab");
587                 du->dk_state = WANTOPEN;
588         }
589
590         bufqdisksort(&drive_queue[lunit], bp);
591
592         if (wdutab[lunit].b_active == 0)
593                 wdustart(du);   /* start drive */
594
595         if (wdtab[du->dk_ctrlr_cmd640].b_active == 0)
596                 wdstart(du->dk_ctrlr);  /* start controller */
597
598         /* Tell devstat that we have started a transaction on this drive */
599         devstat_start_transaction(&du->dk_stats);
600
601         splx(s);
602         return;
603
604 done:
605         /* toss transfer, we're done early */
606         biodone(bp);
607 }
608
609 /*
610  * Routine to queue a command to the controller.  The unit's
611  * request is linked into the active list for the controller.
612  * If the controller is idle, the transfer is started.
613  */
614 static void
615 wdustart(register struct disk *du)
616 {
617         register struct buf *bp;
618         int     ctrlr = du->dk_ctrlr_cmd640;
619
620         /* unit already active? */
621         if (wdutab[du->dk_lunit].b_active)
622                 return;
623
624
625         bp = bufq_first(&drive_queue[du->dk_lunit]);
626         if (bp == NULL) {       /* yes, an assign */
627                 return;
628         }
629         /*
630          * store away which device we came from.
631          */
632         bp->b_driver1 = du;
633
634         bufq_remove(&drive_queue[du->dk_lunit], bp);
635
636         /* link onto controller queue */
637         bufq_insert_tail(&wdtab[ctrlr].controller_queue, bp);
638
639         /* mark the drive unit as busy */
640         wdutab[du->dk_lunit].b_active = 1;
641
642 }
643
644 /*
645  * Controller startup routine.  This does the calculation, and starts
646  * a single-sector read or write operation.  Called to start a transfer,
647  * or from the interrupt routine to continue a multi-sector transfer.
648  * RESTRICTIONS:
649  * 1. The transfer length must be an exact multiple of the sector size.
650  */
651
652 void
653 wdstart(int ctrlr)
654 {
655         register struct disk *du;
656         register struct buf *bp;
657         struct diskgeom *lp;    /* XXX sic */
658         long    blknum;
659         long    secpertrk, secpercyl;
660         u_int   lunit;
661         u_int   count;
662         int     ctrlr_atapi;
663
664         if (eide_quirks & Q_CMD640B) {
665                 ctrlr = PRIMARY;
666                 ctrlr_atapi = atapictrlr;
667         } else {
668                 ctrlr_atapi = ctrlr;
669         }
670
671         if (wdtab[ctrlr].b_active == 2)
672                 wdtab[ctrlr].b_active = 0;
673         if (wdtab[ctrlr].b_active)
674                 return;
675         /* is there a drive for the controller to do a transfer with? */
676         bp = bufq_first(&wdtab[ctrlr].controller_queue);
677         if (bp == NULL) {
678                 if (atapi_strt && atapi_strt (ctrlr_atapi))
679                         /* mark controller active in ATAPI mode */
680                         wdtab[ctrlr].b_active = 3;
681                 return;
682         }
683
684         /* obtain controller and drive information */
685         lunit = dkunit(bp->b_dev);
686         du = wddrives[lunit];
687
688         /* if not really a transfer, do control operations specially */
689         if (du->dk_state < OPEN) {
690                 if (du->dk_state != WANTOPEN)
691                         printf("wd%d: wdstart: weird dk_state %d\n",
692                                du->dk_lunit, du->dk_state);
693                 if (wdcontrol(bp) != 0)
694                         printf("wd%d: wdstart: wdcontrol returned nonzero, state = %d\n",
695                                du->dk_lunit, du->dk_state);
696                 return;
697         }
698
699         /* calculate transfer details */
700         blknum = bp->b_pblkno + du->dk_skip;
701 #ifdef WDDEBUG
702         if (du->dk_skip == 0)
703                 printf("wd%d: wdstart: %s %d@%d; map ", lunit,
704                        (bp->b_flags & B_READ) ? "read" : "write",
705                        bp->b_bcount, blknum);
706         else
707                 printf(" %d)%x", du->dk_skip, inb(du->dk_altport));
708 #endif
709
710         lp = &du->dk_dd;
711         secpertrk = lp->d_nsectors;
712         secpercyl = lp->d_secpercyl;
713
714         if (du->dk_skip == 0)
715                 du->dk_bc = bp->b_bcount;
716
717         wdtab[ctrlr].b_active = 1;      /* mark controller active */
718
719         /* if starting a multisector transfer, or doing single transfers */
720         if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
721                 u_int   command;
722                 u_int   count1;
723                 long    cylin, head, sector;
724
725                 if (du->dk_flags & DKFL_LBA) {
726                         sector = (blknum >> 0) & 0xff; 
727                         cylin = (blknum >> 8) & 0xffff;
728                         head = ((blknum >> 24) & 0xf) | WDSD_LBA; 
729                 } else {
730                         cylin = blknum / secpercyl;
731                         head = (blknum % secpercyl) / secpertrk;
732                         sector = blknum % secpertrk;
733                 }
734                 /* 
735                  * XXX this looks like an attempt to skip bad sectors
736                  * on write.
737                  */
738                 if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0)
739                         du->dk_bc += DEV_BSIZE;
740
741                 count1 = howmany( du->dk_bc, DEV_BSIZE);
742
743                 du->dk_flags &= ~DKFL_MULTI;
744
745                 if (du->dk_flags & DKFL_SINGLE) {
746                         command = (bp->b_flags & B_READ)
747                                   ? WDCC_READ : WDCC_WRITE;
748                         count1 = 1;
749                         du->dk_currentiosize = 1;
750                 } else {
751                         if((du->dk_flags & DKFL_USEDMA) &&
752                            wddma[du->dk_interface].wdd_dmaverify(du->dk_dmacookie,
753                                 (void *)((int)bp->b_data + 
754                                      du->dk_skip * DEV_BSIZE),
755                                 du->dk_bc,
756                                 bp->b_flags & B_READ)) {
757                                 du->dk_flags |= DKFL_DMA;
758                                 if( bp->b_flags & B_READ)
759                                         command = WDCC_READ_DMA;
760                                 else
761                                         command = WDCC_WRITE_DMA;
762                                 du->dk_currentiosize = count1;
763                         } else if( (count1 > 1) && (du->dk_multi > 1)) {
764                                 du->dk_flags |= DKFL_MULTI;
765                                 if( bp->b_flags & B_READ) {
766                                         command = WDCC_READ_MULTI;
767                                 } else {
768                                         command = WDCC_WRITE_MULTI;
769                                 }
770                                 du->dk_currentiosize = du->dk_multi;
771                                 if( du->dk_currentiosize > count1)
772                                         du->dk_currentiosize = count1;
773                         } else {
774                                 if( bp->b_flags & B_READ) {
775                                         command = WDCC_READ;
776                                 } else {
777                                         command = WDCC_WRITE;
778                                 }
779                                 du->dk_currentiosize = 1;
780                         }
781                 }
782
783                 /*
784                  * XXX this loop may never terminate.  The code to handle
785                  * counting down of retries and eventually failing the i/o
786                  * is in wdintr() and we can't get there from here.
787                  */
788                 if (wdtest != 0) {
789                         if (--wdtest == 0) {
790                                 wdtest = 100;
791                                 printf("dummy wdunwedge\n");
792                                 wdunwedge(du);
793                         }
794                 }
795
796                 if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
797                         wddma[du->dk_interface].wdd_dmaprep(du->dk_dmacookie,
798                                            (void *)((int)bp->b_data + 
799                                                     du->dk_skip * DEV_BSIZE),
800                                            du->dk_bc,
801                                            bp->b_flags & B_READ);
802                 }
803                 while (wdcommand(du, cylin, head, sector, count1, command)
804                        != 0) {
805                         wderror(bp, du,
806                                 "wdstart: timeout waiting to give command");
807                         wdunwedge(du);
808                 }
809 #ifdef WDDEBUG
810                 printf("cylin %ld head %ld sector %ld addr %x sts %x\n",
811                        cylin, head, sector,
812                        (int)bp->b_data + du->dk_skip * DEV_BSIZE,
813                        inb(du->dk_altport));
814 #endif
815         }
816
817         /*
818          * Schedule wdtimeout() to wake up after a few seconds.  Retrying
819          * unmarked bad blocks can take 3 seconds!  Then it is not good that
820          * we retry 5 times.
821          *
822          * On the first try, we give it 10 seconds, for drives that may need
823          * to spin up.
824          *
825          * XXX wdtimeout() doesn't increment the error count so we may loop
826          * forever.  More seriously, the loop isn't forever but causes a
827          * crash.
828          *
829          * TODO fix b_resid bug elsewhere (fd.c....).  Fix short but positive
830          * counts being discarded after there is an error (in physio I
831          * think).  Discarding them would be OK if the (special) file offset
832          * was not advanced.
833          */
834         if (wdtab[ctrlr].b_errcnt == 0)
835                 du->dk_timeout = 1 + 10;
836         else
837                 du->dk_timeout = 1 + 3;
838
839         /* if this is a DMA op, start DMA and go away until it's done. */
840         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
841                 wddma[du->dk_interface].wdd_dmastart(du->dk_dmacookie);
842                 return;
843         }
844
845         /* If this is a read operation, just go away until it's done. */
846         if (bp->b_flags & B_READ)
847                 return;
848
849         /* Ready to send data? */
850         if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) < 0) {
851                 wderror(bp, du, "wdstart: timeout waiting for DRQ");
852                 /*
853                  * XXX what do we do now?  If we've just issued the command,
854                  * then we can treat this failure the same as a command
855                  * failure.  But if we are continuing a multi-sector write,
856                  * the command was issued ages ago, so we can't simply
857                  * restart it.
858                  *
859                  * XXX we waste a lot of time unnecessarily translating block
860                  * numbers to cylin/head/sector for continued i/o's.
861                  */
862         }
863
864         count = 1;
865         if( du->dk_flags & DKFL_MULTI) {
866                 count = howmany(du->dk_bc, DEV_BSIZE);
867                 if( count > du->dk_multi)
868                         count = du->dk_multi;
869                 if( du->dk_currentiosize > count)
870                         du->dk_currentiosize = count;
871         }
872
873         if (du->dk_flags & DKFL_32BIT)
874                 outsl(du->dk_port + wd_data,
875                       (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
876                       (count * DEV_BSIZE) / sizeof(long));
877         else
878                 outsw(du->dk_port + wd_data,
879                       (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
880                       (count * DEV_BSIZE) / sizeof(short));
881         du->dk_bc -= DEV_BSIZE * count;
882 }
883
884 /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
885  * errors on the current operation, mark it done if necessary, and start
886  * the next request.  Also check for a partially done transfer, and
887  * continue with the next chunk if so.
888  */
889
890 void
891 wdintr(void *unitnum)
892 {
893         register struct disk *du;
894         register struct buf *bp;
895         int dmastat = 0;                        /* Shut up GCC */
896         int unit = (int)unitnum;
897
898         int ctrlr_atapi;
899
900         if (eide_quirks & Q_CMD640B) {
901                 unit = PRIMARY;
902                 ctrlr_atapi = atapictrlr;
903         } else {
904                 ctrlr_atapi = unit;
905         }
906
907         if (wdtab[unit].b_active == 2)
908                 return;         /* intr in wdflushirq() */
909         if (!wdtab[unit].b_active) {
910 #ifdef WDDEBUG
911                 /*
912                  * These happen mostly because the power-mgt part of the
913                  * bios shuts us down, and we just manage to see the
914                  * interrupt from the "SLEEP" command.
915                  */
916                 printf("wdc%d: extra interrupt\n", unit);
917 #endif
918                 return;
919         }
920         if (wdtab[unit].b_active == 3) {
921                 /* process an ATAPI interrupt */
922                 if (atapi_intr && atapi_intr (ctrlr_atapi))
923                         /* ATAPI op continues */
924                         return;
925                 /* controller is free, start new op */
926                 wdtab[unit].b_active = 0;
927                 wdstart (unit);
928                 return;
929         }
930         bp = bufq_first(&wdtab[unit].controller_queue);
931         du = wddrives[dkunit(bp->b_dev)];
932
933         /* finish off DMA */
934         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
935                 /* XXX SMP boxes sometimes generate an early intr.  Why? */
936                 if ((wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie) & 
937                     WDDS_INTERRUPT) == 0)
938                         return;
939                 dmastat = wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
940         }
941
942         du->dk_timeout = 0;
943
944         /* check drive status/failure */
945         if (wdwait(du, 0, TIMEOUT) < 0) {
946                 wderror(bp, du, "wdintr: timeout waiting for status");
947                 du->dk_status |= WDCS_ERR;      /* XXX */
948         }
949
950         /* is it not a transfer, but a control operation? */
951         if (du->dk_state < OPEN) {
952                 wdtab[unit].b_active = 0;
953                 switch (wdcontrol(bp)) {
954                 case 0:
955                         return;
956                 case 1:
957                         wdstart(unit);
958                         return;
959                 case 2:
960                         goto done;
961                 }
962         }
963
964         /* have we an error? */
965         if ((du->dk_status & (WDCS_ERR | WDCS_ECCCOR))
966             || (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
967                 && dmastat != WDDS_INTERRUPT)) {
968
969                 unsigned int errstat;
970 oops:
971                 /*
972                  * XXX bogus inb() here
973                  */
974                 errstat = inb(du->dk_port + wd_error);
975
976                 if(((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) &&
977                    (errstat & WDERR_ABORT)) {
978                         wderror(bp, du, "reverting to PIO mode");
979                         du->dk_flags &= ~DKFL_USEDMA;
980                 } else if((du->dk_flags & DKFL_MULTI) &&
981                     (errstat & WDERR_ABORT)) {
982                         wderror(bp, du, "reverting to non-multi sector mode");
983                         du->dk_multi = 1;
984                 }
985
986                 if (!(du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) &&
987                     (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) && 
988                      (dmastat != WDDS_INTERRUPT)))
989                         printf("wd%d: DMA failure, DMA status %b\n", 
990                                du->dk_lunit, dmastat, WDDS_BITS);
991 #ifdef WDDEBUG
992                 wderror(bp, du, "wdintr");
993 #endif
994                 if ((du->dk_flags & DKFL_SINGLE) == 0) {
995                         du->dk_flags |= DKFL_ERROR;
996                         goto outt;
997                 }
998
999                 if (du->dk_status & WDCS_ERR) {
1000                         if (++wdtab[unit].b_errcnt < RETRIES) {
1001                                 wdtab[unit].b_active = 0;
1002                         } else {
1003                                 wderror(bp, du, "hard error");
1004                                 bp->b_error = EIO;
1005                                 bp->b_flags |= B_ERROR; /* flag the error */
1006                         }
1007                 } else if (du->dk_status & WDCS_ECCCOR)
1008                         wderror(bp, du, "soft ecc");
1009         }
1010
1011         /*
1012          * If this was a successful read operation, fetch the data.
1013          */
1014         if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ)
1015             && !((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
1016             && wdtab[unit].b_active) {
1017                 u_int   chk, dummy, multisize;
1018                 multisize = chk = du->dk_currentiosize * DEV_BSIZE;
1019                 if( du->dk_bc < chk) {
1020                         chk = du->dk_bc;
1021                         if( ((chk + DEV_BSIZE - 1) / DEV_BSIZE) < du->dk_currentiosize) {
1022                                 du->dk_currentiosize = (chk + DEV_BSIZE - 1) / DEV_BSIZE;
1023                                 multisize = du->dk_currentiosize * DEV_BSIZE;
1024                         }
1025                 }
1026
1027                 /* ready to receive data? */
1028                 if ((du->dk_status & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
1029                     != (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
1030                         wderror(bp, du, "wdintr: read intr arrived early");
1031                 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
1032                         wderror(bp, du, "wdintr: read error detected late");
1033                         goto oops;
1034                 }
1035
1036                 /* suck in data */
1037                 if( du->dk_flags & DKFL_32BIT)
1038                         insl(du->dk_port + wd_data,
1039                              (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
1040                                         chk / sizeof(long));
1041                 else
1042                         insw(du->dk_port + wd_data,
1043                              (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
1044                                         chk / sizeof(short));
1045                 du->dk_bc -= chk;
1046
1047                 /* XXX for obsolete fractional sector reads. */
1048                 while (chk < multisize) {
1049                         insw(du->dk_port + wd_data, &dummy, 1);
1050                         chk += sizeof(short);
1051                 }
1052
1053         }
1054
1055         /* final cleanup on DMA */
1056         if (((bp->b_flags & B_ERROR) == 0)
1057             && ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
1058             && wdtab[unit].b_active) {
1059                 int iosize;
1060
1061                 iosize = du->dk_currentiosize * DEV_BSIZE;
1062
1063                 du->dk_bc -= iosize;
1064
1065         }
1066
1067 outt:
1068         if (wdtab[unit].b_active) {
1069                 if ((bp->b_flags & B_ERROR) == 0) {
1070                         du->dk_skip += du->dk_currentiosize;/* add to successful sectors */
1071                         if (wdtab[unit].b_errcnt)
1072                                 wderror(bp, du, "soft error");
1073                         wdtab[unit].b_errcnt = 0;
1074
1075                         /* see if more to transfer */
1076                         if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
1077                                 if( (du->dk_flags & DKFL_SINGLE) ||
1078                                         ((bp->b_flags & B_READ) == 0)) {
1079                                         wdtab[unit].b_active = 0;
1080                                         wdstart(unit);
1081                                 } else {
1082                                         du->dk_timeout = 1 + 3;
1083                                 }
1084                                 return; /* next chunk is started */
1085                         } else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR))
1086                                    == DKFL_ERROR) {
1087                                 du->dk_skip = 0;
1088                                 du->dk_flags &= ~DKFL_ERROR;
1089                                 du->dk_flags |= DKFL_SINGLE;
1090                                 wdtab[unit].b_active = 0;
1091                                 wdstart(unit);
1092                                 return; /* redo xfer sector by sector */
1093                         }
1094                 }
1095
1096 done: ;
1097                 /* done with this transfer, with or without error */
1098                 du->dk_flags &= ~(DKFL_SINGLE|DKFL_DMA);
1099                 bufq_remove( &wdtab[unit].controller_queue, bp);
1100                 wdtab[unit].b_errcnt = 0;
1101                 bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE;
1102                 wdutab[du->dk_lunit].b_active = 0;
1103                 du->dk_skip = 0;
1104                 devstat_end_transaction_buf(&du->dk_stats, bp);
1105                 biodone(bp);
1106         }
1107
1108         /* controller idle */
1109         wdtab[unit].b_active = 0;
1110
1111         /* anything more on drive queue? */
1112         wdustart(du);
1113         /* anything more for controller to do? */
1114         wdstart(unit);
1115 }
1116
1117 /*
1118  * Initialize a drive.
1119  */
1120 int
1121 wdopen(dev_t dev, int flags, int fmt, struct proc *p)
1122 {
1123         register unsigned int lunit;
1124         register struct disk *du;
1125         int     error;
1126
1127         lunit = dkunit(dev);
1128         if (lunit >= NWD || dktype(dev) != 0)
1129                 return (ENXIO);
1130         du = wddrives[lunit];
1131         if (du == NULL)
1132                 return (ENXIO);
1133
1134         dev->si_iosize_max = 248 * 512;
1135         /* Finish flushing IRQs left over from wdattach(). */
1136         if (wdtab[du->dk_ctrlr_cmd640].b_active == 2)
1137                 wdtab[du->dk_ctrlr_cmd640].b_active = 0;
1138
1139         /* spin waiting for anybody else reading the disk label */
1140         while (du->dk_flags & DKFL_LABELLING)
1141                 tsleep((caddr_t)&du->dk_flags, PZERO - 1, "wdopen", 1);
1142 #if 1
1143         wdsleep(du->dk_ctrlr, "wdopn1");
1144         du->dk_flags |= DKFL_LABELLING;
1145         du->dk_state = WANTOPEN;
1146         {
1147         struct disklabel label;
1148
1149         bzero(&label, sizeof label);
1150         label.d_secsize = du->dk_dd.d_secsize;
1151         label.d_nsectors = du->dk_dd.d_nsectors;
1152         label.d_ntracks = du->dk_dd.d_ntracks;
1153         label.d_ncylinders = du->dk_dd.d_ncylinders;
1154         label.d_secpercyl = du->dk_dd.d_secpercyl;
1155         label.d_secperunit = du->dk_dd.d_secperunit;
1156         error = dsopen(dev, fmt, 0, &du->dk_slices, &label);
1157         }
1158         du->dk_flags &= ~DKFL_LABELLING;
1159         wdsleep(du->dk_ctrlr, "wdopn2");
1160         return (error);
1161 #else
1162         if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
1163                 /*
1164                  * wdtab[ctrlr].b_active != 0 implies  XXX applicable now ??
1165                  * drive_queue[lunit].b_act == NULL (?)  XXX applicable now ??
1166                  * so the following guards most things (until the next i/o).
1167                  * It doesn't guard against a new i/o starting and being
1168                  * affected by the label being changed.  Sigh.
1169                  */
1170                 wdsleep(du->dk_ctrlr, "wdopn1");
1171
1172                 du->dk_flags |= DKFL_LABELLING;
1173                 du->dk_state = WANTOPEN;
1174
1175                 error = dsinit(dkmodpart(dev, RAW_PART), 
1176                                &du->dk_dd, &du->dk_slices);
1177                 if (error != 0) {
1178                         du->dk_flags &= ~DKFL_LABELLING;
1179                         return (error);
1180                 }
1181                 /* XXX check value returned by wdwsetctlr(). */
1182                 wdwsetctlr(du);
1183                 if (dkslice(dev) == WHOLE_DISK_SLICE) {
1184                         dsopen(dev, fmt, du->dk_slices);
1185                         return (0);
1186                 }
1187
1188                 /*
1189                  * Read label using RAW_PART partition.
1190                  *
1191                  * If the drive has an MBR, then the current geometry (from
1192                  * wdgetctlr()) is used to read it; then the BIOS/DOS
1193                  * geometry is inferred and used to read the label off the
1194                  * 'c' partition.  Otherwise the label is read using the
1195                  * current geometry.  The label gives the final geometry.
1196                  * If bad sector handling is enabled, then this geometry
1197                  * is used to read the bad sector table.  The geometry
1198                  * changes occur inside readdisklabel() and are propagated
1199                  * to the driver by resetting the state machine.
1200                  *
1201                  * XXX can now handle changes directly since dsinit() doesn't
1202                  * do too much.
1203                  */
1204                 msg = correct_readdisklabel(dkmodpart(dev, RAW_PART), 
1205                     &du->dk_dd);
1206                 /* XXX check value returned by wdwsetctlr(). */
1207                 wdwsetctlr(du);
1208                 du->dk_flags &= ~DKFL_LABELLING;
1209                 if (msg != NULL) {
1210                         log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
1211                             lunit, msg);
1212                         if (part != RAW_PART)
1213                                 return (EINVAL);  /* XXX needs translation */
1214                         /*
1215                          * Soon return.  This is how slices without labels
1216                          * are allowed.  They only work on the raw partition.
1217                          */
1218                 } else {
1219                         unsigned long newsize, offset, size;
1220 #if 0
1221                         /*
1222                          * Force RAW_PART partition to be the whole disk.
1223                          */
1224                         offset = du->dk_dd.d_partitions[RAW_PART].p_offset;
1225                         if (offset != 0) {
1226                                 printf(
1227                 "wd%d: changing offset of '%c' partition from %lu to 0\n",
1228                                        du->dk_lunit, 'a' + RAW_PART, offset);
1229                                 du->dk_dd.d_partitions[RAW_PART].p_offset = 0;
1230                         }
1231                         size = du->dk_dd.d_partitions[RAW_PART].p_size;
1232                         newsize = du->dk_dd.d_secperunit;       /* XXX */
1233                         if (size != newsize) {
1234                                 printf(
1235                 "wd%d: changing size of '%c' partition from %lu to %lu\n",
1236                                        du->dk_lunit, 'a' + RAW_PART, size,
1237                                        newsize);
1238                                 du->dk_dd.d_partitions[RAW_PART].p_size
1239                                         = newsize;
1240                         }
1241 #endif
1242                 }
1243
1244                 /* Pick up changes made by readdisklabel(). */
1245                 wdsleep(du->dk_ctrlr, "wdopn2");
1246                 du->dk_state = WANTOPEN;
1247         }
1248
1249         /*
1250          * Warn if a partion is opened that overlaps another partition which
1251          * is open unless one is the "raw" partition (whole disk).
1252          */
1253         if ((du->dk_openpart & mask) == 0 && part != RAW_PART) {
1254                 int     start, end;
1255
1256                 pp = &du->dk_dd.d_partitions[part];
1257                 start = pp->p_offset;
1258                 end = pp->p_offset + pp->p_size;
1259                 for (pp = du->dk_dd.d_partitions;
1260                      pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
1261                      pp++) {
1262                         if (pp->p_offset + pp->p_size <= start ||
1263                             pp->p_offset >= end)
1264                                 continue;
1265                         if (pp - du->dk_dd.d_partitions == RAW_PART)
1266                                 continue;
1267                         if (du->dk_openpart
1268                             & (1 << (pp - du->dk_dd.d_partitions)))
1269                                 log(LOG_WARNING,
1270                                     "wd%d%c: overlaps open partition (%c)\n",
1271                                     lunit, part + 'a',
1272                                     pp - du->dk_dd.d_partitions + 'a');
1273                 }
1274         }
1275         if (part >= du->dk_dd.d_npartitions && part != RAW_PART)
1276                 return (ENXIO);
1277
1278         dsopen(dev, fmt, du->dk_slices);
1279
1280         return (0);
1281 #endif
1282 }
1283
1284 /*
1285  * Implement operations other than read/write.
1286  * Called from wdstart or wdintr during opens.
1287  * Uses finite-state-machine to track progress of operation in progress.
1288  * Returns 0 if operation still in progress, 1 if completed, 2 if error.
1289  */
1290 static int
1291 wdcontrol(register struct buf *bp)
1292 {
1293         register struct disk *du;
1294         int     ctrlr;
1295
1296         du = wddrives[dkunit(bp->b_dev)];
1297         ctrlr = du->dk_ctrlr_cmd640;
1298
1299         switch (du->dk_state) {
1300         case WANTOPEN:
1301 tryagainrecal:
1302                 wdtab[ctrlr].b_active = 1;
1303                 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) {
1304                         wderror(bp, du, "wdcontrol: wdcommand failed");
1305                         goto maybe_retry;
1306                 }
1307                 du->dk_state = RECAL;
1308                 return (0);
1309         case RECAL:
1310                 if (du->dk_status & WDCS_ERR || wdsetctlr(du) != 0) {
1311                         wderror(bp, du, "wdcontrol: recal failed");
1312 maybe_retry:
1313                         if (du->dk_status & WDCS_ERR)
1314                                 wdunwedge(du);
1315                         du->dk_state = WANTOPEN;
1316                         if (++wdtab[ctrlr].b_errcnt < RETRIES)
1317                                 goto tryagainrecal;
1318                         bp->b_error = ENXIO;    /* XXX needs translation */
1319                         bp->b_flags |= B_ERROR;
1320                         return (2);
1321                 }
1322                 wdtab[ctrlr].b_errcnt = 0;
1323                 du->dk_state = OPEN;
1324                 /*
1325                  * The rest of the initialization can be done by normal
1326                  * means.
1327                  */
1328                 return (1);
1329         }
1330         panic("wdcontrol");
1331         return (2);
1332 }
1333
1334 /*
1335  * Wait uninterruptibly until controller is not busy, then send it a command.
1336  * The wait usually terminates immediately because we waited for the previous
1337  * command to terminate.
1338  */
1339 static int
1340 wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
1341           u_int count, u_int command)
1342 {
1343         u_int   wdc;
1344
1345         wdc = du->dk_port;
1346         if (du->cfg_flags & WDOPT_SLEEPHACK) {
1347                 /* OK, so the APM bios has put the disk into SLEEP mode,
1348                  * how can we tell ?  Uhm, we can't.  There is no 
1349                  * standardized way of finding out, and the only way to
1350                  * wake it up is to reset it.  Bummer.
1351                  *
1352                  * All the many and varied versions of the IDE/ATA standard
1353                  * explicitly tells us not to look at these registers if
1354                  * the disk is in SLEEP mode.  Well, too bad really, we
1355                  * have to find out if it's in sleep mode before we can 
1356                  * avoid reading the registers.
1357                  *
1358                  * I have reason to belive that most disks will return
1359                  * either 0xff or 0x00 in all but the status register 
1360                  * when in SLEEP mode, but I have yet to see one return 
1361                  * 0x00, so we don't check for that yet.
1362                  *
1363                  * The check for WDCS_BUSY is for the case where the
1364                  * bios spins up the disk for us, but doesn't initialize
1365                  * it correctly                                 /phk
1366                  */
1367                 if(inb(wdc + wd_precomp) + inb(wdc + wd_cyl_lo) +
1368                     inb(wdc + wd_cyl_hi) + inb(wdc + wd_sdh) +
1369                     inb(wdc + wd_sector) + inb(wdc + wd_seccnt) == 6 * 0xff) {
1370                         if (bootverbose)
1371                                 printf("wd(%d,%d): disk aSLEEP\n",
1372                                         du->dk_ctrlr, du->dk_unit);
1373                         wdunwedge(du);
1374                 } else if(inb(wdc + wd_status) == WDCS_BUSY) {
1375                         if (bootverbose)
1376                                 printf("wd(%d,%d): disk is BUSY\n",
1377                                         du->dk_ctrlr, du->dk_unit);
1378                         wdunwedge(du);
1379                 }
1380         }
1381
1382         if (wdwait(du, 0, TIMEOUT) < 0)
1383                 return (1);
1384         if( command == WDCC_FEATURES) {
1385                 outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
1386                 outb(wdc + wd_features, count);
1387                 if ( count == WDFEA_SETXFER )
1388                         outb(wdc + wd_seccnt, sector);
1389         } else {
1390                 outb(wdc + wd_precomp, du->dk_dd.d_precompcyl / 4);
1391                 outb(wdc + wd_cyl_lo, cylinder);
1392                 outb(wdc + wd_cyl_hi, cylinder >> 8);
1393                 outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
1394                 if (head & WDSD_LBA)
1395                         outb(wdc + wd_sector, sector);
1396                 else
1397                         outb(wdc + wd_sector, sector + 1);
1398                 outb(wdc + wd_seccnt, count);
1399         }
1400         if (wdwait(du, (command == WDCC_DIAGNOSE || command == WDCC_IDC)
1401                        ? 0 : WDCS_READY, TIMEOUT) < 0)
1402                 return (1);
1403         outb(wdc + wd_command, command);
1404         return (0);
1405 }
1406
1407 static void
1408 wdsetmulti(struct disk *du)
1409 {
1410         /*
1411          * The config option flags low 8 bits define the maximum multi-block
1412          * transfer size.  If the user wants the maximum that the drive
1413          * is capable of, just set the low bits of the config option to
1414          * 0x00ff.
1415          */
1416         if ((du->cfg_flags & WDOPT_MULTIMASK) != 0 && (du->dk_multi > 1)) {
1417                 int configval = du->cfg_flags & WDOPT_MULTIMASK;
1418                 du->dk_multi = min(du->dk_multi, configval);
1419                 if (wdcommand(du, 0, 0, 0, du->dk_multi, WDCC_SET_MULTI)) {
1420                         du->dk_multi = 1;
1421                 } else {
1422                         if (wdwait(du, WDCS_READY, TIMEOUT) < 0) {
1423                                 du->dk_multi = 1;
1424                         }
1425                 }
1426         } else {
1427                 du->dk_multi = 1;
1428         }
1429 }
1430
1431 /*
1432  * issue IDC to drive to tell it just what geometry it is to be.
1433  */
1434 static int
1435 wdsetctlr(struct disk *du)
1436 {
1437         int error = 0;
1438 #ifdef WDDEBUG
1439         printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
1440                du->dk_ctrlr, du->dk_unit,
1441                du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
1442                du->dk_dd.d_nsectors);
1443 #endif
1444         if (!(du->dk_flags & DKFL_LBA)) {
1445                 if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
1446                         struct wdparams *wp;
1447         
1448                         printf("wd%d: can't handle %lu heads from partition table ",
1449                         du->dk_lunit, du->dk_dd.d_ntracks);
1450                         /* obtain parameters */
1451                         wp = &du->dk_params;
1452                         if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
1453                                 printf("(controller value %u restored)\n",
1454                                         wp->wdp_heads);
1455                                 du->dk_dd.d_ntracks = wp->wdp_heads;
1456                         }
1457                         else {
1458                                 printf("(truncating to 16)\n");
1459                                 du->dk_dd.d_ntracks = 16;
1460                         }
1461                 }
1462         
1463                 if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
1464                         printf("wd%d: cannot handle %lu sectors (max 255)\n",
1465                         du->dk_lunit, du->dk_dd.d_nsectors);
1466                         error = 1;
1467                 }
1468                 if (error) {
1469                         wdtab[du->dk_ctrlr_cmd640].b_errcnt += RETRIES;
1470                         return (1);
1471                 }
1472                 if (wdcommand(du, du->dk_dd.d_ncylinders,                                                     du->dk_dd.d_ntracks - 1, 0,
1473                               du->dk_dd.d_nsectors, WDCC_IDC) != 0
1474                               || wdwait(du, WDCS_READY, TIMEOUT) < 0) {
1475                         wderror((struct buf *)NULL, du, "wdsetctlr failed");
1476                         return (1);
1477                 }
1478         }
1479
1480         wdsetmulti(du);
1481
1482 #ifdef NOTYET
1483 /* set read caching and write caching */
1484         wdcommand(du, 0, 0, 0, WDFEA_RCACHE, WDCC_FEATURES);
1485         wdwait(du, WDCS_READY, TIMEOUT);
1486
1487         wdcommand(du, 0, 0, 0, WDFEA_WCACHE, WDCC_FEATURES);
1488         wdwait(du, WDCS_READY, TIMEOUT);
1489 #endif
1490
1491         return (0);
1492 }
1493
1494 #if 0
1495 /*
1496  * Wait until driver is inactive, then set up controller.
1497  */
1498 static int
1499 wdwsetctlr(struct disk *du)
1500 {
1501         int     stat;
1502         int     x;
1503
1504         wdsleep(du->dk_ctrlr, "wdwset");
1505         x = splbio();
1506         stat = wdsetctlr(du);
1507         wdflushirq(du, x);
1508         splx(x);
1509         return (stat);
1510 }
1511 #endif
1512
1513 /*
1514  * gross little callback function for wdddma interface. returns 1 for
1515  * success, 0 for failure.
1516  */
1517 static int
1518 wdsetmode(int mode, void *wdinfo)
1519 {
1520     int i;
1521     struct disk *du;
1522
1523     du = wdinfo;
1524     if (bootverbose)
1525         printf("wd%d: wdsetmode() setting transfer mode to %02x\n", 
1526                du->dk_lunit, mode);
1527     i = wdcommand(du, 0, 0, mode, WDFEA_SETXFER, 
1528                   WDCC_FEATURES) == 0 &&
1529         wdwait(du, WDCS_READY, TIMEOUT) == 0;
1530     return i;
1531 }
1532
1533 /*
1534  * issue READP to drive to ask it what it is.
1535  */
1536 static int
1537 wdgetctlr(struct disk *du)
1538 {
1539         int     i;
1540         char    tb[DEV_BSIZE], tb2[DEV_BSIZE];
1541         struct wdparams *wp = NULL;
1542         u_long flags = du->cfg_flags;
1543 again:
1544         if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0
1545             || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
1546
1547                 /*
1548                  * if we failed on the second try, assume non-32bit
1549                  */
1550                 if( du->dk_flags & DKFL_32BIT)
1551                         goto failed;
1552
1553                 /* XXX need to check error status after final transfer. */
1554                 /*
1555                  * Old drives don't support WDCC_READP.  Try a seek to 0.
1556                  * Some IDE controllers return trash if there is no drive
1557                  * attached, so first test that the drive can be selected.
1558                  * This also avoids long waits for nonexistent drives.
1559                  */
1560                 if (wdwait(du, 0, TIMEOUT) < 0)
1561                         return (1);
1562                 outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
1563                 DELAY(5000);    /* usually unnecessary; drive select is fast */
1564                 /*
1565                  * Do this twice: may get a false WDCS_READY the first time.
1566                  */
1567                 inb(du->dk_port + wd_status);
1568                 if ((inb(du->dk_port + wd_status) & (WDCS_BUSY | WDCS_READY))
1569                     != WDCS_READY
1570                     || wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
1571                     || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
1572                         return (1);
1573
1574                 if (du->dk_unit == bootinfo.bi_n_bios_used) {
1575                         du->dk_dd.d_secsize = DEV_BSIZE;
1576                         du->dk_dd.d_nsectors =
1577                             bootinfo.bi_bios_geom[du->dk_unit] & 0xff;
1578                         du->dk_dd.d_ntracks =
1579                             ((bootinfo.bi_bios_geom[du->dk_unit] >> 8) & 0xff)
1580                             + 1;
1581                         /* XXX Why 2 ? */
1582                         du->dk_dd.d_ncylinders =
1583                             (bootinfo.bi_bios_geom[du->dk_unit] >> 16) + 2;
1584                         du->dk_dd.d_secpercyl =
1585                             du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1586                         du->dk_dd.d_secperunit =
1587                             du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
1588 #if 0
1589                         du->dk_dd.d_partitions[WDRAW].p_size =
1590                                 du->dk_dd.d_secperunit;
1591                         du->dk_dd.d_type = DTYPE_ST506;
1592                         du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1593                         strncpy(du->dk_dd.d_typename, "Bios geometry",
1594                                 sizeof du->dk_dd.d_typename);
1595                         strncpy(du->dk_params.wdp_model, "ST506",
1596                                 sizeof du->dk_params.wdp_model);
1597 #endif
1598                         bootinfo.bi_n_bios_used ++;
1599                         return 0;
1600                 }
1601                 /*
1602                  * Fake minimal drive geometry for reading the MBR.
1603                  * readdisklabel() may enlarge it to read the label.
1604                  */
1605                 du->dk_dd.d_secsize = DEV_BSIZE;
1606                 du->dk_dd.d_nsectors = 17;
1607                 du->dk_dd.d_ntracks = 1;
1608                 du->dk_dd.d_ncylinders = 1;
1609                 du->dk_dd.d_secpercyl = 17;
1610                 du->dk_dd.d_secperunit = 17;
1611
1612 #if 0
1613                 /*
1614                  * Fake maximal drive size for writing the label.
1615                  */
1616                 du->dk_dd.d_partitions[RAW_PART].p_size = 64 * 16 * 1024;
1617
1618                 /*
1619                  * Fake some more of the label for printing by disklabel(1)
1620                  * in case there is no real label.
1621                  */
1622                 du->dk_dd.d_type = DTYPE_ST506;
1623                 du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1624                 strncpy(du->dk_dd.d_typename, "Fake geometry",
1625                         sizeof du->dk_dd.d_typename);
1626 #endif
1627
1628                 /* Fake the model name for printing by wdattach(). */
1629                 strncpy(du->dk_params.wdp_model, "unknown",
1630                         sizeof du->dk_params.wdp_model);
1631
1632                 return (0);
1633         }
1634
1635         /* obtain parameters */
1636         wp = &du->dk_params;
1637         if (du->dk_flags & DKFL_32BIT)
1638                 insl(du->dk_port + wd_data, tb, sizeof(tb) / sizeof(long));
1639         else
1640                 insw(du->dk_port + wd_data, tb, sizeof(tb) / sizeof(short));
1641
1642         /* try 32-bit data path (VLB IDE controller) */
1643         if (flags & WDOPT_32BIT) {
1644                 if (! (du->dk_flags & DKFL_32BIT)) {
1645                         bcopy(tb, tb2, sizeof(struct wdparams));
1646                         du->dk_flags |= DKFL_32BIT;
1647                         goto again;
1648                 }
1649
1650                 /* check that we really have 32-bit controller */
1651                 if (bcmp (tb, tb2, sizeof(struct wdparams)) != 0) {
1652 failed:
1653                         /* test failed, use 16-bit i/o mode */
1654                         bcopy(tb2, tb, sizeof(struct wdparams));
1655                         du->dk_flags &= ~DKFL_32BIT;
1656                 }
1657         }
1658
1659         bcopy(tb, wp, sizeof(struct wdparams));
1660
1661         /* shuffle string byte order */
1662         for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i += 2) {
1663                 u_short *p;
1664
1665                 p = (u_short *) (wp->wdp_model + i);
1666                 *p = ntohs(*p);
1667         }
1668         /*
1669          * Clean up the wdp_model by converting nulls to spaces, and
1670          * then removing the trailing spaces.
1671          */
1672         for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i++) {
1673                 if (wp->wdp_model[i] == '\0') {
1674                         wp->wdp_model[i] = ' ';
1675                 }
1676         }
1677         for (i = sizeof(wp->wdp_model) - 1;
1678             (i >= 0 && wp->wdp_model[i] == ' '); i--) {
1679                 wp->wdp_model[i] = '\0';
1680         }
1681
1682         /*
1683          * find out the drives maximum multi-block transfer capability
1684          */
1685         du->dk_multi = wp->wdp_nsecperint & 0xff;
1686         wdsetmulti(du);
1687
1688         /*
1689          * check drive's DMA capability
1690          */
1691         if (wddma[du->dk_interface].wdd_candma) {
1692                 du->dk_dmacookie = wddma[du->dk_interface].wdd_candma(
1693                     du->dk_port, du->dk_ctrlr, du->dk_unit);
1694         /* does user want this? */
1695                 if ((du->cfg_flags & WDOPT_DMA) &&
1696             /* have we got a DMA controller? */
1697                      du->dk_dmacookie &&
1698                     /* can said drive do DMA? */
1699                      wddma[du->dk_interface].wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)) {
1700                     du->dk_flags |= DKFL_USEDMA;
1701                 }
1702         } else {
1703                 du->dk_dmacookie = NULL;
1704         }
1705
1706 #ifdef WDDEBUG
1707         printf(
1708 "\nwd(%d,%d): wdgetctlr: gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
1709                du->dk_ctrlr, du->dk_unit, wp->wdp_config, wp->wdp_cylinders,
1710                wp->wdp_heads, wp->wdp_sectors, wp->wdp_buffertype,
1711                wp->wdp_buffersize, wp->wdp_model);
1712 #endif
1713
1714         /* update disklabel given drive information */
1715         du->dk_dd.d_secsize = DEV_BSIZE;
1716         if ((du->cfg_flags & WDOPT_LBA) && wp->wdp_lbasize) {
1717                 du->dk_dd.d_nsectors = 63;
1718                 if (wp->wdp_lbasize < 16*63*1024) {             /* <=528.4 MB */
1719                         du->dk_dd.d_ntracks = 16;
1720                 }
1721                 else if (wp->wdp_lbasize < 32*63*1024) {        /* <=1.057 GB */
1722                         du->dk_dd.d_ntracks = 32;
1723                 }
1724                 else if (wp->wdp_lbasize < 64*63*1024) {        /* <=2.114 GB */
1725                         du->dk_dd.d_ntracks = 64;
1726                 }
1727                 else if (wp->wdp_lbasize < 128*63*1024) {       /* <=4.228 GB */
1728                         du->dk_dd.d_ntracks = 128;
1729                 }
1730                 else if (wp->wdp_lbasize < 255*63*1024) {       /* <=8.422 GB */
1731                         du->dk_dd.d_ntracks = 255;
1732                 }
1733                 else {                                          /* >8.422 GB */
1734                         du->dk_dd.d_ntracks = 255;              /* XXX */
1735                 }
1736                 du->dk_dd.d_secpercyl= du->dk_dd.d_ntracks*du->dk_dd.d_nsectors;
1737                 du->dk_dd.d_ncylinders = wp->wdp_lbasize/du->dk_dd.d_secpercyl;
1738                 du->dk_dd.d_secperunit = wp->wdp_lbasize;
1739                 du->dk_flags |= DKFL_LBA;
1740         }
1741         else {
1742                 du->dk_dd.d_ncylinders = wp->wdp_cylinders;     /* +- 1 */
1743                 du->dk_dd.d_ntracks = wp->wdp_heads;
1744                 du->dk_dd.d_nsectors = wp->wdp_sectors;
1745                 du->dk_dd.d_secpercyl = 
1746                         du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1747                 du->dk_dd.d_secperunit = 
1748                         du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
1749                 if (wp->wdp_cylinders == 16383 &&
1750                     du->dk_dd.d_secperunit < wp->wdp_lbasize) {
1751                         du->dk_dd.d_secperunit = wp->wdp_lbasize;
1752                         du->dk_dd.d_ncylinders = 
1753                                 du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
1754                 }
1755         }
1756         if (WDOPT_FORCEHD(du->cfg_flags)) {
1757                 du->dk_dd.d_ntracks = WDOPT_FORCEHD(du->cfg_flags);
1758                 du->dk_dd.d_secpercyl = 
1759                     du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1760                 du->dk_dd.d_ncylinders =
1761                     du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
1762         }
1763         if (du->dk_dd.d_ncylinders > 0x10000 && !(du->cfg_flags & WDOPT_LBA)) {
1764                 du->dk_dd.d_ncylinders = 0x10000;
1765                 du->dk_dd.d_secperunit = du->dk_dd.d_secpercyl *
1766                     du->dk_dd.d_ncylinders;
1767                 printf(
1768                     "wd%d: cannot handle %d total sectors; truncating to %lu\n",
1769                     du->dk_lunit, wp->wdp_lbasize, du->dk_dd.d_secperunit);
1770         }
1771 #if 0
1772         du->dk_dd.d_partitions[RAW_PART].p_size = du->dk_dd.d_secperunit;
1773         /* dubious ... */
1774         bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
1775         bcopy(wp->wdp_model + 20, du->dk_dd.d_packname, 14 - 1);
1776         /* better ... */
1777         du->dk_dd.d_type = DTYPE_ESDI;
1778         du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1779 #endif
1780
1781         return (0);
1782 }
1783
1784 int
1785 wdclose(dev_t dev, int flags, int fmt, struct proc *p)
1786 {
1787         dsclose(dev, fmt, wddrives[dkunit(dev)]->dk_slices);
1788         return (0);
1789 }
1790
1791 int
1792 wdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
1793 {
1794         int     lunit = dkunit(dev);
1795         register struct disk *du;
1796         int     error;
1797
1798         du = wddrives[lunit];
1799         wdsleep(du->dk_ctrlr, "wdioct");
1800         error = dsioctl(dev, cmd, addr, flags, &du->dk_slices);
1801         if (error != ENOIOCTL)
1802                 return (error);
1803         return (ENOTTY);
1804 }
1805
1806 int
1807 wdsize(dev_t dev)
1808 {
1809         struct disk *du;
1810         int     lunit;
1811
1812         lunit = dkunit(dev);
1813         if (lunit >= NWD || dktype(dev) != 0)
1814                 return (-1);
1815         du = wddrives[lunit];
1816         if (du == NULL)
1817                 return (-1);
1818         return (dssize(dev, &du->dk_slices));
1819 }
1820  
1821 int
1822 wddump(dev_t dev)
1823 {
1824         register struct disk *du;
1825         struct disklabel *lp;
1826         long    num;            /* number of sectors to write */
1827         int     lunit, part;
1828         long    blkoff, blknum;
1829         long    blkcnt, blknext;
1830         u_long  ds_offset;
1831         u_long  nblocks;
1832         static int wddoingadump = 0;
1833         long    cylin, head, sector;
1834         long    secpertrk, secpercyl;
1835         char   *addr;
1836
1837         /* Toss any characters present prior to dump. */
1838         while (cncheckc() != -1)
1839                 ;
1840
1841         /* Check for acceptable device. */
1842         /* XXX should reset to maybe allow du->dk_state < OPEN. */
1843         lunit = dkunit(dev);    /* eventually support floppies? */
1844         part = dkpart(dev);
1845         if (lunit >= NWD || (du = wddrives[lunit]) == NULL
1846             || du->dk_state < OPEN
1847             || (lp = dsgetlabel(dev, du->dk_slices)) == NULL)
1848                 return (ENXIO);
1849
1850         /* Size of memory to dump, in disk sectors. */
1851         num = (u_long)Maxmem * PAGE_SIZE / du->dk_dd.d_secsize;
1852
1853
1854         secpertrk = du->dk_dd.d_nsectors;
1855         secpercyl = du->dk_dd.d_secpercyl;
1856         nblocks = lp->d_partitions[part].p_size;
1857         blkoff = lp->d_partitions[part].p_offset;
1858         /* XXX */
1859         ds_offset = du->dk_slices->dss_slices[dkslice(dev)].ds_offset;
1860         blkoff += ds_offset;
1861
1862 #if 0
1863         printf("part %d, nblocks %lu, dumplo %ld num %ld\n",
1864             part, nblocks, dumplo, num);
1865 #endif
1866
1867         /* Check transfer bounds against partition size. */
1868         if (dumplo < 0 || dumplo + num > nblocks)
1869                 return (EINVAL);
1870
1871         /* Check if we are being called recursively. */
1872         if (wddoingadump)
1873                 return (EFAULT);
1874
1875 #if 0
1876         /* Mark controller active for if we panic during the dump. */
1877         wdtab[du->dk_ctrlr].b_active = 1;
1878 #endif
1879         wddoingadump = 1;
1880
1881         /* Recalibrate the drive. */
1882         DELAY(5);               /* ATA spec XXX NOT */
1883         if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
1884             || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
1885             || wdsetctlr(du) != 0) {
1886                 wderror((struct buf *)NULL, du, "wddump: recalibrate failed");
1887                 return (EIO);
1888         }
1889
1890         du->dk_flags |= DKFL_SINGLE;
1891         addr = (char *) 0;
1892         blknum = dumplo + blkoff;
1893         while (num > 0) {
1894                 blkcnt = num;
1895                 if (blkcnt > MAXTRANSFER)
1896                         blkcnt = MAXTRANSFER;
1897                 if ((du->dk_flags & DKFL_LBA) == 0) {
1898                         /* XXX keep transfer within current cylinder. */
1899                         if ((blknum + blkcnt - 1) / secpercyl !=
1900                             blknum / secpercyl)
1901                                 blkcnt = secpercyl - (blknum % secpercyl);
1902                 }
1903                 blknext = blknum + blkcnt;
1904
1905                 /* Compute disk address. */
1906                 if (du->dk_flags & DKFL_LBA) {
1907                         sector = (blknum >> 0) & 0xff; 
1908                         cylin = (blknum >> 8) & 0xffff;
1909                         head = ((blknum >> 24) & 0xf) | WDSD_LBA; 
1910                 } else {
1911                         cylin = blknum / secpercyl;
1912                         head = (blknum % secpercyl) / secpertrk;
1913                         sector = blknum % secpertrk;
1914                 }
1915
1916 #if 0
1917                 /* Let's just talk about this first... */
1918                 printf("cylin %ld head %ld sector %ld addr %p count %ld\n",
1919                     cylin, head, sector, addr, blkcnt);
1920                 cngetc();
1921 #endif
1922
1923                 /* Do the write. */
1924                 if (wdcommand(du, cylin, head, sector, blkcnt, WDCC_WRITE)
1925                     != 0) {
1926                         wderror((struct buf *)NULL, du,
1927                                 "wddump: timeout waiting to to give command");
1928                         return (EIO);
1929                 }
1930                 while (blkcnt != 0) {
1931                         if (is_physical_memory((vm_offset_t)addr))
1932                                 pmap_kenter((vm_offset_t)CADDR1,
1933                                            trunc_page((vm_offset_t)addr));
1934                         else
1935                                 pmap_kenter((vm_offset_t)CADDR1,
1936                                            trunc_page(0));
1937
1938                         /* Ready to send data? */
1939                         DELAY(5);       /* ATA spec */
1940                         if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT)
1941                             < 0) {
1942                                 wderror((struct buf *)NULL, du,
1943                                         "wddump: timeout waiting for DRQ");
1944                                 return (EIO);
1945                         }
1946                         if (du->dk_flags & DKFL_32BIT)
1947                                 outsl(du->dk_port + wd_data,
1948                                       CADDR1 + ((int)addr & PAGE_MASK),
1949                                       DEV_BSIZE / sizeof(long));
1950                         else
1951                                 outsw(du->dk_port + wd_data,
1952                                       CADDR1 + ((int)addr & PAGE_MASK),
1953                                       DEV_BSIZE / sizeof(short));
1954                         addr += DEV_BSIZE;
1955                         /*
1956                          * If we are dumping core, it may take a while.
1957                          * So reassure the user and hold off any watchdogs.
1958                          */
1959                         if ((unsigned)addr % (1024 * 1024) == 0) {
1960 #ifdef  HW_WDOG
1961                                 if (wdog_tickler)
1962                                         (*wdog_tickler)();
1963 #endif /* HW_WDOG */
1964                                 printf("%ld ", num / (1024 * 1024 / DEV_BSIZE));
1965                         }
1966                         num--;
1967                         blkcnt--;
1968                 }
1969
1970                 /* Wait for completion. */
1971                 DELAY(5);       /* ATA spec XXX NOT */
1972                 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) < 0) {
1973                         wderror((struct buf *)NULL, du,
1974                                 "wddump: timeout waiting for status");
1975                         return (EIO);
1976                 }
1977
1978                 /* Check final status. */
1979                 if ((du->dk_status
1980                     & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ | WDCS_ERR))
1981                     != (WDCS_READY | WDCS_SEEKCMPLT)) {
1982                         wderror((struct buf *)NULL, du,
1983                                 "wddump: extra DRQ, or error");
1984                         return (EIO);
1985                 }
1986
1987                 /* Update block count. */
1988                 blknum = blknext;
1989
1990                 /* Operator aborting dump? */
1991                 if (cncheckc() != -1)
1992                         return (EINTR);
1993         }
1994         return (0);
1995 }
1996
1997 static void
1998 wderror(struct buf *bp, struct disk *du, char *mesg)
1999 {
2000         if (bp == NULL)
2001                 printf("wd%d: %s", du->dk_lunit, mesg);
2002         else
2003                 diskerr(bp, mesg, LOG_PRINTF, du->dk_skip,
2004                         dsgetlabel(bp->b_dev, du->dk_slices));
2005         printf(" (status %b error %b)\n",
2006                du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS);
2007 }
2008
2009 /*
2010  * Discard any interrupts that were latched by the interrupt system while
2011  * we were doing polled i/o.
2012  */
2013 static void
2014 wdflushirq(struct disk *du, int old_ipl)
2015 {
2016         wdtab[du->dk_ctrlr_cmd640].b_active = 2;
2017         splx(old_ipl);
2018         (void)splbio();
2019         wdtab[du->dk_ctrlr_cmd640].b_active = 0;
2020 }
2021
2022 /*
2023  * Reset the controller.
2024  */
2025 static int
2026 wdreset(struct disk *du)
2027 {
2028         int     err = 0;
2029
2030         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
2031                 wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
2032         (void)wdwait(du, 0, TIMEOUT);
2033         outb(du->dk_altport, WDCTL_IDS | WDCTL_RST);
2034         DELAY(10 * 1000);
2035         outb(du->dk_altport, WDCTL_IDS);
2036         outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
2037         if (wdwait(du, 0, TIMEOUT) != 0)
2038                 err = 1;                /* no IDE drive found */
2039         du->dk_error = inb(du->dk_port + wd_error);
2040         if (du->dk_error != 0x01)
2041                 err = 1;                /* the drive is incompatible */
2042         outb(du->dk_altport, WDCTL_4BIT);
2043         return (err);
2044 }
2045
2046 /*
2047  * Sleep until driver is inactive.
2048  * This is used only for avoiding rare race conditions, so it is unimportant
2049  * that the sleep may be far too short or too long.
2050  */
2051 static void
2052 wdsleep(int ctrlr, char *wmesg)
2053 {
2054         int s = splbio();
2055         if (eide_quirks & Q_CMD640B)
2056                 ctrlr = PRIMARY;
2057         while (wdtab[ctrlr].b_active)
2058                 tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1);
2059         splx(s);
2060 }
2061
2062 static void
2063 wdtimeout(void *cdu)
2064 {
2065         struct disk *du;
2066         int     x;
2067         static  int     timeouts;
2068
2069         du = (struct disk *)cdu;
2070         x = splbio();
2071         if (du->dk_timeout != 0 && --du->dk_timeout == 0) {
2072                 if(timeouts++ <= 5) {
2073                         char *msg;
2074
2075                         msg = (timeouts > 5) ?
2076 "Last time I say: interrupt timeout.  Probably a portable PC." :
2077 "interrupt timeout";
2078                         wderror((struct buf *)NULL, du, msg);
2079                         if (du->dk_dmacookie)
2080                                 printf("wd%d: wdtimeout() DMA status %b\n", 
2081                                        du->dk_lunit,
2082                                        wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie), 
2083                                        WDDS_BITS);
2084                 }
2085                 wdunwedge(du);
2086                 wdflushirq(du, x);
2087                 du->dk_skip = 0;
2088                 du->dk_flags |= DKFL_SINGLE;
2089                 wdstart(du->dk_ctrlr);
2090         }
2091         timeout(wdtimeout, cdu, hz);
2092         splx(x);
2093 }
2094
2095 /*
2096  * Reset the controller after it has become wedged.  This is different from
2097  * wdreset() so that wdreset() can be used in the probe and so that this
2098  * can restore the geometry .
2099  */
2100 static int
2101 wdunwedge(struct disk *du)
2102 {
2103         struct disk *du1;
2104         int     lunit;
2105
2106         /* Schedule other drives for recalibration. */
2107         for (lunit = 0; lunit < NWD; lunit++)
2108                 if ((du1 = wddrives[lunit]) != NULL && du1 != du
2109                     && du1->dk_ctrlr == du->dk_ctrlr
2110                     && du1->dk_state > WANTOPEN)
2111                         du1->dk_state = WANTOPEN;
2112
2113         DELAY(RECOVERYTIME);
2114         if (wdreset(du) == 0) {
2115                 /*
2116                  * XXX - recalibrate current drive now because some callers
2117                  * aren't prepared to have its state change.
2118                  */
2119                 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) == 0
2120                     && wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) == 0
2121                     && wdsetctlr(du) == 0)
2122                         return (0);
2123         }
2124         wderror((struct buf *)NULL, du, "wdunwedge failed");
2125         return (1);
2126 }
2127
2128 /*
2129  * Wait uninterruptibly until controller is not busy and either certain
2130  * status bits are set or an error has occurred.
2131  * The wait is usually short unless it is for the controller to process
2132  * an entire critical command.
2133  * Return 1 for (possibly stale) controller errors, -1 for timeout errors,
2134  * or 0 for no errors.
2135  * Return controller status in du->dk_status and, if there was a controller
2136  * error, return the error code in du->dk_error.
2137  */
2138 #ifdef WD_COUNT_RETRIES
2139 static int min_retries[NWDC];
2140 #endif
2141
2142 static int
2143 wdwait(struct disk *du, u_char bits_wanted, int timeout)
2144 {
2145         int     wdc;
2146         u_char  status;
2147
2148 #define POLLING         1000
2149
2150         wdc = du->dk_port;
2151         timeout += POLLING;
2152
2153 /*
2154  * This delay is really too long, but does not impact the performance
2155  * as much when using the multi-sector option.  Shorter delays have
2156  * caused I/O errors on some drives and system configs.  This should
2157  * probably be fixed if we develop a better short term delay mechanism.
2158  */
2159         DELAY(1);
2160
2161         do {
2162 #ifdef WD_COUNT_RETRIES
2163                 if (min_retries[du->dk_ctrlr] > timeout
2164                     || min_retries[du->dk_ctrlr] == 0)
2165                         min_retries[du->dk_ctrlr] = timeout;
2166 #endif
2167                 du->dk_status = status = inb(wdc + wd_status);
2168                 /*
2169                  * Atapi drives have a very interesting feature, when attached
2170                  * as a slave on the IDE bus, and there is no master.
2171                  * They release the bus after getting the command.
2172                  * We should reselect the drive here to get the status.
2173                  */
2174                 if (status == 0xff) {
2175                         outb(wdc + wd_sdh, WDSD_IBM | du->dk_unit << 4);
2176                         du->dk_status = status = inb(wdc + wd_status);
2177                 }
2178                 if (!(status & WDCS_BUSY)) {
2179                         if (status & WDCS_ERR) {
2180                                 du->dk_error = inb(wdc + wd_error);
2181                                 /*
2182                                  * We once returned here.  This is wrong
2183                                  * because the error bit is apparently only
2184                                  * valid after the controller has interrupted
2185                                  * (e.g., the error bit is stale when we wait
2186                                  * for DRQ for writes).  So we can't depend
2187                                  * on the error bit at all when polling for
2188                                  * command completion.
2189                                  */
2190                         }
2191                         if ((status & bits_wanted) == bits_wanted) {
2192                                 return (status & WDCS_ERR);
2193                         }
2194                 }
2195                 if (timeout < TIMEOUT)
2196                         /*
2197                          * Switch to a polling rate of about 1 KHz so that
2198                          * the timeout is almost machine-independent.  The
2199                          * controller is taking a long time to respond, so
2200                          * an extra msec won't matter.
2201                          */
2202                         DELAY(1000);
2203                 else
2204                         DELAY(1);
2205         } while (--timeout != 0);
2206         return (-1);
2207 }
2208
2209 #endif /* NWDC > 0 */