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