wd.c revision 1.78 1 /*
2 * Copyright (c) 1994 Charles Hannum.
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * William Jolitz.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * from: @(#)wd.c 7.2 (Berkeley) 5/9/91
38 * $Id: wd.c,v 1.78 1994/04/20 07:23:54 mycroft Exp $
39 */
40
41 #define INSTRUMENT /* instrumentation stuff by Brad Parker */
42
43 #include <sys/param.h>
44 #include <sys/dkbad.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/conf.h>
48 #include <sys/file.h>
49 #include <sys/stat.h>
50 #include <sys/ioctl.h>
51 #include <sys/disklabel.h>
52 #include <sys/buf.h>
53 #include <sys/uio.h>
54 #include <sys/malloc.h>
55 #include <sys/device.h>
56 #include <sys/syslog.h>
57 #ifdef INSTRUMENT
58 #include <sys/dkstat.h>
59 #endif
60
61 #include <vm/vm.h>
62
63 #include <machine/cpu.h>
64 #include <machine/cpufunc.h>
65 #include <machine/pio.h>
66
67 #include <i386/isa/isa.h>
68 #ifndef NEWCONFIG
69 #include <i386/isa/isa_device.h>
70 #endif
71 #include <i386/isa/isavar.h>
72 #include <i386/isa/icu.h>
73 #include <i386/isa/wdreg.h>
74
75 #define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */
76 #define WDCDELAY 100
77 #define RECOVERYTIME hz/2 /* time to recover from an error */
78
79 #if 0
80 /* If you enable this, it will report any delays more than 100us * N long. */
81 #define WDCNDELAY_DEBUG 10
82 #endif
83
84 #define WDIORETRIES 5 /* number of retries before giving up */
85
86 #define WDUNIT(dev) ((minor(dev) & 0xf8) >> 3)
87 #define WDPART(dev) ((minor(dev) & 0x07) )
88 #define makewddev(maj, unit, part) (makedev(maj, ((unit << 3) + part)))
89 #define WDRAW 3 /* 'd' partition isn't a partition! */
90
91 #define b_cylin b_resid /* cylinder number for doing IO to */
92 /* shares an entry in the buf struct */
93
94 /*
95 * Drive states. Used to initialize drive.
96 */
97 #define CLOSED 0 /* disk is closed */
98 #define RECAL 1 /* recalibrate */
99 #define RECAL_WAIT 2 /* done recalibrating */
100 #define GEOMETRY 3 /* upload geometry */
101 #define GEOMETRY_WAIT 4 /* done uploading geometry */
102 #define OPEN 5 /* done with open */
103
104 /*
105 * Drive status.
106 */
107 struct wd_softc {
108 struct device sc_dev;
109
110 long sc_bcount; /* byte count left */
111 long sc_mbcount; /* total byte count left */
112 short sc_skip; /* blocks already transferred */
113 short sc_mskip; /* blocks already transferred for multi */
114 char sc_drive; /* physical unit number */
115 char sc_state; /* control state */
116
117 u_long sc_copenpart; /* character units open on this drive */
118 u_long sc_bopenpart; /* block units open on this drive */
119 u_long sc_openpart; /* all units open on this drive */
120 short sc_wlabel; /* label writable? */
121 short sc_flags; /* drive characteistics found */
122 #define WDF_BSDLABEL 0x00010 /* has a BSD disk label */
123 #define WDF_BADSECT 0x00020 /* has a bad144 badsector table */
124 #define WDF_WRITEPROT 0x00040 /* manual unit write protect */
125 TAILQ_ENTRY(wd_softc) sc_drivechain;
126 struct buf sc_q;
127 struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
128 struct disklabel sc_label; /* device configuration data */
129 struct cpu_disklabel sc_cpulabel;
130 long sc_badsect[127]; /* 126 plus trailing -1 marker */
131 };
132
133 struct wdc_softc {
134 struct device sc_dev;
135 struct intrhand sc_ih;
136
137 u_char sc_flags;
138 #define WDCF_ACTIVE 0x00001 /* controller is active */
139 #define WDCF_SINGLE 0x00004 /* sector at a time mode */
140 #define WDCF_ERROR 0x00008 /* processing a disk error */
141 u_char sc_status; /* copy of status register */
142 u_char sc_error; /* copy of error register */
143 u_short sc_iobase; /* i/o port base */
144 int sc_timeout; /* timeout counter */
145 int sc_errors; /* count of errors during current transfer */
146 TAILQ_HEAD(drivehead, wd_softc) sc_drives;
147 };
148
149 int wdcprobe(), wdprobe(), wdcintr();
150 void wdcattach(), wdattach();
151
152 struct cfdriver wdccd = {
153 NULL, "wdc", wdcprobe, wdcattach, DV_DULL, sizeof(struct wd_softc)
154 };
155
156 struct cfdriver wdcd = {
157 NULL, "wd", wdprobe, wdattach, DV_DISK, sizeof(struct wd_softc)
158 };
159
160 void wdfinish __P((struct wd_softc *, struct buf *));
161 static void wdstart __P((struct wd_softc *));
162 static void wdcstart __P((struct wdc_softc *));
163 static int wdcommand __P((struct wd_softc *, int, int, int, int, int));
164 static int wdcontrol __P((struct wd_softc *));
165 static int wdsetctlr __P((struct wd_softc *));
166 static int wdgetctlr __P((struct wd_softc *));
167 static void bad144intern __P((struct wd_softc *));
168 static int wdcreset __P((struct wdc_softc *));
169 static void wdcrestart __P((struct wdc_softc *));
170 static void wdcunwedge __P((struct wdc_softc *));
171 static void wdctimeout __P((struct wdc_softc *));
172 void wddisksort __P((struct buf *, struct buf *));
173 static void wderror __P((void *, struct buf *, char *));
174 int wdcwait __P((struct wdc_softc *, int));
175 #define wait_for_drq(d) wdcwait(d, WDCS_DRQ)
176 #define wait_for_ready(d) wdcwait(d, WDCS_READY | WDCS_SEEKCMPLT)
177 #define wait_for_unbusy(d) wdcwait(d, 0)
178
179 /*
180 * Probe for controller.
181 */
182 int
183 wdcprobe(parent, self, aux)
184 struct device *parent, *self;
185 void *aux;
186 {
187 struct wdc_softc *wdc = (void *)self;
188 struct isa_attach_args *ia = aux;
189 struct wd_softc *wd;
190 u_short iobase;
191
192 wdc->sc_iobase = iobase = ia->ia_iobase;
193
194 /* Check if we have registers that work. */
195 outb(iobase+wd_error, 0x5a); /* Error register not writable. */
196 outb(iobase+wd_cyl_lo, 0xa5); /* But all of cyllo are implemented. */
197 if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5)
198 return 0;
199
200 if (wdcreset(wdc) != 0) {
201 delay(500000);
202 if (wdcreset(wdc) != 0)
203 return 0;
204 }
205
206 /*
207 * XXX wdcommand() accepts a wd_softc, so we have to make it one.
208 */
209 wd = (void *)malloc(sizeof(struct wd_softc), M_TEMP, M_NOWAIT);
210 bzero(wd, sizeof(struct wd_softc));
211 wd->sc_drive = 0;
212 wd->sc_dev.dv_unit = 0;
213 wd->sc_dev.dv_parent = (void *)wdc;
214
215 /* Execute a controller only command. */
216 if (wdcommand(wd, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0 ||
217 wait_for_unbusy(wdc) != 0)
218 goto lose;
219
220 free(wd, M_TEMP);
221 ia->ia_iosize = 8;
222 ia->ia_msize = 0;
223 return 1;
224
225 lose:
226 free(wd, M_TEMP);
227 return 0;
228 }
229
230 struct wdc_attach_args {
231 int wa_drive;
232 };
233
234 int
235 wdprint(aux, wdc)
236 void *aux;
237 char *wdc;
238 {
239 struct wdc_attach_args *wa = aux;
240
241 if (!wdc)
242 printf(" drive %d", wa->wa_drive);
243 return QUIET;
244 }
245
246 void
247 wdcattach(parent, self, aux)
248 struct device *parent, *self;
249 void *aux;
250 {
251 struct wdc_softc *wdc = (void *)self;
252 struct isa_attach_args *ia = aux;
253 struct wdc_attach_args wa;
254
255 printf("\n");
256
257 for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
258 (void)config_found(self, &wa, wdprint);
259
260 TAILQ_INIT(&wdc->sc_drives);
261 wdctimeout(wdc);
262 wdc->sc_ih.ih_fun = wdcintr;
263 wdc->sc_ih.ih_arg = wdc;
264 wdc->sc_ih.ih_level = IPL_BIO;
265 intr_establish(ia->ia_irq, &wdc->sc_ih);
266 }
267
268 int
269 wdprobe(parent, self, aux)
270 struct device *parent, *self;
271 void *aux;
272 {
273 struct wd_softc *wd = (void *)self;
274 struct cfdata *cf = wd->sc_dev.dv_cfdata;
275 struct wdc_attach_args *wa = aux;
276 int drive = wa->wa_drive;
277 #ifdef NEWCONFIG
278
279 #define cf_drive cf_loc[0]
280 if (cf->cf_drive != -1 && cf->cf_drive != drive)
281 return 0;
282 #undef cf_drive
283 #else
284 struct isa_device *id = (void *)cf->cf_loc;
285
286 if (id->id_physid != -1 && id->id_physid != drive)
287 return 0;
288 #endif
289
290 wd->sc_drive = drive;
291
292 if (wdgetctlr(wd) != 0)
293 return 0;
294
295 return 1;
296 }
297
298 void
299 wdattach(parent, self, aux)
300 struct device *parent, *self;
301 void *aux;
302 {
303 struct wd_softc *wd = (void *)self;
304 int i, blank;
305
306 if (wd->sc_params.wdp_heads == 0)
307 printf(": (unknown size) <");
308 else
309 printf(": %dMB %d cyl, %d head, %d sec <",
310 wd->sc_label.d_ncylinders * wd->sc_label.d_secpercyl /
311 (1048576 / DEV_BSIZE),
312 wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks,
313 wd->sc_label.d_nsectors);
314 for (i = blank = 0; i < sizeof(wd->sc_params.wdp_model); i++) {
315 char c = wd->sc_params.wdp_model[i];
316 if (c == '\0')
317 break;
318 if (c != ' ') {
319 if (blank)
320 printf(" %c", c);
321 else
322 printf("%c", c);
323 blank = 0;
324 } else
325 blank = 1;
326 }
327 printf(">\n");
328 }
329
330 /*
331 * Read/write routine for a buffer. Finds the proper unit, range checks
332 * arguments, and schedules the transfer. Does not wait for the transfer to
333 * complete. Multi-page transfers are supported. All I/O requests must be a
334 * multiple of a sector in length.
335 */
336 void
337 wdstrategy(bp)
338 struct buf *bp;
339 {
340 struct wd_softc *wd; /* disk unit to do the IO */
341 struct wdc_softc *wdc;
342 int lunit = WDUNIT(bp->b_dev);
343 int s;
344
345 /* Valid unit, controller, and request? */
346 if (lunit >= wdcd.cd_ndevs || bp->b_blkno < 0 ||
347 howmany(bp->b_bcount, DEV_BSIZE) >= (1 << NBBY) ||
348 (wd = wdcd.cd_devs[lunit]) == 0) {
349 bp->b_error = EINVAL;
350 bp->b_flags |= B_ERROR;
351 goto done;
352 }
353
354 /* "Soft" write protect check. */
355 if ((wd->sc_flags & WDF_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
356 bp->b_error = EROFS;
357 bp->b_flags |= B_ERROR;
358 goto done;
359 }
360
361 /* Have partitions and want to use them? */
362 if ((wd->sc_flags & WDF_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) {
363 /*
364 * Do bounds checking, adjust transfer. if error, process.
365 * If end of partition, just return.
366 */
367 if (bounds_check_with_label(bp, &wd->sc_label,
368 wd->sc_wlabel) <= 0)
369 goto done;
370 /* Otherwise, process transfer request. */
371 }
372
373 /* Don't bother doing rotational optimization. */
374 bp->b_cylin = 0;
375
376 /* Queue transfer on drive, activate drive and controller if idle. */
377 s = splbio();
378 wddisksort(&wd->sc_q, bp);
379 if (!wd->sc_q.b_active)
380 wdstart(wd); /* Start drive. */
381 #ifdef DIAGNOSTIC
382 else if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
383 printf("wdstrategy: controller inactive\n");
384 wdcstart(wdc);
385 }
386 #endif
387 splx(s);
388 return;
389
390 done:
391 /* Toss transfer; we're done early. */
392 biodone(bp);
393 }
394
395 /*
396 * Need to skip over multitransfer bufs.
397 */
398 void
399 wddisksort(dp, bp)
400 struct buf *dp, *bp;
401 {
402 struct buf *ap;
403
404 while ((ap = dp->b_actf) && ap->b_flags & B_XXX)
405 dp = ap;
406 disksort(dp, bp);
407 }
408
409 /*
410 * Routine to queue a command to the controller. The unit's request is linked
411 * into the active list for the controller. If the controller is idle, the
412 * transfer is started.
413 */
414 static void
415 wdstart(wd)
416 struct wd_softc *wd;
417 {
418 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
419 int active = wdc->sc_drives.tqh_first != 0;
420
421 /* Link onto controller queue. */
422 wd->sc_q.b_active = 1;
423 TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
424
425 /* If controller not already active, start it. */
426 if (!active)
427 wdcstart(wdc);
428 }
429
430 void
431 wdfinish(wd, bp)
432 struct wd_softc *wd;
433 struct buf *bp;
434 {
435 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
436
437 #ifdef INSTRUMENT
438 dk_busy &= ~(1 << wd->sc_drive);
439 #endif
440 wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
441 wdc->sc_errors = 0;
442 /*
443 * If this is the only buf or the last buf in the transfer (taking into
444 * account any residual, in case we erred)...
445 */
446 wd->sc_mbcount -= wd->sc_bcount;
447 if (wd->sc_mbcount == 0) {
448 wd->sc_mskip = 0;
449 /*
450 * ...then move this drive to the end of the queue to give
451 * others a `fair' chance.
452 */
453 if (wd->sc_drivechain.tqe_next) {
454 TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
455 if (bp->b_actf) {
456 TAILQ_INSERT_TAIL(&wdc->sc_drives, wd,
457 sc_drivechain);
458 } else
459 wd->sc_q.b_active = 0;
460 }
461 }
462 bp->b_resid = wd->sc_bcount;
463 bp->b_flags &= ~B_XXX;
464 wd->sc_skip = 0;
465 wd->sc_q.b_actf = bp->b_actf;
466 biodone(bp);
467 }
468
469 /*
470 * Controller startup routine. This does the calculation, and starts a
471 * single-sector read or write operation. Called to start a transfer, or from
472 * the interrupt routine to continue a multi-sector transfer.
473 * RESTRICTIONS:
474 * 1. The transfer length must be an exact multiple of the sector size.
475 */
476 static void
477 wdcstart(wdc)
478 struct wdc_softc *wdc;
479 {
480 struct wd_softc *wd; /* disk unit for IO */
481 struct buf *bp;
482 struct disklabel *lp;
483 long blknum, cylin, head, sector;
484 long secpertrk, secpercyl;
485 int xfrblknum;
486
487 loop:
488 /* Is there a drive for the controller to do a transfer with? */
489 wd = wdc->sc_drives.tqh_first;
490 if (wd == NULL)
491 return;
492
493 /* Is there a transfer to this drive? If not, deactivate drive. */
494 bp = wd->sc_q.b_actf;
495 if (bp == NULL) {
496 TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
497 wd->sc_q.b_active = 0;
498 goto loop;
499 }
500
501 if (wdc->sc_errors >= WDIORETRIES) {
502 wderror(wd, bp, "hard error");
503 bp->b_error = EIO;
504 bp->b_flags |= B_ERROR;
505 wdfinish(wd, bp);
506 goto loop;
507 }
508
509 /* Mark the controller active and set a timeout. */
510 wdc->sc_flags |= WDCF_ACTIVE;
511 wdc->sc_timeout = 4;
512
513 /* Do control operations specially. */
514 if (wd->sc_state < OPEN) {
515 /*
516 * Actually, we want to be careful not to mess with the control
517 * state if the device is currently busy, but we can assume
518 * that we never get to this point if that's the case.
519 */
520 (void) wdcontrol(wd);
521 return;
522 }
523
524 /*
525 * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is
526 * encountered. If we are in multi-sector mode, then we switch to
527 * single-sector mode and retry the operation from the start.
528 */
529 if (wdc->sc_flags & WDCF_ERROR) {
530 wdc->sc_flags &= ~WDCF_ERROR;
531 if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
532 wdc->sc_flags |= WDCF_SINGLE;
533 wd->sc_skip = 0;
534 wd->sc_mskip = 0;
535 }
536 }
537
538 /* Calculate transfer details. */
539 blknum = bp->b_blkno + wd->sc_skip;
540 #ifdef WDDEBUG
541 if (wd->sc_skip == 0)
542 printf("\nwdcstart %s: %s %d@%d; map ", wd->sc_dev.dv_xname,
543 (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
544 blknum);
545 else
546 printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts));
547 #endif
548 if (wd->sc_skip == 0)
549 wd->sc_bcount = bp->b_bcount;
550 if (wd->sc_mskip == 0) {
551 struct buf *oldbp, *nextbp;
552 oldbp = bp;
553 nextbp = bp->b_actf;
554 wd->sc_mbcount = wd->sc_bcount;
555 oldbp->b_flags |= B_XXX;
556 while (nextbp && oldbp->b_dev == nextbp->b_dev &&
557 nextbp->b_blkno ==
558 (oldbp->b_blkno + (oldbp->b_bcount / DEV_BSIZE)) &&
559 (oldbp->b_flags & B_READ) == (nextbp->b_flags & B_READ)) {
560 if ((wd->sc_mbcount + nextbp->b_bcount) / DEV_BSIZE >= 240)
561 break;
562 wd->sc_mbcount += nextbp->b_bcount;
563 nextbp->b_flags |= B_XXX;
564 oldbp = nextbp;
565 nextbp = nextbp->b_actf;
566 }
567 }
568
569 lp = &wd->sc_label;
570 secpertrk = lp->d_nsectors;
571 secpercyl = lp->d_secpercyl;
572 if ((wd->sc_flags & WDF_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW)
573 blknum += lp->d_partitions[WDPART(bp->b_dev)].p_offset;
574 cylin = blknum / secpercyl;
575 head = (blknum % secpercyl) / secpertrk;
576 sector = blknum % secpertrk;
577
578 /*
579 * Check for bad sectors if we have them, and not formatting. Only do
580 * this in single-sector mode, or when starting a multiple-sector
581 * transfer.
582 */
583 if ((wd->sc_flags & WDF_BADSECT) &&
584 #ifdef B_FORMAT
585 (bp->b_flags & B_FORMAT) == 0 &&
586 #endif
587 (wd->sc_mskip == 0 || (wdc->sc_flags & WDCF_SINGLE))) {
588
589 long blkchk, blkend, blknew;
590 int i;
591
592 blkend = blknum + howmany(wd->sc_mbcount, DEV_BSIZE) - 1;
593 for (i = 0; (blkchk = wd->sc_badsect[i]) != -1; i++) {
594 if (blkchk > blkend)
595 break; /* Transfer is completely OK; done. */
596 if (blkchk == blknum) {
597 blknew =
598 lp->d_secperunit - lp->d_nsectors - i - 1;
599 cylin = blknew / secpercyl;
600 head = (blknew % secpercyl) / secpertrk;
601 sector = blknew % secpertrk;
602 wdc->sc_flags |= WDCF_SINGLE;
603 /* Found and replaced first blk of transfer; done. */
604 break;
605 } else if (blkchk > blknum) {
606 wdc->sc_flags |= WDCF_SINGLE;
607 break; /* Bad block inside transfer; done. */
608 }
609 }
610 }
611 if (wdc->sc_flags & WDCF_SINGLE) {
612 wd->sc_mbcount = wd->sc_bcount;
613 wd->sc_mskip = wd->sc_skip;
614 }
615
616 #ifdef WDDEBUG
617 printf("c%d h%d s%d ", cylin, head, sector);
618 #endif
619
620 sector++; /* Sectors begin with 1, not 0. */
621
622 #ifdef INSTRUMENT
623 if (wd->sc_skip == 0) {
624 dk_busy |= 1 << wd->sc_dev.dv_unit;
625 dk_wds[wd->sc_dev.dv_unit] += bp->b_bcount >> 6;
626 }
627 #endif
628
629 /* If starting a multisector transfer, or doing single transfers. */
630 if (wd->sc_mskip == 0 || (wdc->sc_flags & WDCF_SINGLE)) {
631 int command, count;
632
633 #ifdef INSTRUMENT
634 ++dk_seek[wd->sc_dev.dv_unit];
635 ++dk_xfer[wd->sc_dev.dv_unit];
636 #endif
637
638 #ifdef B_FORMAT
639 if (bp->b_flags & B_FORMAT) {
640 sector = lp->d_gap3;
641 count = lp->d_nsectors;
642 command = WDCC_FORMAT;
643 } else {
644 if (wdc->sc_flags & WDCF_SINGLE)
645 count = 1;
646 else
647 count = howmany(wd->sc_mbcount, DEV_BSIZE);
648 command =
649 (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
650 }
651 #else
652 if (wdc->sc_flags & WDCF_SINGLE)
653 count = 1;
654 else
655 count = howmany(wd->sc_mbcount, DEV_BSIZE);
656 command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
657 #endif
658
659 /* Initiate command! */
660 if (wdcommand(wd, cylin, head, sector, count, command) != 0) {
661 wderror(wd, NULL,
662 "wdcstart: timeout waiting for unbusy");
663 wdcunwedge(wdc);
664 return;
665 }
666 #ifdef WDDEBUG
667 printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
668 cylin, head, bp->b_un.b_addr, inb(wd->sc_iobase+wd_altsts));
669 #endif
670 }
671
672 /* If this is a read operation, just go away until it's done. */
673 if (bp->b_flags & B_READ)
674 return;
675
676 if (wait_for_drq(wdc) < 0) {
677 wderror(wd, NULL, "wdcstart: timeout waiting for drq");
678 wdcunwedge(wdc);
679 return;
680 }
681
682 /* Then send it! */
683 outsw(wdc->sc_iobase+wd_data, bp->b_un.b_addr + wd->sc_skip * DEV_BSIZE,
684 DEV_BSIZE / sizeof(short));
685 }
686
687 /*
688 * Interrupt routine for the controller. Acknowledge the interrupt, check for
689 * errors on the current operation, mark it done if necessary, and start the
690 * next request. Also check for a partially done transfer, and continue with
691 * the next chunk if so.
692 */
693 int
694 wdcintr(wdc)
695 struct wdc_softc *wdc;
696 {
697 struct wd_softc *wd;
698 struct buf *bp;
699
700 /* Clear the pending interrupt. */
701 (void) inb(wdc->sc_iobase+wd_status);
702
703 if ((wdc->sc_flags & WDCF_ACTIVE) == 0)
704 return 0;
705
706 wd = wdc->sc_drives.tqh_first;
707 bp = wd->sc_q.b_actf;
708
709 #ifdef WDDEBUG
710 printf("I%d ", ctrlr);
711 #endif
712
713 if (wait_for_unbusy(wdc) < 0) {
714 wderror(wd, NULL, "wdcintr: timeout waiting for unbusy");
715 wdc->sc_status |= WDCS_ERR; /* XXX */
716 }
717
718 /* Is it not a transfer, but a control operation? */
719 if (wd->sc_state < OPEN) {
720 if (wdcontrol(wd))
721 wdcstart(wdc);
722 return 1;
723 }
724
725 wdc->sc_flags &= ~WDCF_ACTIVE;
726 wdc->sc_timeout = 0;
727
728 /* Have we an error? */
729 if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) {
730 lose:
731 #ifdef WDDEBUG
732 wderror(wd, NULL, "wdcintr");
733 #endif
734 if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
735 wdc->sc_flags |= WDCF_ERROR;
736 goto restart;
737 }
738 #ifdef B_FORMAT
739 if (bp->b_flags & B_FORMAT) {
740 bp->b_error = EIO;
741 bp->b_flags |= B_ERROR;
742 goto done;
743 }
744 #endif
745
746 /* Error or error correction? */
747 if (wdc->sc_status & WDCS_ERR) {
748 if (++wdc->sc_errors >= WDIORETRIES) {
749 wderror(wd, bp, "hard error");
750 bp->b_error = EIO;
751 bp->b_flags |= B_ERROR; /* Flag the error. */
752 goto done;
753 } else
754 goto restart;
755 } else
756 wderror(wd, bp, "soft ecc");
757 }
758
759 /* If this was a read, fetch the data. */
760 if (bp->b_flags & B_READ) {
761 /* Ready to receive data? */
762 if (wait_for_drq(wdc) != 0) {
763 wderror(wd, NULL, "wdcintr: read error detected late");
764 wdcunwedge(wdc);
765 return 1;
766 }
767
768 /* Suck in data. */
769 insw(wdc->sc_iobase+wd_data,
770 bp->b_un.b_addr + wd->sc_skip * DEV_BSIZE,
771 DEV_BSIZE / sizeof(short));
772 }
773
774 /* If we encountered any abnormalities, flag it as a soft error. */
775 if (wdc->sc_errors) {
776 wderror(wd, bp, "soft error");
777 wdc->sc_errors = 0;
778 }
779
780 /* Ready for the next block, if any. */
781 wd->sc_skip++;
782 wd->sc_mskip++;
783 wd->sc_bcount -= DEV_BSIZE;
784 wd->sc_mbcount -= DEV_BSIZE;
785
786 /* See if more to transfer. */
787 if (wd->sc_bcount > 0)
788 goto restart;
789
790 done:
791 /* Done with this transfer, with or without error. */
792 wdfinish(wd, bp);
793
794 restart:
795 /* Start the next transfer, if any. */
796 wdcstart(wdc);
797
798 return 1;
799 }
800
801 /*
802 * Initialize a drive.
803 */
804 int
805 wdopen(dev, flag, fmt, p)
806 dev_t dev;
807 int flag;
808 int fmt;
809 struct proc *p;
810 {
811 int lunit;
812 struct wd_softc *wd;
813 int part = WDPART(dev), mask = 1 << part;
814 struct partition *pp;
815 char *msg;
816
817 lunit = WDUNIT(dev);
818 if (lunit >= wdcd.cd_ndevs)
819 return ENXIO;
820 wd = wdcd.cd_devs[lunit];
821 if (wd == 0)
822 return ENXIO;
823
824 if ((wd->sc_flags & WDF_BSDLABEL) == 0) {
825 wd->sc_flags |= WDF_WRITEPROT;
826 wd->sc_q.b_actf = NULL;
827
828 /*
829 * Use the default sizes until we've read the label, or longer
830 * if there isn't one there.
831 */
832 bzero(&wd->sc_label, sizeof(wd->sc_label));
833 wd->sc_label.d_type = DTYPE_ST506;
834 wd->sc_label.d_ncylinders = 1024;
835 wd->sc_label.d_secsize = DEV_BSIZE;
836 wd->sc_label.d_ntracks = 8;
837 wd->sc_label.d_nsectors = 17;
838 wd->sc_label.d_secpercyl = 17*8;
839 wd->sc_label.d_secperunit = 17*8*1024;
840 wd->sc_state = RECAL;
841
842 /* Read label using "raw" partition. */
843 msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW),
844 wdstrategy, &wd->sc_label, &wd->sc_cpulabel);
845 if (msg) {
846 /*
847 * This probably happened because the drive's default
848 * geometry doesn't match the DOS geometry. We
849 * assume the DOS geometry is now in the label and try
850 * again. XXX This is a kluge.
851 */
852 if (wd->sc_state > GEOMETRY)
853 wd->sc_state = GEOMETRY;
854 msg = readdisklabel(makewddev(major(dev), WDUNIT(dev),
855 WDRAW), wdstrategy, &wd->sc_label,
856 &wd->sc_cpulabel);
857 }
858 if (msg) {
859 log(LOG_WARNING, "%s: cannot find label (%s)\n",
860 wd->sc_dev.dv_xname, msg);
861 if (part != WDRAW)
862 return EINVAL; /* XXX needs translation */
863 } else {
864 if (wd->sc_state > GEOMETRY)
865 wd->sc_state = GEOMETRY;
866 wd->sc_flags |= WDF_BSDLABEL;
867 wd->sc_flags &= ~WDF_WRITEPROT;
868 if (wd->sc_label.d_flags & D_BADSECT)
869 wd->sc_flags |= WDF_BADSECT;
870 }
871 }
872
873 if (wd->sc_flags & WDF_BADSECT)
874 bad144intern(wd);
875
876 /*
877 * Warn if a partition is opened that overlaps another partition which
878 * is open unless one is the "raw" partition (whole disk).
879 */
880 if ((wd->sc_openpart & mask) == 0 && part != WDRAW) {
881 int start, end;
882
883 pp = &wd->sc_label.d_partitions[part];
884 start = pp->p_offset;
885 end = pp->p_offset + pp->p_size;
886 for (pp = wd->sc_label.d_partitions;
887 pp < &wd->sc_label.d_partitions[wd->sc_label.d_npartitions];
888 pp++) {
889 if (pp->p_offset + pp->p_size <= start ||
890 pp->p_offset >= end)
891 continue;
892 if (pp - wd->sc_label.d_partitions == WDRAW)
893 continue;
894 if (wd->sc_openpart & (1 << (pp - wd->sc_label.d_partitions)))
895 log(LOG_WARNING,
896 "%s%c: overlaps open partition (%c)\n",
897 wd->sc_dev.dv_xname, part + 'a',
898 pp - wd->sc_label.d_partitions + 'a');
899 }
900 }
901 if (part >= wd->sc_label.d_npartitions && part != WDRAW)
902 return ENXIO;
903
904 /* Insure only one open at a time. */
905 switch (fmt) {
906 case S_IFCHR:
907 wd->sc_copenpart |= mask;
908 break;
909 case S_IFBLK:
910 wd->sc_bopenpart |= mask;
911 break;
912 }
913 wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart;
914
915 return 0;
916 }
917
918 /*
919 * Implement operations other than read/write.
920 * Called from wdcstart or wdcintr during opens and formats.
921 * Uses finite-state-machine to track progress of operation in progress.
922 * Returns 0 if operation still in progress, 1 if completed.
923 */
924 static int
925 wdcontrol(wd)
926 struct wd_softc *wd;
927 {
928 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
929
930 switch (wd->sc_state) {
931 case RECAL: /* Set SDH, step rate, do restore. */
932 if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) {
933 wderror(wd, NULL, "wdcontrol: wdcommand failed");
934 wdcunwedge(wdc);
935 return 0;
936 }
937 wd->sc_state = RECAL_WAIT;
938 return 0;
939
940 case RECAL_WAIT:
941 if (wdc->sc_status & WDCS_ERR) {
942 wderror(wd, NULL, "wdcontrol: recal failed");
943 wdcunwedge(wdc);
944 return 0;
945 }
946 /* fall through */
947 case GEOMETRY:
948 if (wdsetctlr(wd) != 0) {
949 /* Already printed a message. */
950 wdcunwedge(wdc);
951 return 0;
952 }
953 wd->sc_state = GEOMETRY_WAIT;
954 return 0;
955
956 case GEOMETRY_WAIT:
957 if (wdc->sc_status & WDCS_ERR) {
958 wderror(wd, NULL, "wdcontrol: geometry failed");
959 wdcunwedge(wdc);
960 return 0;
961 }
962
963 wdc->sc_errors = 0;
964 wd->sc_state = OPEN;
965 /*
966 * The rest of the initialization can be done by normal means.
967 */
968 return 1;
969 }
970
971 #ifdef DIAGNOSTIC
972 panic("wdcontrol: impossible");
973 #endif
974 }
975
976 /*
977 * Send a command and wait uninterruptibly until controller is finished.
978 * Return -1 if controller busy for too long, otherwise return non-zero if
979 * error. Intended for brief controller commands at critical points.
980 * Assumes interrupts are blocked.
981 */
982 static int
983 wdcommand(wd, cylin, head, sector, count, cmd)
984 struct wd_softc *wd;
985 int cylin, head, sector, count;
986 int cmd;
987 {
988 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
989 int stat;
990 u_short iobase;
991
992 /* Controller ready for command? */
993 if (wait_for_unbusy(wdc) < 0)
994 return -1;
995
996 /* Select drive. */
997 iobase = wdc->sc_iobase;
998 outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head);
999 if (cmd == WDCC_DIAGNOSE || cmd == WDCC_IDC)
1000 stat = wait_for_unbusy(wdc);
1001 else
1002 stat = wdcwait(wdc, WDCS_READY);
1003 if (stat < 0)
1004 return -1;
1005
1006 /* Load parameters. */
1007 outb(iobase+wd_precomp, wd->sc_label.d_precompcyl / 4);
1008 outb(iobase+wd_cyl_lo, cylin);
1009 outb(iobase+wd_cyl_hi, cylin >> 8);
1010 outb(iobase+wd_sector, sector);
1011 outb(iobase+wd_seccnt, count);
1012
1013 /* Send command, await results. */
1014 outb(iobase+wd_command, cmd);
1015
1016 return 0;
1017 }
1018
1019 /*
1020 * Issue IDC to drive to tell it just what geometry it is to be.
1021 */
1022 static int
1023 wdsetctlr(wd)
1024 struct wd_softc *wd;
1025 {
1026 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1027
1028 #ifdef WDDEBUG
1029 printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_ctrlr, wd->sc_drive,
1030 wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks,
1031 wd->sc_label.d_nsectors);
1032 #endif
1033
1034 if (wdcommand(wd, wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks - 1,
1035 0, wd->sc_label.d_nsectors, WDCC_IDC) != 0) {
1036 wderror(wd, NULL, "wdsetctlr: wdcommand failed");
1037 return -1;
1038 }
1039
1040 return 0;
1041 }
1042
1043 /*
1044 * Issue READP to drive to ask it what it is.
1045 */
1046 static int
1047 wdgetctlr(wd)
1048 struct wd_softc *wd;
1049 {
1050 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1051 int i;
1052 char tb[DEV_BSIZE];
1053 struct wdparams *wp;
1054
1055 if (wdcommand(wd, 0, 0, 0, 0, WDCC_READP) != 0 ||
1056 wait_for_drq(wdc) != 0) {
1057 /*
1058 * If WDCC_READP fails then we might have an old drive so we
1059 * try a seek to 0; if that passes then the drive is there but
1060 * it's OLD AND KRUSTY.
1061 */
1062 if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 ||
1063 wait_for_ready(wdc) != 0)
1064 return -1;
1065
1066 strncpy(wd->sc_label.d_typename, "ST506",
1067 sizeof wd->sc_label.d_typename);
1068 strncpy(wd->sc_params.wdp_model, "Unknown Type",
1069 sizeof wd->sc_params.wdp_model);
1070 wd->sc_label.d_type = DTYPE_ST506;
1071 } else {
1072 /* Obtain parameters. */
1073 wp = &wd->sc_params;
1074 insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
1075 bcopy(tb, wp, sizeof(struct wdparams));
1076
1077 /* Shuffle string byte order. */
1078 for (i = 0; i < sizeof(wp->wdp_model); i += 2) {
1079 u_short *p;
1080 p = (u_short *)(wp->wdp_model + i);
1081 *p = ntohs(*p);
1082 }
1083
1084 strncpy(wd->sc_label.d_typename, "ESDI/IDE",
1085 sizeof wd->sc_label.d_typename);
1086 wd->sc_label.d_type = DTYPE_ESDI;
1087 bcopy(wp->wdp_model+20, wd->sc_label.d_packname, 14-1);
1088
1089 /* Update disklabel given drive information. */
1090 wd->sc_label.d_ncylinders =
1091 wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/;
1092 wd->sc_label.d_ntracks = wp->wdp_heads;
1093 wd->sc_label.d_nsectors = wp->wdp_sectors;
1094 wd->sc_label.d_secpercyl =
1095 wd->sc_label.d_ntracks * wd->sc_label.d_nsectors;
1096 wd->sc_label.d_partitions[1].p_size =
1097 wd->sc_label.d_secpercyl * wp->wdp_sectors;
1098 wd->sc_label.d_partitions[1].p_offset = 0;
1099 }
1100
1101 #if 0
1102 printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
1103 wp->wdp_config, wp->wdp_fixedcyl + wp->wdp_removcyl, wp->wdp_heads,
1104 wp->wdp_sectors, wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);
1105 #endif
1106
1107 wd->sc_label.d_subtype |= DSTYPE_GEOMETRY;
1108
1109 /* XXX sometimes possibly needed */
1110 (void) inb(wdc->sc_iobase+wd_status);
1111
1112 return 0;
1113 }
1114
1115 int
1116 wdclose(dev, flag, fmt)
1117 dev_t dev;
1118 int flag;
1119 int fmt;
1120 {
1121 struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)];
1122 int part = WDPART(dev), mask = 1 << part;
1123
1124 switch (fmt) {
1125 case S_IFCHR:
1126 wd->sc_copenpart &= ~mask;
1127 break;
1128 case S_IFBLK:
1129 wd->sc_bopenpart &= ~mask;
1130 break;
1131 }
1132 wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart;
1133
1134 return 0;
1135 }
1136
1137 int
1138 wdioctl(dev, cmd, addr, flag, p)
1139 dev_t dev;
1140 int cmd;
1141 caddr_t addr;
1142 int flag;
1143 struct proc *p;
1144 {
1145 int lunit = WDUNIT(dev);
1146 struct wd_softc *wd = wdcd.cd_devs[lunit];
1147 int error;
1148
1149 switch (cmd) {
1150 case DIOCSBAD:
1151 if ((flag & FWRITE) == 0)
1152 return EBADF;
1153 wd->sc_cpulabel.bad = *(struct dkbad *)addr;
1154 bad144intern(wd);
1155 return 0;
1156
1157 case DIOCGDINFO:
1158 *(struct disklabel *)addr = wd->sc_label;
1159 return 0;
1160
1161 case DIOCGPART:
1162 ((struct partinfo *)addr)->disklab = &wd->sc_label;
1163 ((struct partinfo *)addr)->part =
1164 &wd->sc_label.d_partitions[WDPART(dev)];
1165 return 0;
1166
1167 case DIOCSDINFO:
1168 if ((flag & FWRITE) == 0)
1169 return EBADF;
1170 error = setdisklabel(&wd->sc_label,
1171 (struct disklabel *)addr,
1172 /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_openpart : */0,
1173 &wd->sc_cpulabel);
1174 if (error == 0) {
1175 wd->sc_flags |= WDF_BSDLABEL;
1176 if (wd->sc_state > GEOMETRY)
1177 wd->sc_state = GEOMETRY;
1178 }
1179 return error;
1180
1181 case DIOCWLABEL:
1182 wd->sc_flags &= ~WDF_WRITEPROT;
1183 if ((flag & FWRITE) == 0)
1184 return EBADF;
1185 wd->sc_wlabel = *(int *)addr;
1186 return 0;
1187
1188 case DIOCWDINFO:
1189 wd->sc_flags &= ~WDF_WRITEPROT;
1190 if ((flag & FWRITE) == 0)
1191 return EBADF;
1192 error = setdisklabel(&wd->sc_label,
1193 (struct disklabel *)addr,
1194 /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_openpart :*/0,
1195 &wd->sc_cpulabel);
1196 if (error == 0) {
1197 int wlab;
1198
1199 wd->sc_flags |= WDF_BSDLABEL;
1200 if (wd->sc_state > GEOMETRY)
1201 wd->sc_state = GEOMETRY;
1202
1203 /* Simulate opening partition 0 so write succeeds. */
1204 wd->sc_openpart |= (1 << 0); /* XXX */
1205 wlab = wd->sc_wlabel;
1206 wd->sc_wlabel = 1;
1207 error = writedisklabel(dev, wdstrategy, &wd->sc_label,
1208 &wd->sc_cpulabel);
1209 wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart;
1210 wd->sc_wlabel = wlab;
1211 }
1212 return error;
1213
1214 #ifdef notyet
1215 case DIOCGDINFOP:
1216 *(struct disklabel **)addr = &wd->sc_label;
1217 return 0;
1218
1219 case DIOCWFORMAT:
1220 if ((flag & FWRITE) == 0)
1221 return EBADF;
1222 {
1223 register struct format_op *fop;
1224 struct iovec aiov;
1225 struct uio auio;
1226
1227 fop = (struct format_op *)addr;
1228 aiov.iov_base = fop->df_buf;
1229 aiov.iov_len = fop->df_count;
1230 auio.uio_iov = &aiov;
1231 auio.uio_iovcnt = 1;
1232 auio.uio_resid = fop->df_count;
1233 auio.uio_segflg = 0;
1234 auio.uio_offset =
1235 fop->df_startblk * wd->sc_label.d_secsize;
1236 error = physio(wdformat, NULL, dev, B_WRITE, minphys,
1237 &auio);
1238 fop->df_count -= auio.uio_resid;
1239 fop->df_reg[0] = wdc->sc_status;
1240 fop->df_reg[1] = wdc->sc_error;
1241 return error;
1242 }
1243 #endif
1244
1245 default:
1246 return ENOTTY;
1247 }
1248
1249 #ifdef DIAGNOSTIC
1250 panic("wdioctl: impossible");
1251 #endif
1252 }
1253
1254 #ifdef B_FORMAT
1255 int
1256 wdformat(struct buf *bp)
1257 {
1258
1259 bp->b_flags |= B_FORMAT;
1260 return wdstrategy(bp);
1261 }
1262 #endif
1263
1264 int
1265 wdsize(dev)
1266 dev_t dev;
1267 {
1268 int lunit = WDUNIT(dev), part = WDPART(dev);
1269 struct wd_softc *wd;
1270
1271 if (lunit >= wdcd.cd_ndevs)
1272 return -1;
1273 wd = wdcd.cd_devs[lunit];
1274 if (wd == 0)
1275 return -1;
1276
1277 if (wd->sc_state < OPEN || (wd->sc_flags & WDF_BSDLABEL) == 0) {
1278 int val;
1279 val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD,
1280 S_IFBLK, 0);
1281 /* XXX Clear the open flag? */
1282 if (val != 0)
1283 return -1;
1284 }
1285
1286 if ((wd->sc_flags & (WDF_WRITEPROT | WDF_BSDLABEL)) != WDF_BSDLABEL)
1287 return -1;
1288
1289 return (int)wd->sc_label.d_partitions[part].p_size;
1290 }
1291
1292 /*
1293 * Dump core after a system crash.
1294 */
1295 int
1296 wddump(dev)
1297 dev_t dev;
1298 {
1299 struct wd_softc *wd; /* disk unit to do the IO */
1300 struct wdc_softc *wdc;
1301 long num; /* number of sectors to write */
1302 int lunit, part;
1303 long blkoff, blknum;
1304 long cylin, head, sector;
1305 long secpertrk, secpercyl, nblocks;
1306 char *addr;
1307 static wddoingadump = 0;
1308 extern caddr_t CADDR1;
1309 extern struct pte *CMAP1;
1310
1311 addr = (char *)0; /* starting address */
1312
1313 #if DO_NOT_KNOW_HOW
1314 /* Toss any characters present prior to dump, ie. non-blocking getc. */
1315 while (cngetc())
1316 ;
1317 #endif
1318
1319 lunit = WDUNIT(dev);
1320 /* Check for acceptable drive number. */
1321 if (lunit >= wdcd.cd_ndevs)
1322 return ENXIO;
1323 wd = wdcd.cd_devs[lunit];
1324 /* Was it ever initialized? */
1325 if (wd == 0 || wd->sc_state < OPEN || wd->sc_flags & WDF_WRITEPROT)
1326 return ENXIO;
1327
1328 wdc = (void *)wd->sc_dev.dv_parent;
1329
1330 /* Convert to disk sectors. */
1331 num = ctob(physmem) / wd->sc_label.d_secsize;
1332
1333 secpertrk = wd->sc_label.d_nsectors;
1334 secpercyl = wd->sc_label.d_secpercyl;
1335 part = WDPART(dev);
1336 nblocks = wd->sc_label.d_partitions[part].p_size;
1337 blkoff = wd->sc_label.d_partitions[part].p_offset;
1338
1339 /*printf("part %x, nblocks %d, dumplo %d, num %d\n", part, nblocks,
1340 dumplo, num);*/
1341
1342 /* Check transfer bounds against partition size. */
1343 if (dumplo < 0 || dumplo + num > nblocks)
1344 return EINVAL;
1345
1346 if (wddoingadump)
1347 return EFAULT;
1348 wddoingadump = 1;
1349
1350 /* Recalibrate. */
1351 if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 ||
1352 wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 ||
1353 wait_for_ready(wdc) != 0) {
1354 wderror(wd, NULL, "wddump: recal failed");
1355 return EIO;
1356 }
1357
1358 blknum = dumplo + blkoff;
1359 while (num > 0) {
1360 /* Compute disk address. */
1361 cylin = blknum / secpercyl;
1362 head = (blknum % secpercyl) / secpertrk;
1363 sector = blknum % secpertrk;
1364
1365 if (wd->sc_flags & WDF_BADSECT) {
1366 long newblk;
1367 int i;
1368
1369 for (i = 0; wd->sc_badsect[i] != -1; i++) {
1370 if (blknum < wd->sc_badsect[i]) {
1371 /* Sorted list, passed our block by. */
1372 break;
1373 } else if (blknum == wd->sc_badsect[i]) {
1374 newblk = wd->sc_label.d_secperunit -
1375 wd->sc_label.d_nsectors - i - 1;
1376 cylin = newblk / secpercyl;
1377 head = (newblk % secpercyl) / secpertrk;
1378 sector = newblk % secpertrk;
1379 /* Found and replaced; done. */
1380 break;
1381 }
1382 }
1383 }
1384 sector++; /* origin 1 */
1385
1386 #ifdef notdef
1387 /* Let's just talk about this first. */
1388 printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head,
1389 sector, addr);
1390 #endif
1391 if (wdcommand(wd, cylin, head, sector, 1, WDCC_WRITE) != 0) {
1392 wderror(wd, NULL, "wddump: wdcommand failed");
1393 return EIO;
1394 }
1395 if (wait_for_drq(wdc) != 0) {
1396 wderror(wd, NULL, "wddump: timeout waiting for drq");
1397 return EIO;
1398 }
1399
1400 #ifdef notdef /* Cannot use this since this address was mapped differently. */
1401 pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
1402 #else
1403 *(int *)CMAP1 = PG_V | PG_KW | ctob((long)addr);
1404 tlbflush();
1405 #endif
1406
1407 outsw(wdc->sc_iobase+wd_data, CADDR1 + ((int)addr & PGOFSET),
1408 DEV_BSIZE / sizeof(short));
1409
1410 /* Check data request (should be done). */
1411 if (wait_for_ready(wdc) != 0) {
1412 wderror(wd, NULL, "wddump: timeout waiting for ready");
1413 return EIO;
1414 }
1415 if (wdc->sc_status & WDCS_DRQ) {
1416 wderror(wd, NULL, "wddump: extra drq");
1417 return EIO;
1418 }
1419
1420 if ((unsigned)addr % 1048576 == 0)
1421 printf("%d ", num / (1048576 / DEV_BSIZE));
1422
1423 /* Update block count. */
1424 num--;
1425 blknum++;
1426 (int)addr += DEV_BSIZE;
1427
1428 #if DO_NOT_KNOW_HOW
1429 /* Operator aborting dump? non-blocking getc() */
1430 if (cngetc())
1431 return EINTR;
1432 #endif
1433 }
1434 return 0;
1435 }
1436
1437 /*
1438 * Internalize the bad sector table.
1439 */
1440 void
1441 bad144intern(wd)
1442 struct wd_softc *wd;
1443 {
1444 int i;
1445
1446 if ((wd->sc_flags & WDF_BADSECT) == 0)
1447 return;
1448
1449 for (i = 0; i < 127; i++)
1450 wd->sc_badsect[i] = -1;
1451 for (i = 0; i < 126; i++) {
1452 if (wd->sc_cpulabel.bad.bt_bad[i].bt_cyl == 0xffff)
1453 break;
1454 wd->sc_badsect[i] =
1455 wd->sc_cpulabel.bad.bt_bad[i].bt_cyl *
1456 wd->sc_label.d_secpercyl +
1457 (wd->sc_cpulabel.bad.bt_bad[i].bt_trksec >> 8) *
1458 wd->sc_label.d_nsectors +
1459 (wd->sc_cpulabel.bad.bt_bad[i].bt_trksec & 0x00ff);
1460 }
1461 }
1462
1463 static int
1464 wdcreset(wdc)
1465 struct wdc_softc *wdc;
1466 {
1467 u_short iobase = wdc->sc_iobase;
1468
1469 /* Reset the device. */
1470 outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
1471 delay(1000);
1472 outb(iobase+wd_ctlr, WDCTL_IDS);
1473 delay(1000);
1474 (void) inb(iobase+wd_error);
1475 outb(iobase+wd_ctlr, WDCTL_4BIT);
1476
1477 if (wait_for_unbusy(wdc) < 0) {
1478 printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
1479 return 1;
1480 }
1481
1482 return 0;
1483 }
1484
1485 static void
1486 wdcrestart(wdc)
1487 struct wdc_softc *wdc;
1488 {
1489 int s = splbio();
1490
1491 wdcstart(wdc);
1492 splx(s);
1493 }
1494
1495 /*
1496 * Unwedge the controller after an unexpected error. We do this by resetting
1497 * it, marking all drives for recalibration, and stalling the queue for a short
1498 * period to give the reset time to finish.
1499 * NOTE: We use a timeout here, so this routine must not be called during
1500 * autoconfig or dump.
1501 */
1502 static void
1503 wdcunwedge(wdc)
1504 struct wdc_softc *wdc;
1505 {
1506 int lunit;
1507
1508 wdc->sc_timeout = 0;
1509 (void) wdcreset(wdc);
1510
1511 /* Schedule recalibrate for all drives on this controller. */
1512 for (lunit = 0; lunit < wdcd.cd_ndevs; lunit++) {
1513 struct wd_softc *wd = wdcd.cd_devs[lunit];
1514 if (!wd || (void *)wd->sc_dev.dv_parent != wdc)
1515 continue;
1516 if (wd->sc_state > RECAL)
1517 wd->sc_state = RECAL;
1518 }
1519
1520 wdc->sc_flags |= WDCF_ERROR;
1521 ++wdc->sc_errors;
1522
1523 /* Wake up in a little bit and restart the operation. */
1524 timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);
1525 }
1526
1527 int
1528 wdcwait(wdc, mask)
1529 struct wdc_softc *wdc;
1530 int mask;
1531 {
1532 u_short iobase = wdc->sc_iobase;
1533 int timeout = 0;
1534 u_char status;
1535
1536 for (;;) {
1537 wdc->sc_status = status = inb(iobase+wd_altsts);
1538 if ((status & WDCS_BUSY) == 0 && (status & mask) == mask)
1539 break;
1540 if (++timeout > WDCNDELAY)
1541 return -1;
1542 delay(WDCDELAY);
1543 }
1544 if (status & WDCS_ERR)
1545 wdc->sc_error = inb(iobase+wd_error);
1546 #ifdef WDCNDELAY_DEBUG
1547 if (timeout > WDCNDELAY_DEBUG)
1548 printf("%s: ignore this: busy-wait took %dus\n",
1549 wdc->sc_dev.dv_xname, WDCDELAY * timeout);
1550 #endif
1551 return status & WDCS_ERR;
1552 }
1553
1554 static void
1555 wdctimeout(wdc)
1556 struct wdc_softc *wdc;
1557 {
1558 int s = splbio();
1559
1560 if (wdc->sc_timeout && --wdc->sc_timeout == 0) {
1561 wderror(wdc, NULL, "lost interrupt");
1562 wdcunwedge(wdc);
1563 }
1564 timeout((timeout_t)wdctimeout, (caddr_t)wdc, hz);
1565 splx(s);
1566 }
1567
1568 static void
1569 wderror(dev, bp, msg)
1570 void *dev;
1571 struct buf *bp;
1572 char *msg;
1573 {
1574 struct wd_softc *wd = dev;
1575 struct wdc_softc *wdc = dev;
1576
1577 if (bp)
1578 diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip, &wd->sc_label);
1579 else
1580 printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname,
1581 msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS);
1582 }
1583