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