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