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