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