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