FreeBSD/Linux Kernel Cross Reference
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: releng/5.0/sys/pc98/pc98/wd.c 105242 2002-10-16 13:41:12Z phk $
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 dev_t dev;
475
476 dvp->id_intr = wdintr;
477
478 if (dvp->id_unit >= NWDC)
479 return (0);
480
481 if (eide_quirks & Q_CMD640B) {
482 if (dvp->id_unit == PRIMARY) {
483 printf("wdc0: CMD640B workaround enabled\n");
484 bioq_init(&wdtab[PRIMARY].controller_queue);
485 }
486 } else
487 bioq_init(&wdtab[dvp->id_unit].controller_queue);
488
489 sprintf(buf, "wdc%d", dvp->id_unit);
490 i = 0;
491 while ((resource_find_match(&i, &dname, &lunit, "at", buf)) == 0) {
492 if (strcmp(dname, "wd"))
493 /* Avoid a bit of foot shooting. */
494 continue;
495
496 if (lunit >= NWD)
497 continue;
498 #ifdef PC98
499 if ((lunit%2)!=0) {
500 if ((PC98_SYSTEM_PARAMETER(0x457) & 0x40)==0) {
501 continue;
502 }
503 }
504 #endif
505
506 if (resource_int_value("wd", lunit, "drive", &unit) != 0)
507 continue;
508 if (resource_int_value("wd", lunit, "flags", &flags) != 0)
509 flags = 0;
510
511 du = malloc(sizeof *du, M_TEMP, M_NOWAIT | M_ZERO);
512 if (du == NULL)
513 continue;
514 if (wddrives[lunit] != NULL)
515 panic("drive attached twice");
516 wddrives[lunit] = du;
517 bioq_init(&drive_queue[lunit]);
518 du->dk_ctrlr = dvp->id_unit;
519 if (eide_quirks & Q_CMD640B) {
520 du->dk_ctrlr_cmd640 = PRIMARY;
521 } else {
522 du->dk_ctrlr_cmd640 = du->dk_ctrlr;
523 }
524 du->dk_unit = unit;
525 du->dk_lunit = lunit;
526 du->dk_port = dvp->id_iobase;
527
528 du->dk_altport = du->dk_port + wd_ctlr;
529 /*
530 * Use the individual device flags or the controller
531 * flags.
532 */
533 du->cfg_flags = flags |
534 ((dvp->id_flags) >> (16 * unit));
535
536 if (wdgetctlr(du) == 0) {
537 /*
538 * Print out description of drive.
539 * wdp_model may not be null terminated.
540 */
541 printf("wdc%d: unit %d (wd%d): <%.*s>",
542 dvp->id_unit, unit, lunit,
543 (int)sizeof(du->dk_params.wdp_model),
544 du->dk_params.wdp_model);
545 if (du->dk_flags & DKFL_LBA)
546 printf(", LBA");
547 if (du->dk_flags & DKFL_USEDMA)
548 printf(", DMA");
549 if (du->dk_flags & DKFL_32BIT)
550 printf(", 32-bit");
551 if (du->dk_multi > 1)
552 printf(", multi-block-%d", du->dk_multi);
553 if (du->cfg_flags & WDOPT_SLEEPHACK)
554 printf(", sleep-hack");
555 printf("\n");
556 if (du->dk_params.wdp_heads == 0)
557 printf("wd%d: size unknown, using %s values\n",
558 lunit, du->dk_dd.d_secperunit > 17
559 ? "BIOS" : "fake");
560 printf( "wd%d: %luMB (%lu sectors), "
561 "%lu cyls, %lu heads, %lu S/T, %lu B/S\n",
562 lunit,
563 du->dk_dd.d_secperunit
564 / ((1024L * 1024L) / du->dk_dd.d_secsize),
565 du->dk_dd.d_secperunit,
566 du->dk_dd.d_ncylinders,
567 du->dk_dd.d_ntracks,
568 du->dk_dd.d_nsectors,
569 du->dk_dd.d_secsize);
570
571 if (bootverbose) {
572 wp = &du->dk_params;
573 printf( "wd%d: ATA INQUIRE valid = %04x, "
574 "dmamword = %04x, apio = %04x, "
575 "udma = %04x\n",
576 du->dk_lunit,
577 wp->wdp_atavalid,
578 wp->wdp_dmamword,
579 wp->wdp_eidepiomodes,
580 wp->wdp_udmamode);
581 }
582
583 /*
584 * Start timeout routine for this drive.
585 * XXX timeout should be per controller.
586 */
587 wdtimeout(du);
588
589 /*
590 * Export the drive to the devstat interface.
591 */
592 devstat_add_entry(&du->dk_stats, "wd",
593 lunit, du->dk_dd.d_secsize,
594 DEVSTAT_NO_ORDERED_TAGS,
595 DEVSTAT_TYPE_DIRECT |
596 DEVSTAT_TYPE_IF_IDE,
597 DEVSTAT_PRIORITY_DISK);
598
599 /*
600 * Register this media as a disk
601 */
602 dev = disk_create(lunit, &du->disk, 0, &wd_cdevsw,
603 &wddisk_cdevsw);
604 dev->si_drv1 = du;
605
606 } else {
607 free(du, M_TEMP);
608 wddrives[lunit] = NULL;
609 }
610 }
611 /*
612 * Probe all free IDE units, searching for ATAPI drives.
613 */
614 #ifdef PC98
615 for (unit=0; unit<4; ++unit) {
616 outb(0x432,unit%2);
617 #else
618 for (unit=0; unit<2; ++unit) {
619 #endif /* PC98 */
620 for (lunit=0; lunit<NWD; ++lunit)
621 if (wddrives[lunit] &&
622 wddrives[lunit]->dk_ctrlr == dvp->id_unit &&
623 wddrives[lunit]->dk_unit == unit)
624 goto next;
625 if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase))
626 atapictrlr = dvp->id_unit;
627 next: ;
628 }
629 /*
630 * Discard any interrupts generated by wdgetctlr(). wdflushirq()
631 * doesn't work now because the ambient ipl is too high.
632 */
633 if (eide_quirks & Q_CMD640B) {
634 wdtab[PRIMARY].b_active = 2;
635 } else {
636 wdtab[dvp->id_unit].b_active = 2;
637 }
638
639 return (1);
640 }
641
642 /* Read/write routine for a buffer. Finds the proper unit, range checks
643 * arguments, and schedules the transfer. Does not wait for the transfer
644 * to complete. Multi-page transfers are supported. All I/O requests must
645 * be a multiple of a sector in length.
646 */
647 void
648 wdstrategy(register struct bio *bp)
649 {
650 struct softc *du;
651 int lunit;
652 int s;
653
654 du = bp->bio_dev->si_drv1;
655 if (du == NULL || bp->bio_blkno < 0 ||
656 bp->bio_bcount % DEV_BSIZE != 0) {
657
658 bp->bio_error = EINVAL;
659 bp->bio_flags |= BIO_ERROR;
660 goto done;
661 }
662 lunit = du->dk_lunit;
663
664 #ifdef PC98
665 outb(0x432,(du->dk_unit)%2);
666 #endif
667
668 /* queue transfer on drive, activate drive and controller if idle */
669 s = splbio();
670
671 /* Pick up changes made by readdisklabel(). */
672 if (du->dk_flags & DKFL_LABELLING && du->dk_state > RECAL) {
673 wdsleep(du->dk_ctrlr, "wdlab");
674 du->dk_state = WANTOPEN;
675 }
676
677 bioqdisksort(&drive_queue[lunit], bp);
678
679 if (wdutab[lunit].b_active == 0)
680 wdustart(du); /* start drive */
681
682 if (wdtab[du->dk_ctrlr_cmd640].b_active == 0)
683 wdstart(du->dk_ctrlr); /* start controller */
684
685 /* Tell devstat that we have started a transaction on this drive */
686 devstat_start_transaction(&du->dk_stats);
687
688 splx(s);
689 return;
690
691 done:
692 /* toss transfer, we're done early */
693 biodone(bp);
694 }
695
696 /*
697 * Routine to queue a command to the controller. The unit's
698 * request is linked into the active list for the controller.
699 * If the controller is idle, the transfer is started.
700 */
701 static void
702 wdustart(register struct softc *du)
703 {
704 register struct bio *bp;
705 int ctrlr = du->dk_ctrlr_cmd640;
706
707 #ifdef PC98
708 outb(0x432,(du->dk_unit)%2);
709 #endif
710 /* unit already active? */
711 if (wdutab[du->dk_lunit].b_active)
712 return;
713
714
715 bp = bioq_first(&drive_queue[du->dk_lunit]);
716 if (bp == NULL) { /* yes, an assign */
717 return;
718 }
719 /*
720 * store away which device we came from.
721 */
722 bp->bio_driver1 = du;
723
724 bioq_remove(&drive_queue[du->dk_lunit], bp);
725
726 /* link onto controller queue */
727 bioq_insert_tail(&wdtab[ctrlr].controller_queue, bp);
728
729 /* mark the drive unit as busy */
730 wdutab[du->dk_lunit].b_active = 1;
731
732 }
733
734 /*
735 * Controller startup routine. This does the calculation, and starts
736 * a single-sector read or write operation. Called to start a transfer,
737 * or from the interrupt routine to continue a multi-sector transfer.
738 * RESTRICTIONS:
739 * 1. The transfer length must be an exact multiple of the sector size.
740 */
741
742 void
743 wdstart(int ctrlr)
744 {
745 register struct softc *du;
746 register struct bio *bp;
747 struct diskgeom *lp; /* XXX sic */
748 long blknum;
749 long secpertrk, secpercyl;
750 u_int lunit;
751 u_int count;
752 int ctrlr_atapi;
753
754 if (eide_quirks & Q_CMD640B) {
755 ctrlr = PRIMARY;
756 ctrlr_atapi = atapictrlr;
757 } else {
758 ctrlr_atapi = ctrlr;
759 }
760
761 if (wdtab[ctrlr].b_active == 2)
762 wdtab[ctrlr].b_active = 0;
763 if (wdtab[ctrlr].b_active)
764 return;
765 /* is there a drive for the controller to do a transfer with? */
766 bp = bioq_first(&wdtab[ctrlr].controller_queue);
767 if (bp == NULL) {
768 if (atapi_start && atapi_start (ctrlr_atapi))
769 /* mark controller active in ATAPI mode */
770 wdtab[ctrlr].b_active = 3;
771 return;
772 }
773
774 /* obtain controller and drive information */
775 du = bp->bio_dev->si_drv1;
776 lunit = du->dk_lunit;
777
778 #ifdef PC98
779 outb(0x432,(du->dk_unit)%2);
780 #endif
781
782 /* if not really a transfer, do control operations specially */
783 if (du->dk_state < OPEN) {
784 if (du->dk_state != WANTOPEN)
785 printf("wd%d: wdstart: weird dk_state %d\n",
786 du->dk_lunit, du->dk_state);
787 if (wdcontrol(bp) != 0)
788 printf("wd%d: wdstart: wdcontrol returned nonzero, state = %d\n",
789 du->dk_lunit, du->dk_state);
790 return;
791 }
792
793 /* calculate transfer details */
794 blknum = bp->bio_pblkno + du->dk_skip;
795 #ifdef WDDEBUG
796 if (du->dk_skip == 0)
797 printf("wd%d: wdstart: %s %d@%d; map ", lunit,
798 (bp->bio_cmd == BIO_READ) ? "read" : "write",
799 bp->bio_bcount, blknum);
800 else {
801 if (old_epson_note)
802 printf(" %d)%x", du->dk_skip, epson_inb(du->dk_altport);
803 else
804 printf(" %d)%x", du->dk_skip, inb(du->dk_altport);
805 }
806 #endif
807
808 lp = &du->dk_dd;
809 secpertrk = lp->d_nsectors;
810 secpercyl = lp->d_secpercyl;
811
812 if (du->dk_skip == 0)
813 du->dk_bc = bp->bio_bcount;
814
815 wdtab[ctrlr].b_active = 1; /* mark controller active */
816
817 /* if starting a multisector transfer, or doing single transfers */
818 if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
819 u_int command;
820 u_int count1;
821 long cylin, head, sector;
822
823 if (du->dk_flags & DKFL_LBA) {
824 sector = (blknum >> 0) & 0xff;
825 cylin = (blknum >> 8) & 0xffff;
826 head = ((blknum >> 24) & 0xf) | WDSD_LBA;
827 } else {
828 cylin = blknum / secpercyl;
829 head = (blknum % secpercyl) / secpertrk;
830 sector = blknum % secpertrk;
831 }
832 /*
833 * XXX this looks like an attempt to skip bad sectors
834 * on write.
835 */
836 if (wdtab[ctrlr].b_errcnt && (bp->bio_cmd == BIO_WRITE))
837 du->dk_bc += DEV_BSIZE;
838
839 count1 = howmany( du->dk_bc, DEV_BSIZE);
840
841 du->dk_flags &= ~DKFL_MULTI;
842
843 if (du->dk_flags & DKFL_SINGLE) {
844 command = (bp->bio_cmd == BIO_READ)
845 ? WDCC_READ : WDCC_WRITE;
846 count1 = 1;
847 du->dk_currentiosize = 1;
848 } else {
849 if((du->dk_flags & DKFL_USEDMA) &&
850 wddma[du->dk_interface].wdd_dmaverify(du->dk_dmacookie,
851 (void *)((int)bp->bio_data +
852 du->dk_skip * DEV_BSIZE),
853 du->dk_bc,
854 bp->bio_cmd == BIO_READ)) {
855 du->dk_flags |= DKFL_DMA;
856 if(bp->bio_cmd == BIO_READ)
857 command = WDCC_READ_DMA;
858 else
859 command = WDCC_WRITE_DMA;
860 du->dk_currentiosize = count1;
861 } else if( (count1 > 1) && (du->dk_multi > 1)) {
862 du->dk_flags |= DKFL_MULTI;
863 if(bp->bio_cmd == BIO_READ) {
864 command = WDCC_READ_MULTI;
865 } else {
866 command = WDCC_WRITE_MULTI;
867 }
868 du->dk_currentiosize = du->dk_multi;
869 if( du->dk_currentiosize > count1)
870 du->dk_currentiosize = count1;
871 } else {
872 if(bp->bio_cmd == BIO_READ) {
873 command = WDCC_READ;
874 } else {
875 command = WDCC_WRITE;
876 }
877 du->dk_currentiosize = 1;
878 }
879 }
880
881 /*
882 * XXX this loop may never terminate. The code to handle
883 * counting down of retries and eventually failing the i/o
884 * is in wdintr() and we can't get there from here.
885 */
886 if (wdtest != 0) {
887 if (--wdtest == 0) {
888 wdtest = 100;
889 printf("dummy wdunwedge\n");
890 wdunwedge(du);
891 }
892 }
893
894 if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
895 wddma[du->dk_interface].wdd_dmaprep(du->dk_dmacookie,
896 (void *)((int)bp->bio_data +
897 du->dk_skip * DEV_BSIZE),
898 du->dk_bc,
899 bp->bio_cmd == BIO_READ);
900 }
901 while (wdcommand(du, cylin, head, sector, count1, command)
902 != 0) {
903 wderror(bp, du,
904 "wdstart: timeout waiting to give command");
905 wdunwedge(du);
906 }
907 #ifdef WDDEBUG
908 printf("cylin %ld head %ld sector %ld addr %x sts ",
909 cylin, head, sector,
910 (int)bp->bio_data + du->dk_skip * DEV_BSIZE);
911 if (old_epson_note)
912 printf("%x\n", epson_inb(du->dk_altport));
913 else
914 printf("%x\n", inb(du->dk_altport));
915 #endif
916 }
917
918 /*
919 * Schedule wdtimeout() to wake up after a few seconds. Retrying
920 * unmarked bad blocks can take 3 seconds! Then it is not good that
921 * we retry 5 times.
922 *
923 * On the first try, we give it 10 seconds, for drives that may need
924 * to spin up.
925 *
926 * XXX wdtimeout() doesn't increment the error count so we may loop
927 * forever. More seriously, the loop isn't forever but causes a
928 * crash.
929 *
930 * TODO fix b_resid bug elsewhere (fd.c....). Fix short but positive
931 * counts being discarded after there is an error (in physio I
932 * think). Discarding them would be OK if the (special) file offset
933 * was not advanced.
934 */
935 if (wdtab[ctrlr].b_errcnt == 0)
936 du->dk_timeout = 1 + 10;
937 else
938 du->dk_timeout = 1 + 3;
939
940 /* if this is a DMA op, start DMA and go away until it's done. */
941 if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
942 wddma[du->dk_interface].wdd_dmastart(du->dk_dmacookie);
943 return;
944 }
945
946 /* If this is a read operation, just go away until it's done. */
947 if (bp->bio_cmd == BIO_READ)
948 return;
949
950 /* Ready to send data? */
951 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) < 0) {
952 wderror(bp, du, "wdstart: timeout waiting for DRQ");
953 /*
954 * XXX what do we do now? If we've just issued the command,
955 * then we can treat this failure the same as a command
956 * failure. But if we are continuing a multi-sector write,
957 * the command was issued ages ago, so we can't simply
958 * restart it.
959 *
960 * XXX we waste a lot of time unnecessarily translating block
961 * numbers to cylin/head/sector for continued i/o's.
962 */
963 }
964
965 count = 1;
966 if( du->dk_flags & DKFL_MULTI) {
967 count = howmany(du->dk_bc, DEV_BSIZE);
968 if( count > du->dk_multi)
969 count = du->dk_multi;
970 if( du->dk_currentiosize > count)
971 du->dk_currentiosize = count;
972 }
973 if (!old_epson_note) {
974 if (du->dk_flags & DKFL_32BIT)
975 outsl(du->dk_port + wd_data,
976 (void *)((int)bp->bio_data
977 + du->dk_skip * DEV_BSIZE),
978 (count * DEV_BSIZE) / sizeof(long));
979 else
980 outsw(du->dk_port + wd_data,
981 (void *)((int)bp->bio_data
982 + du->dk_skip * DEV_BSIZE),
983 (count * DEV_BSIZE) / sizeof(short));
984 }
985 else
986 epson_outsw(du->dk_port + wd_data,
987 (void *)((int)bp->bio_data + du->dk_skip * DEV_BSIZE),
988 (count * DEV_BSIZE) / sizeof(short));
989
990 du->dk_bc -= DEV_BSIZE * count;
991 }
992
993 /* Interrupt routine for the controller. Acknowledge the interrupt, check for
994 * errors on the current operation, mark it done if necessary, and start
995 * the next request. Also check for a partially done transfer, and
996 * continue with the next chunk if so.
997 */
998
999 void
1000 wdintr(void *unitnum)
1001 {
1002 register struct softc *du;
1003 register struct bio *bp;
1004 int dmastat = 0; /* Shut up GCC */
1005 int unit = (int)unitnum;
1006
1007 int ctrlr_atapi;
1008
1009 if (eide_quirks & Q_CMD640B) {
1010 unit = PRIMARY;
1011 ctrlr_atapi = atapictrlr;
1012 } else {
1013 ctrlr_atapi = unit;
1014 }
1015
1016 if (wdtab[unit].b_active == 2)
1017 return; /* intr in wdflushirq() */
1018 if (!wdtab[unit].b_active) {
1019 #ifdef WDDEBUG
1020 /*
1021 * These happen mostly because the power-mgt part of the
1022 * bios shuts us down, and we just manage to see the
1023 * interrupt from the "SLEEP" command.
1024 */
1025 printf("wdc%d: extra interrupt\n", unit);
1026 #endif
1027 return;
1028 }
1029 if (wdtab[unit].b_active == 3) {
1030 /* process an ATAPI interrupt */
1031 if (atapi_intr && atapi_intr (ctrlr_atapi))
1032 /* ATAPI op continues */
1033 return;
1034 /* controller is free, start new op */
1035 wdtab[unit].b_active = 0;
1036 wdstart (unit);
1037 return;
1038 }
1039 bp = bioq_first(&wdtab[unit].controller_queue);
1040 du = bp->bio_dev->si_drv1;
1041
1042 #ifdef PC98
1043 outb(0x432,(du->dk_unit)%2);
1044 #endif
1045 /* finish off DMA */
1046 if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
1047 /* XXX SMP boxes sometimes generate an early intr. Why? */
1048 if ((wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie) &
1049 WDDS_INTERRUPT) == 0)
1050 return;
1051 dmastat = wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
1052 }
1053
1054 du->dk_timeout = 0;
1055
1056 /* check drive status/failure */
1057 if (wdwait(du, 0, TIMEOUT) < 0) {
1058 wderror(bp, du, "wdintr: timeout waiting for status");
1059 du->dk_status |= WDCS_ERR; /* XXX */
1060 }
1061
1062 /* is it not a transfer, but a control operation? */
1063 if (du->dk_state < OPEN) {
1064 wdtab[unit].b_active = 0;
1065 switch (wdcontrol(bp)) {
1066 case 0:
1067 return;
1068 case 1:
1069 wdstart(unit);
1070 return;
1071 case 2:
1072 goto done;
1073 }
1074 }
1075
1076 /* have we an error? */
1077 if ((du->dk_status & (WDCS_ERR | WDCS_ECCCOR))
1078 || (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
1079 && dmastat != WDDS_INTERRUPT)) {
1080
1081 unsigned int errstat;
1082 oops:
1083 /*
1084 * XXX bogus inb() here
1085 */
1086 errstat = inb(du->dk_port + wd_error);
1087
1088 if(((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) &&
1089 (errstat & WDERR_ABORT)) {
1090 wderror(bp, du, "reverting to PIO mode");
1091 du->dk_flags &= ~DKFL_USEDMA;
1092 } else if((du->dk_flags & DKFL_MULTI) &&
1093 (errstat & WDERR_ABORT)) {
1094 wderror(bp, du, "reverting to non-multi sector mode");
1095 du->dk_multi = 1;
1096 }
1097
1098 if (!(du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) &&
1099 (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) &&
1100 (dmastat != WDDS_INTERRUPT)))
1101 printf("wd%d: DMA failure, DMA status %b\n",
1102 du->dk_lunit, dmastat, WDDS_BITS);
1103 #ifdef WDDEBUG
1104 wderror(bp, du, "wdintr");
1105 #endif
1106 if ((du->dk_flags & DKFL_SINGLE) == 0) {
1107 du->dk_flags |= DKFL_ERROR;
1108 goto outt;
1109 }
1110
1111 if (du->dk_status & WDCS_ERR) {
1112 if (++wdtab[unit].b_errcnt < RETRIES) {
1113 wdtab[unit].b_active = 0;
1114 } else {
1115 wderror(bp, du, "hard error");
1116 bp->bio_error = EIO;
1117 bp->bio_flags |= BIO_ERROR; /* flag the error */
1118 }
1119 } else if (du->dk_status & WDCS_ECCCOR)
1120 wderror(bp, du, "soft ecc");
1121 }
1122
1123 /*
1124 * If this was a successful read operation, fetch the data.
1125 */
1126 if (bp->bio_cmd == BIO_READ && !(bp->bio_flags & BIO_ERROR)
1127 && !((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
1128 && wdtab[unit].b_active) {
1129 u_int chk, dummy, multisize;
1130 multisize = chk = du->dk_currentiosize * DEV_BSIZE;
1131 if( du->dk_bc < chk) {
1132 chk = du->dk_bc;
1133 if( ((chk + DEV_BSIZE - 1) / DEV_BSIZE) < du->dk_currentiosize) {
1134 du->dk_currentiosize = (chk + DEV_BSIZE - 1) / DEV_BSIZE;
1135 multisize = du->dk_currentiosize * DEV_BSIZE;
1136 }
1137 }
1138
1139 /* ready to receive data? */
1140 if ((du->dk_status & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
1141 != (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
1142 wderror(bp, du, "wdintr: read intr arrived early");
1143 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
1144 wderror(bp, du, "wdintr: read error detected late");
1145 goto oops;
1146 }
1147
1148 /* suck in data */
1149 if( du->dk_flags & DKFL_32BIT)
1150 insl(du->dk_port + wd_data,
1151 (void *)((int)bp->bio_data + du->dk_skip * DEV_BSIZE),
1152 chk / sizeof(long));
1153 else
1154 insw(du->dk_port + wd_data,
1155 (void *)((int)bp->bio_data + du->dk_skip * DEV_BSIZE),
1156 chk / sizeof(short));
1157 du->dk_bc -= chk;
1158
1159 /* XXX for obsolete fractional sector reads. */
1160 while (chk < multisize) {
1161 insw(du->dk_port + wd_data, &dummy, 1);
1162 chk += sizeof(short);
1163 }
1164
1165 }
1166
1167 /* final cleanup on DMA */
1168 if (((bp->bio_flags & BIO_ERROR) == 0)
1169 && ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
1170 && wdtab[unit].b_active) {
1171 int iosize;
1172
1173 iosize = du->dk_currentiosize * DEV_BSIZE;
1174
1175 du->dk_bc -= iosize;
1176
1177 }
1178
1179 outt:
1180 if (wdtab[unit].b_active) {
1181 if ((bp->bio_flags & BIO_ERROR) == 0) {
1182 du->dk_skip += du->dk_currentiosize;/* add to successful sectors */
1183 if (wdtab[unit].b_errcnt)
1184 wderror(bp, du, "soft error");
1185 wdtab[unit].b_errcnt = 0;
1186
1187 /* see if more to transfer */
1188 if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
1189 if( (du->dk_flags & DKFL_SINGLE) ||
1190 (bp->bio_cmd == BIO_WRITE)) {
1191 wdtab[unit].b_active = 0;
1192 wdstart(unit);
1193 } else {
1194 du->dk_timeout = 1 + 3;
1195 }
1196 return; /* next chunk is started */
1197 } else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR))
1198 == DKFL_ERROR) {
1199 du->dk_skip = 0;
1200 du->dk_flags &= ~DKFL_ERROR;
1201 du->dk_flags |= DKFL_SINGLE;
1202 wdtab[unit].b_active = 0;
1203 wdstart(unit);
1204 return; /* redo xfer sector by sector */
1205 }
1206 }
1207
1208 done: ;
1209 /* done with this transfer, with or without error */
1210 du->dk_flags &= ~(DKFL_SINGLE|DKFL_DMA);
1211 bioq_remove( &wdtab[unit].controller_queue, bp);
1212 wdtab[unit].b_errcnt = 0;
1213 bp->bio_resid = bp->bio_bcount - du->dk_skip * DEV_BSIZE;
1214 wdutab[du->dk_lunit].b_active = 0;
1215 du->dk_skip = 0;
1216 biofinish(bp, &du->dk_stats, 0);
1217 }
1218
1219 /* controller idle */
1220 wdtab[unit].b_active = 0;
1221
1222 /* anything more on drive queue? */
1223 wdustart(du);
1224 /* anything more for controller to do? */
1225 wdstart(unit);
1226 }
1227
1228 /*
1229 * Initialize a drive.
1230 */
1231 int
1232 wdopen(dev_t dev, int flags, int fmt, struct thread *td)
1233 {
1234 register struct softc *du;
1235
1236 du = dev->si_drv1;
1237 if (du == NULL)
1238 return (ENXIO);
1239
1240 dev->si_iosize_max = 248 * 512;
1241 #ifdef PC98
1242 outb(0x432,(du->dk_unit)%2);
1243 #endif
1244
1245 /* Finish flushing IRQs left over from wdattach(). */
1246 if (wdtab[du->dk_ctrlr_cmd640].b_active == 2)
1247 wdtab[du->dk_ctrlr_cmd640].b_active = 0;
1248
1249 du->dk_flags &= ~DKFL_BADSCAN;
1250
1251 /* spin waiting for anybody else reading the disk label */
1252 while (du->dk_flags & DKFL_LABELLING)
1253 tsleep((caddr_t)&du->dk_flags, PZERO - 1, "wdopen", 1);
1254
1255 wdsleep(du->dk_ctrlr, "wdopn1");
1256 du->dk_flags |= DKFL_LABELLING;
1257 du->dk_state = WANTOPEN;
1258
1259 du->disk.d_sectorsize = du->dk_dd.d_secsize;
1260 du->disk.d_mediasize = du->dk_dd.d_secperunit * du->dk_dd.d_secsize;
1261 du->disk.d_fwsectors = du->dk_dd.d_nsectors;
1262 du->disk.d_fwheads = du->dk_dd.d_ntracks;
1263
1264 du->dk_flags &= ~DKFL_LABELLING;
1265 wdsleep(du->dk_ctrlr, "wdopn2");
1266
1267 return 0;
1268 }
1269
1270 /*
1271 * Implement operations other than read/write.
1272 * Called from wdstart or wdintr during opens.
1273 * Uses finite-state-machine to track progress of operation in progress.
1274 * Returns 0 if operation still in progress, 1 if completed, 2 if error.
1275 */
1276 static int
1277 wdcontrol(register struct bio *bp)
1278 {
1279 register struct softc *du;
1280 int ctrlr;
1281
1282 du = bp->bio_dev->si_drv1;
1283 ctrlr = du->dk_ctrlr_cmd640;
1284
1285 #ifdef PC98
1286 outb(0x432,(du->dk_unit)%2);
1287 #endif
1288
1289 switch (du->dk_state) {
1290 case WANTOPEN:
1291 tryagainrecal:
1292 wdtab[ctrlr].b_active = 1;
1293 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) {
1294 wderror(bp, du, "wdcontrol: wdcommand failed");
1295 goto maybe_retry;
1296 }
1297 du->dk_state = RECAL;
1298 return (0);
1299 case RECAL:
1300 if (du->dk_status & WDCS_ERR || wdsetctlr(du) != 0) {
1301 wderror(bp, du, "wdcontrol: recal failed");
1302 maybe_retry:
1303 if (du->dk_status & WDCS_ERR)
1304 wdunwedge(du);
1305 du->dk_state = WANTOPEN;
1306 if (++wdtab[ctrlr].b_errcnt < RETRIES)
1307 goto tryagainrecal;
1308 bp->bio_error = ENXIO; /* XXX needs translation */
1309 bp->bio_flags |= BIO_ERROR;
1310 return (2);
1311 }
1312 wdtab[ctrlr].b_errcnt = 0;
1313 du->dk_state = OPEN;
1314 /*
1315 * The rest of the initialization can be done by normal
1316 * means.
1317 */
1318 return (1);
1319 }
1320 panic("wdcontrol");
1321 return (2);
1322 }
1323
1324 /*
1325 * Wait uninterruptibly until controller is not busy, then send it a command.
1326 * The wait usually terminates immediately because we waited for the previous
1327 * command to terminate.
1328 */
1329 static int
1330 wdcommand(struct softc *du, u_int cylinder, u_int head, u_int sector,
1331 u_int count, u_int command)
1332 {
1333 u_int wdc;
1334 #ifdef PC98
1335 unsigned char u_addr;
1336 #endif
1337
1338 wdc = du->dk_port;
1339 if (du->cfg_flags & WDOPT_SLEEPHACK) {
1340 /* OK, so the APM bios has put the disk into SLEEP mode,
1341 * how can we tell ? Uhm, we can't. There is no
1342 * standardized way of finding out, and the only way to
1343 * wake it up is to reset it. Bummer.
1344 *
1345 * All the many and varied versions of the IDE/ATA standard
1346 * explicitly tells us not to look at these registers if
1347 * the disk is in SLEEP mode. Well, too bad really, we
1348 * have to find out if it's in sleep mode before we can
1349 * avoid reading the registers.
1350 *
1351 * I have reason to belive that most disks will return
1352 * either 0xff or 0x00 in all but the status register
1353 * when in SLEEP mode, but I have yet to see one return
1354 * 0x00, so we don't check for that yet.
1355 *
1356 * The check for WDCS_BUSY is for the case where the
1357 * bios spins up the disk for us, but doesn't initialize
1358 * it correctly /phk
1359 */
1360 if (old_epson_note) {
1361 if(epson_inb(wdc + wd_precomp) + epson_inb(wdc + wd_cyl_lo) +
1362 epson_inb(wdc + wd_cyl_hi) + epson_inb(wdc + wd_sdh) +
1363 epson_inb(wdc + wd_sector) +
1364 epson_inb(wdc + wd_seccnt) == 6 * 0xff) {
1365 if (bootverbose)
1366 printf("wd(%d,%d): disk aSLEEP\n",
1367 du->dk_ctrlr, du->dk_unit);
1368 wdunwedge(du);
1369 } else if(epson_inb(wdc + wd_status) == WDCS_BUSY) {
1370 if (bootverbose)
1371 printf("wd(%d,%d): disk is BUSY\n",
1372 du->dk_ctrlr, du->dk_unit);
1373 wdunwedge(du);
1374 }
1375 } else {
1376 if(inb(wdc + wd_precomp) + inb(wdc + wd_cyl_lo) +
1377 inb(wdc + wd_cyl_hi) + inb(wdc + wd_sdh) +
1378 inb(wdc + wd_sector) + inb(wdc + wd_seccnt) == 6 * 0xff) {
1379 if (bootverbose)
1380 printf("wd(%d,%d): disk aSLEEP\n",
1381 du->dk_ctrlr, du->dk_unit);
1382 wdunwedge(du);
1383 } else if(inb(wdc + wd_status) == WDCS_BUSY) {
1384 if (bootverbose)
1385 printf("wd(%d,%d): disk is BUSY\n",
1386 du->dk_ctrlr, du->dk_unit);
1387 wdunwedge(du);
1388 }
1389 }
1390 }
1391
1392 if (wdwait(du, 0, TIMEOUT) < 0)
1393 return (1);
1394 #ifdef PC98
1395 /* u_addr = (du->dk_unit & 0xfe); */
1396 u_addr = ((du->dk_unit)/2)<<4;
1397 #endif /* PC98 */
1398 if( command == WDCC_FEATURES) {
1399 if (old_epson_note)
1400 epson_outb(wdc + wd_features, count);
1401 else {
1402 outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
1403 outb(wdc + wd_features, count);
1404 if ( count == WDFEA_SETXFER )
1405 outb(wdc + wd_seccnt, sector);
1406 }
1407 } else {
1408 if (old_epson_note) {
1409 epson_outb(wdc + wd_precomp, du->dk_dd.d_precompcyl/4);
1410 epson_outb(wdc + wd_cyl_lo, cylinder);
1411 epson_outb(wdc + wd_cyl_hi, cylinder >> 8);
1412 epson_outb(wdc + wd_sdh, WDSD_IBM | u_addr | head);
1413 epson_outb(wdc + wd_sector, sector + 1);
1414 epson_outb(wdc + wd_seccnt, count);
1415 }
1416 else {
1417 outb(wdc + wd_precomp, du->dk_dd.d_precompcyl / 4);
1418 outb(wdc + wd_cyl_lo, cylinder);
1419 outb(wdc + wd_cyl_hi, cylinder >> 8);
1420 #ifdef PC98
1421 outb(wdc + wd_sdh, WDSD_IBM | u_addr | head);
1422 #else
1423 outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit<<4) | head);
1424 #endif
1425 if (head & WDSD_LBA)
1426 outb(wdc + wd_sector, sector);
1427 else
1428 outb(wdc + wd_sector, sector + 1);
1429 outb(wdc + wd_seccnt, count);
1430 }
1431 }
1432 if (wdwait(du, (command == WDCC_DIAGNOSE || command == WDCC_IDC)
1433 ? 0 : WDCS_READY, TIMEOUT) < 0)
1434 return (1);
1435 if (old_epson_note)
1436 epson_outb(wdc + wd_command, command);
1437 else
1438 outb(wdc + wd_command, command);
1439 return (0);
1440 }
1441
1442 static void
1443 wdsetmulti(struct softc *du)
1444 {
1445 /*
1446 * The config option flags low 8 bits define the maximum multi-block
1447 * transfer size. If the user wants the maximum that the drive
1448 * is capable of, just set the low bits of the config option to
1449 * 0x00ff.
1450 */
1451 if ((du->cfg_flags & WDOPT_MULTIMASK) != 0 && (du->dk_multi > 1)) {
1452 int configval = du->cfg_flags & WDOPT_MULTIMASK;
1453 du->dk_multi = min(du->dk_multi, configval);
1454 if (wdcommand(du, 0, 0, 0, du->dk_multi, WDCC_SET_MULTI)) {
1455 du->dk_multi = 1;
1456 } else {
1457 if (wdwait(du, WDCS_READY, TIMEOUT) < 0) {
1458 du->dk_multi = 1;
1459 }
1460 }
1461 } else {
1462 du->dk_multi = 1;
1463 }
1464 }
1465
1466 /*
1467 * issue IDC to drive to tell it just what geometry it is to be.
1468 */
1469 static int
1470 wdsetctlr(struct softc *du)
1471 {
1472 int error = 0;
1473 #ifdef PC98
1474 outb(0x432,(du->dk_unit)%2);
1475 #endif
1476 #ifdef WDDEBUG
1477 printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
1478 du->dk_ctrlr, du->dk_unit,
1479 du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
1480 du->dk_dd.d_nsectors);
1481 #endif
1482 if (!(du->dk_flags & DKFL_LBA)) {
1483 if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
1484 struct wdparams *wp;
1485
1486 printf("wd%d: can't handle %lu heads from partition table ",
1487 du->dk_lunit, du->dk_dd.d_ntracks);
1488 /* obtain parameters */
1489 wp = &du->dk_params;
1490 if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
1491 printf("(controller value %u restored)\n",
1492 wp->wdp_heads);
1493 du->dk_dd.d_ntracks = wp->wdp_heads;
1494 }
1495 else {
1496 printf("(truncating to 16)\n");
1497 du->dk_dd.d_ntracks = 16;
1498 }
1499 }
1500
1501 if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
1502 printf("wd%d: cannot handle %lu sectors (max 255)\n",
1503 du->dk_lunit, du->dk_dd.d_nsectors);
1504 error = 1;
1505 }
1506 if (error) {
1507 wdtab[du->dk_ctrlr_cmd640].b_errcnt += RETRIES;
1508 return (1);
1509 }
1510 if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
1511 du->dk_dd.d_nsectors, WDCC_IDC) != 0
1512 || wdwait(du, WDCS_READY, TIMEOUT) < 0) {
1513 wderror((struct bio *)NULL, du, "wdsetctlr failed");
1514 return (1);
1515 }
1516 }
1517
1518 wdsetmulti(du);
1519
1520 #ifdef NOTYET
1521 /* set read caching and write caching */
1522 wdcommand(du, 0, 0, 0, WDFEA_RCACHE, WDCC_FEATURES);
1523 wdwait(du, WDCS_READY, TIMEOUT);
1524
1525 wdcommand(du, 0, 0, 0, WDFEA_WCACHE, WDCC_FEATURES);
1526 wdwait(du, WDCS_READY, TIMEOUT);
1527 #endif
1528
1529 return (0);
1530 }
1531
1532 #if 0
1533 /*
1534 * Wait until driver is inactive, then set up controller.
1535 */
1536 static int
1537 wdwsetctlr(struct softc *du)
1538 {
1539 int stat;
1540 int x;
1541
1542 wdsleep(du->dk_ctrlr, "wdwset");
1543 x = splbio();
1544 stat = wdsetctlr(du);
1545 wdflushirq(du, x);
1546 splx(x);
1547 return (stat);
1548 }
1549 #endif
1550
1551 /*
1552 * gross little callback function for wdddma interface. returns 1 for
1553 * success, 0 for failure.
1554 */
1555 static int
1556 wdsetmode(int mode, void *wdinfo)
1557 {
1558 int i;
1559 struct softc *du;
1560
1561 du = wdinfo;
1562 if (bootverbose)
1563 printf("wd%d: wdsetmode() setting transfer mode to %02x\n",
1564 du->dk_lunit, mode);
1565 i = wdcommand(du, 0, 0, mode, WDFEA_SETXFER,
1566 WDCC_FEATURES) == 0 &&
1567 wdwait(du, WDCS_READY, TIMEOUT) == 0;
1568 return i;
1569 }
1570
1571 /*
1572 * issue READP to drive to ask it what it is.
1573 */
1574 static int
1575 wdgetctlr(struct softc *du)
1576 {
1577 int i;
1578 char tb[DEV_BSIZE], tb2[DEV_BSIZE];
1579 struct wdparams *wp = NULL;
1580 u_long flags = du->cfg_flags;
1581 #ifdef PC98
1582 outb(0x432,(du->dk_unit)%2);
1583 #endif
1584
1585 again:
1586 if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0
1587 || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
1588
1589 #ifdef PC98
1590 if ( du->dk_unit > 1 )
1591 return(1);
1592 #endif
1593 /*
1594 * if we failed on the second try, assume non-32bit
1595 */
1596 if( du->dk_flags & DKFL_32BIT)
1597 goto failed;
1598
1599 /* XXX need to check error status after final transfer. */
1600 /*
1601 * Old drives don't support WDCC_READP. Try a seek to 0.
1602 * Some IDE controllers return trash if there is no drive
1603 * attached, so first test that the drive can be selected.
1604 * This also avoids long waits for nonexistent drives.
1605 */
1606 if (wdwait(du, 0, TIMEOUT) < 0)
1607 return (1);
1608 if (old_epson_note) {
1609 epson_outb(du->dk_port + wd_sdh,
1610 WDSD_IBM | (du->dk_unit << 4));
1611 DELAY(5000); /* usually unnecessary; drive select is fast */
1612 if ((epson_inb(du->dk_port + wd_status)
1613 & (WDCS_BUSY | WDCS_READY))
1614 != WDCS_READY
1615 || wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
1616 || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
1617 return (1);
1618 }
1619 else {
1620 outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
1621 DELAY(5000); /* usually unnecessary; drive select is fast */
1622 /*
1623 * Do this twice: may get a false WDCS_READY the first time.
1624 */
1625 inb(du->dk_port + wd_status);
1626 if ((inb(du->dk_port + wd_status) & (WDCS_BUSY | WDCS_READY))
1627 != WDCS_READY
1628 || wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
1629 || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
1630 return (1);
1631 }
1632 if (du->dk_unit == bootinfo.bi_n_bios_used) {
1633 du->dk_dd.d_secsize = DEV_BSIZE;
1634 du->dk_dd.d_nsectors =
1635 bootinfo.bi_bios_geom[du->dk_unit] & 0xff;
1636 du->dk_dd.d_ntracks =
1637 ((bootinfo.bi_bios_geom[du->dk_unit] >> 8) & 0xff)
1638 + 1;
1639 /* XXX Why 2 ? */
1640 du->dk_dd.d_ncylinders =
1641 (bootinfo.bi_bios_geom[du->dk_unit] >> 16) + 2;
1642 du->dk_dd.d_secpercyl =
1643 du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1644 du->dk_dd.d_secperunit =
1645 du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
1646 #if 0
1647 du->dk_dd.d_partitions[WDRAW].p_size =
1648 du->dk_dd.d_secperunit;
1649 du->dk_dd.d_type = DTYPE_ST506;
1650 du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1651 strncpy(du->dk_dd.d_typename, "Bios geometry",
1652 sizeof du->dk_dd.d_typename);
1653 strncpy(du->dk_params.wdp_model, "ST506",
1654 sizeof du->dk_params.wdp_model);
1655 #endif
1656 bootinfo.bi_n_bios_used ++;
1657 return 0;
1658 }
1659 /*
1660 * Fake minimal drive geometry for reading the MBR.
1661 * readdisklabel() may enlarge it to read the label and the
1662 * bad sector table.
1663 */
1664 du->dk_dd.d_secsize = DEV_BSIZE;
1665 du->dk_dd.d_nsectors = 17;
1666 du->dk_dd.d_ntracks = 1;
1667 du->dk_dd.d_ncylinders = 1;
1668 du->dk_dd.d_secpercyl = 17;
1669 du->dk_dd.d_secperunit = 17;
1670
1671 #if 0
1672 /*
1673 * Fake maximal drive size for writing the label.
1674 */
1675 du->dk_dd.d_partitions[RAW_PART].p_size = 64 * 16 * 1024;
1676
1677 /*
1678 * Fake some more of the label for printing by disklabel(1)
1679 * in case there is no real label.
1680 */
1681 du->dk_dd.d_type = DTYPE_ST506;
1682 du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1683 strncpy(du->dk_dd.d_typename, "Fake geometry",
1684 sizeof du->dk_dd.d_typename);
1685 #endif
1686
1687 /* Fake the model name for printing by wdattach(). */
1688 strncpy(du->dk_params.wdp_model, "unknown",
1689 sizeof du->dk_params.wdp_model);
1690
1691 return (0);
1692 }
1693
1694 /* obtain parameters */
1695 wp = &du->dk_params;
1696 if (!old_epson_note) {
1697 if (du->dk_flags & DKFL_32BIT)
1698 insl(du->dk_port + wd_data, tb,
1699 sizeof(tb) / sizeof(long));
1700 else
1701 insw(du->dk_port + wd_data, tb,
1702 sizeof(tb) / sizeof(short));
1703 }
1704 else
1705 epson_insw(du->dk_port + wd_data, tb,
1706 sizeof(tb) / sizeof(short));
1707
1708 /* try 32-bit data path (VLB IDE controller) */
1709 if (flags & WDOPT_32BIT) {
1710 if (! (du->dk_flags & DKFL_32BIT)) {
1711 bcopy(tb, tb2, sizeof(struct wdparams));
1712 du->dk_flags |= DKFL_32BIT;
1713 goto again;
1714 }
1715
1716 /* check that we really have 32-bit controller */
1717 if (bcmp (tb, tb2, sizeof(struct wdparams)) != 0) {
1718 failed:
1719 /* test failed, use 16-bit i/o mode */
1720 bcopy(tb2, tb, sizeof(struct wdparams));
1721 du->dk_flags &= ~DKFL_32BIT;
1722 }
1723 }
1724
1725 bcopy(tb, wp, sizeof(struct wdparams));
1726
1727 /* shuffle string byte order */
1728 for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i += 2) {
1729 u_short *p;
1730
1731 p = (u_short *) (wp->wdp_model + i);
1732 *p = ntohs(*p);
1733 }
1734 /*
1735 * Clean up the wdp_model by converting nulls to spaces, and
1736 * then removing the trailing spaces.
1737 */
1738 for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i++) {
1739 if (wp->wdp_model[i] == '\0') {
1740 wp->wdp_model[i] = ' ';
1741 }
1742 }
1743 for (i = sizeof(wp->wdp_model) - 1;
1744 (i >= 0 && wp->wdp_model[i] == ' '); i--) {
1745 wp->wdp_model[i] = '\0';
1746 }
1747
1748 /*
1749 * find out the drives maximum multi-block transfer capability
1750 */
1751 du->dk_multi = wp->wdp_nsecperint & 0xff;
1752 wdsetmulti(du);
1753
1754 /*
1755 * check drive's DMA capability
1756 */
1757 if (wddma[du->dk_interface].wdd_candma) {
1758 du->dk_dmacookie = wddma[du->dk_interface].wdd_candma(
1759 du->dk_port, du->dk_ctrlr, du->dk_unit);
1760 /* does user want this? */
1761 if ((du->cfg_flags & WDOPT_DMA) &&
1762 /* have we got a DMA controller? */
1763 du->dk_dmacookie &&
1764 /* can said drive do DMA? */
1765 wddma[du->dk_interface].wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)) {
1766 du->dk_flags |= DKFL_USEDMA;
1767 }
1768 } else {
1769 du->dk_dmacookie = NULL;
1770 }
1771
1772 #ifdef WDDEBUG
1773 printf(
1774 "\nwd(%d,%d): wdgetctlr: gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
1775 du->dk_ctrlr, du->dk_unit, wp->wdp_config, wp->wdp_cylinders,
1776 wp->wdp_heads, wp->wdp_sectors, wp->wdp_buffertype,
1777 wp->wdp_buffersize, wp->wdp_model);
1778 #endif
1779 #ifdef PC98
1780 /* for larger than 40MB */
1781 {
1782 long cyl = wp->wdp_cylinders * wp->wdp_heads * wp->wdp_sectors;
1783
1784 if ( du->dk_unit > 1 ) {
1785 wp->wdp_sectors = 17;
1786 wp->wdp_heads = 8;
1787 } else {
1788 wp->wdp_sectors = bootinfo.bi_bios_geom[du->dk_unit] & 0xff;
1789 wp->wdp_heads = (bootinfo.bi_bios_geom[du->dk_unit] >> 8) & 0xff;
1790 }
1791
1792 wp->wdp_cylinders = cyl / (wp->wdp_heads * wp->wdp_sectors);
1793 }
1794 #endif
1795
1796 /* update disklabel given drive information */
1797 du->dk_dd.d_secsize = DEV_BSIZE;
1798 if ((du->cfg_flags & WDOPT_LBA) && wp->wdp_lbasize) {
1799 du->dk_dd.d_nsectors = 63;
1800 if (wp->wdp_lbasize < 16*63*1024) { /* <=528.4 MB */
1801 du->dk_dd.d_ntracks = 16;
1802 }
1803 else if (wp->wdp_lbasize < 32*63*1024) { /* <=1.057 GB */
1804 du->dk_dd.d_ntracks = 32;
1805 }
1806 else if (wp->wdp_lbasize < 64*63*1024) { /* <=2.114 GB */
1807 du->dk_dd.d_ntracks = 64;
1808 }
1809 else if (wp->wdp_lbasize < 128*63*1024) { /* <=4.228 GB */
1810 du->dk_dd.d_ntracks = 128;
1811 }
1812 else if (wp->wdp_lbasize < 255*63*1024) { /* <=8.422 GB */
1813 du->dk_dd.d_ntracks = 255;
1814 }
1815 else { /* >8.422 GB */
1816 du->dk_dd.d_ntracks = 255; /* XXX */
1817 }
1818 du->dk_dd.d_secpercyl= du->dk_dd.d_ntracks*du->dk_dd.d_nsectors;
1819 du->dk_dd.d_ncylinders = wp->wdp_lbasize/du->dk_dd.d_secpercyl;
1820 du->dk_dd.d_secperunit = wp->wdp_lbasize;
1821 du->dk_flags |= DKFL_LBA;
1822 }
1823 else {
1824 du->dk_dd.d_ncylinders = wp->wdp_cylinders; /* +- 1 */
1825 du->dk_dd.d_ntracks = wp->wdp_heads;
1826 du->dk_dd.d_nsectors = wp->wdp_sectors;
1827 du->dk_dd.d_secpercyl =
1828 du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1829 du->dk_dd.d_secperunit =
1830 du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
1831 if (wp->wdp_cylinders == 16383 &&
1832 du->dk_dd.d_secperunit < wp->wdp_lbasize) {
1833 du->dk_dd.d_secperunit = wp->wdp_lbasize;
1834 du->dk_dd.d_ncylinders =
1835 du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
1836 }
1837 }
1838 if (WDOPT_FORCEHD(du->cfg_flags)) {
1839 du->dk_dd.d_ntracks = WDOPT_FORCEHD(du->cfg_flags);
1840 du->dk_dd.d_secpercyl =
1841 du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1842 du->dk_dd.d_ncylinders =
1843 du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
1844 }
1845 if (du->dk_dd.d_ncylinders > 0x10000 && !(du->cfg_flags & WDOPT_LBA)) {
1846 du->dk_dd.d_ncylinders = 0x10000;
1847 du->dk_dd.d_secperunit = du->dk_dd.d_secpercyl *
1848 du->dk_dd.d_ncylinders;
1849 printf(
1850 "wd%d: cannot handle %d total sectors; truncating to %lu\n",
1851 du->dk_lunit, wp->wdp_lbasize, du->dk_dd.d_secperunit);
1852 }
1853 #if 0
1854 du->dk_dd.d_partitions[RAW_PART].p_size = du->dk_dd.d_secperunit;
1855 /* dubious ... */
1856 bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
1857 bcopy(wp->wdp_model + 20, du->dk_dd.d_packname, 14 - 1);
1858 /* better ... */
1859 du->dk_dd.d_type = DTYPE_ESDI;
1860 du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1861 #endif
1862
1863 return (0);
1864 }
1865
1866 static void
1867 wderror(struct bio *bp, struct softc *du, char *mesg)
1868 {
1869 if (bp == NULL)
1870 printf("wd%d: %s", du->dk_lunit, mesg);
1871 else
1872 disk_err(bp, mesg, du->dk_skip, 0);
1873 printf(" (status %b error %b)\n",
1874 du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS);
1875 }
1876
1877 /*
1878 * Discard any interrupts that were latched by the interrupt system while
1879 * we were doing polled i/o.
1880 */
1881 static void
1882 wdflushirq(struct softc *du, int old_ipl)
1883 {
1884 wdtab[du->dk_ctrlr_cmd640].b_active = 2;
1885 splx(old_ipl);
1886 (void)splbio();
1887 wdtab[du->dk_ctrlr_cmd640].b_active = 0;
1888 }
1889
1890 /*
1891 * Reset the controller.
1892 */
1893 static int
1894 wdreset(struct softc *du)
1895 {
1896 int err = 0;
1897
1898 #ifdef PC98
1899 outb(0x432,(du->dk_unit)%2);
1900 #endif
1901 if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
1902 wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
1903 (void)wdwait(du, 0, TIMEOUT);
1904 #ifdef PC98
1905 if (old_epson_note) {
1906 epson_outb(du->dk_altport, WDCTL_IDS | WDCTL_RST);
1907 DELAY(10 * 1000);
1908 epson_outb(du->dk_altport, WDCTL_IDS);
1909 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
1910 || (du->dk_error = epson_errorf(du->dk_port + wd_error)) != 0x01)
1911 return (1);
1912 epson_outb(du->dk_altport, WDCTL_4BIT);
1913 err = 0;
1914 }
1915 else {
1916 #endif
1917 outb(du->dk_altport, WDCTL_IDS | WDCTL_RST);
1918 DELAY(10 * 1000);
1919 outb(du->dk_altport, WDCTL_IDS);
1920 outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
1921 if (wdwait(du, 0, TIMEOUT) != 0)
1922 err = 1; /* no IDE drive found */
1923 du->dk_error = inb(du->dk_port + wd_error);
1924 if (du->dk_error != 0x01)
1925 err = 1; /* the drive is incompatible */
1926 outb(du->dk_altport, WDCTL_4BIT);
1927 #ifdef PC98
1928 }
1929 #endif
1930 return (err);
1931 }
1932
1933 /*
1934 * Sleep until driver is inactive.
1935 * This is used only for avoiding rare race conditions, so it is unimportant
1936 * that the sleep may be far too short or too long.
1937 */
1938 static void
1939 wdsleep(int ctrlr, char *wmesg)
1940 {
1941 int s = splbio();
1942 if (eide_quirks & Q_CMD640B)
1943 ctrlr = PRIMARY;
1944 while (wdtab[ctrlr].b_active)
1945 tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1);
1946 splx(s);
1947 }
1948
1949 static void
1950 wdtimeout(void *cdu)
1951 {
1952 struct softc *du;
1953 int x;
1954 static int timeouts;
1955
1956 du = (struct softc *)cdu;
1957 x = splbio();
1958 #ifdef PC98
1959 outb(0x432,(du->dk_unit)%2);
1960 #endif
1961 if (du->dk_timeout != 0 && --du->dk_timeout == 0) {
1962 if(timeouts++ <= 5) {
1963 char *msg;
1964
1965 msg = (timeouts > 5) ?
1966 "Last time I say: interrupt timeout. Probably a portable PC." :
1967 "interrupt timeout";
1968 wderror((struct bio *)NULL, du, msg);
1969 if (du->dk_dmacookie)
1970 printf("wd%d: wdtimeout() DMA status %b\n",
1971 du->dk_lunit,
1972 wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie),
1973 WDDS_BITS);
1974 }
1975 wdunwedge(du);
1976 wdflushirq(du, x);
1977 du->dk_skip = 0;
1978 du->dk_flags |= DKFL_SINGLE;
1979 wdstart(du->dk_ctrlr);
1980 }
1981 timeout(wdtimeout, cdu, hz);
1982 splx(x);
1983 }
1984
1985 /*
1986 * Reset the controller after it has become wedged. This is different from
1987 * wdreset() so that wdreset() can be used in the probe and so that this
1988 * can restore the geometry .
1989 */
1990 static int
1991 wdunwedge(struct softc *du)
1992 {
1993 struct softc *du1;
1994 int lunit;
1995
1996 #ifdef PC98
1997 outb(0x432,(du->dk_unit)%2);
1998 #endif
1999
2000 /* Schedule other drives for recalibration. */
2001 for (lunit = 0; lunit < NWD; lunit++)
2002 if ((du1 = wddrives[lunit]) != NULL && du1 != du
2003 && du1->dk_ctrlr == du->dk_ctrlr
2004 && du1->dk_state > WANTOPEN)
2005 du1->dk_state = WANTOPEN;
2006
2007 DELAY(RECOVERYTIME);
2008 if (wdreset(du) == 0) {
2009 /*
2010 * XXX - recalibrate current drive now because some callers
2011 * aren't prepared to have its state change.
2012 */
2013 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) == 0
2014 && wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) == 0
2015 && wdsetctlr(du) == 0)
2016 return (0);
2017 }
2018 wderror((struct bio *)NULL, du, "wdunwedge failed");
2019 return (1);
2020 }
2021
2022 /*
2023 * Wait uninterruptibly until controller is not busy and either certain
2024 * status bits are set or an error has occurred.
2025 * The wait is usually short unless it is for the controller to process
2026 * an entire critical command.
2027 * Return 1 for (possibly stale) controller errors, -1 for timeout errors,
2028 * or 0 for no errors.
2029 * Return controller status in du->dk_status and, if there was a controller
2030 * error, return the error code in du->dk_error.
2031 */
2032 #ifdef WD_COUNT_RETRIES
2033 static int min_retries[NWDC];
2034 #endif
2035
2036 static int
2037 wdwait(struct softc *du, u_char bits_wanted, int timeout)
2038 {
2039 int wdc;
2040 u_char status;
2041
2042 #define POLLING 1000
2043
2044 wdc = du->dk_port;
2045 timeout += POLLING;
2046
2047 /*
2048 * This delay is really too long, but does not impact the performance
2049 * as much when using the multi-sector option. Shorter delays have
2050 * caused I/O errors on some drives and system configs. This should
2051 * probably be fixed if we develop a better short term delay mechanism.
2052 */
2053 DELAY(1);
2054
2055 do {
2056 #ifdef WD_COUNT_RETRIES
2057 if (min_retries[du->dk_ctrlr] > timeout
2058 || min_retries[du->dk_ctrlr] == 0)
2059 min_retries[du->dk_ctrlr] = timeout;
2060 #endif
2061 #ifdef PC98
2062 if (old_epson_note)
2063 du->dk_status = status = epson_inb(wdc + wd_status);
2064 else
2065 du->dk_status = status = inb(wdc + wd_status);
2066 #else
2067 du->dk_status = status = inb(wdc + wd_status);
2068 #endif
2069 /*
2070 * Atapi drives have a very interesting feature, when attached
2071 * as a slave on the IDE bus, and there is no master.
2072 * They release the bus after getting the command.
2073 * We should reselect the drive here to get the status.
2074 */
2075 if (status == 0xff) {
2076 outb(wdc + wd_sdh, WDSD_IBM | du->dk_unit << 4);
2077 du->dk_status = status = inb(wdc + wd_status);
2078 }
2079 if (!(status & WDCS_BUSY)) {
2080 if (status & WDCS_ERR) {
2081 if (old_epson_note)
2082 du->dk_error = epson_errorf(wdc + wd_error);
2083 else
2084 du->dk_error = inb(wdc + wd_error);
2085 /*
2086 * We once returned here. This is wrong
2087 * because the error bit is apparently only
2088 * valid after the controller has interrupted
2089 * (e.g., the error bit is stale when we wait
2090 * for DRQ for writes). So we can't depend
2091 * on the error bit at all when polling for
2092 * command completion.
2093 */
2094 }
2095 if ((status & bits_wanted) == bits_wanted) {
2096 return (status & WDCS_ERR);
2097 }
2098 }
2099 if (timeout < TIMEOUT)
2100 /*
2101 * Switch to a polling rate of about 1 KHz so that
2102 * the timeout is almost machine-independent. The
2103 * controller is taking a long time to respond, so
2104 * an extra msec won't matter.
2105 */
2106 DELAY(1000);
2107 else
2108 DELAY(1);
2109 } while (--timeout != 0);
2110 return (-1);
2111 }
2112
2113 #endif /* NWDC > 0 */
Cache object: 080c34862d9d3ca83dfc6d0d2bebff25
|