wd.c revision 1.141 1 /* $NetBSD: wd.c,v 1.141 1995/07/04 07:23:53 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, 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 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 char *errstring;
987
988 bzero(&wd->sc_dk.dk_label, sizeof(struct disklabel));
989 bzero(&wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
990
991 wd->sc_dk.dk_label.d_secsize = DEV_BSIZE;
992 wd->sc_dk.dk_label.d_ntracks = wd->sc_params.wdp_heads;
993 wd->sc_dk.dk_label.d_nsectors = wd->sc_params.wdp_sectors;
994 wd->sc_dk.dk_label.d_ncylinders = wd->sc_params.wdp_cylinders;
995 wd->sc_dk.dk_label.d_secpercyl =
996 wd->sc_dk.dk_label.d_ntracks * wd->sc_dk.dk_label.d_nsectors;
997
998 #if 0
999 strncpy(wd->sc_dk.dk_label.d_typename, "ST506 disk", 16);
1000 wd->sc_dk.dk_label.d_type = DTYPE_ST506;
1001 #endif
1002 strncpy(wd->sc_dk.dk_label.d_packname, wd->sc_params.wdp_model, 16);
1003 wd->sc_dk.dk_label.d_secperunit =
1004 wd->sc_dk.dk_label.d_secpercyl * wd->sc_dk.dk_label.d_ncylinders;
1005 wd->sc_dk.dk_label.d_rpm = 3600;
1006 wd->sc_dk.dk_label.d_interleave = 1;
1007 wd->sc_dk.dk_label.d_flags = 0;
1008
1009 wd->sc_dk.dk_label.d_partitions[RAW_PART].p_offset = 0;
1010 wd->sc_dk.dk_label.d_partitions[RAW_PART].p_size =
1011 wd->sc_dk.dk_label.d_secperunit *
1012 (wd->sc_dk.dk_label.d_secsize / DEV_BSIZE);
1013 wd->sc_dk.dk_label.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1014 wd->sc_dk.dk_label.d_npartitions = RAW_PART + 1;
1015
1016 wd->sc_dk.dk_label.d_magic = DISKMAGIC;
1017 wd->sc_dk.dk_label.d_magic2 = DISKMAGIC;
1018 wd->sc_dk.dk_label.d_checksum = dkcksum(&wd->sc_dk.dk_label);
1019
1020 wd->sc_badsect[0] = -1;
1021
1022 if (wd->sc_state > RECAL)
1023 wd->sc_state = RECAL;
1024 errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
1025 wdstrategy, &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel);
1026 if (errstring) {
1027 /*
1028 * This probably happened because the drive's default
1029 * geometry doesn't match the DOS geometry. We
1030 * assume the DOS geometry is now in the label and try
1031 * again. XXX This is a kluge.
1032 */
1033 if (wd->sc_state > GEOMETRY)
1034 wd->sc_state = GEOMETRY;
1035 errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
1036 wdstrategy, &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel);
1037 }
1038 if (errstring) {
1039 printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
1040 return;
1041 }
1042
1043 if (wd->sc_state > GEOMETRY)
1044 wd->sc_state = GEOMETRY;
1045 if ((wd->sc_dk.dk_label.d_flags & D_BADSECT) != 0)
1046 bad144intern(wd);
1047 }
1048
1049 /*
1050 * Implement operations needed before read/write.
1051 * Returns 0 if operation still in progress, 1 if completed.
1052 */
1053 int
1054 wdcontrol(wd)
1055 struct wd_softc *wd;
1056 {
1057 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1058
1059 switch (wd->sc_state) {
1060 case RECAL: /* Set SDH, step rate, do recal. */
1061 if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0) {
1062 wderror(wd, NULL, "wdcontrol: recal failed (1)");
1063 goto bad;
1064 }
1065 wd->sc_state = RECAL_WAIT;
1066 break;
1067
1068 case RECAL_WAIT:
1069 if (wdc->sc_status & WDCS_ERR) {
1070 wderror(wd, NULL, "wdcontrol: recal failed (2)");
1071 goto bad;
1072 }
1073 /* fall through */
1074 case GEOMETRY:
1075 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
1076 goto multimode;
1077 if (wdsetctlr(wd) != 0) {
1078 /* Already printed a message. */
1079 goto bad;
1080 }
1081 wd->sc_state = GEOMETRY_WAIT;
1082 break;
1083
1084 case GEOMETRY_WAIT:
1085 if (wdc->sc_status & WDCS_ERR) {
1086 wderror(wd, NULL, "wdcontrol: geometry failed");
1087 goto bad;
1088 }
1089 /* fall through */
1090 case MULTIMODE:
1091 multimode:
1092 if (wd->sc_mode != WDM_PIOMULTI)
1093 goto open;
1094 outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
1095 if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
1096 wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
1097 goto bad;
1098 }
1099 wd->sc_state = MULTIMODE_WAIT;
1100 break;
1101
1102 case MULTIMODE_WAIT:
1103 if (wdc->sc_status & WDCS_ERR) {
1104 wderror(wd, NULL, "wdcontrol: setmulti failed (2)");
1105 goto bad;
1106 }
1107 /* fall through */
1108 case OPEN:
1109 open:
1110 wdc->sc_errors = 0;
1111 wd->sc_state = OPEN;
1112 /*
1113 * The rest of the initialization can be done by normal means.
1114 */
1115 return 1;
1116
1117 bad:
1118 wdcunwedge(wdc);
1119 return 0;
1120 }
1121
1122 wdc->sc_flags |= WDCF_ACTIVE;
1123 timeout(wdctimeout, wdc, WAITTIME);
1124 return 0;
1125 }
1126
1127 /*
1128 * Wait for the drive to become ready and send a command.
1129 * Return -1 if busy for too long or 0 otherwise.
1130 * Assumes interrupts are blocked.
1131 */
1132 int
1133 wdcommand(wd, command, cylin, head, sector, count)
1134 struct wd_softc *wd;
1135 int command;
1136 int cylin, head, sector, count;
1137 {
1138 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1139 int iobase = wdc->sc_iobase;
1140 int stat;
1141
1142 /* Select drive, head, and addressing mode. */
1143 outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head);
1144
1145 /* Wait for it to become ready to accept a command. */
1146 if (command == WDCC_IDP)
1147 stat = wait_for_unbusy(wdc);
1148 else
1149 stat = wdcwait(wdc, WDCS_DRDY);
1150 if (stat < 0)
1151 return -1;
1152
1153 /* Load parameters. */
1154 if (wd->sc_dk.dk_label.d_type == DTYPE_ST506)
1155 outb(iobase+wd_precomp, wd->sc_dk.dk_label.d_precompcyl / 4);
1156 else
1157 outb(iobase+wd_features, 0);
1158 outb(iobase+wd_cyl_lo, cylin);
1159 outb(iobase+wd_cyl_hi, cylin >> 8);
1160 outb(iobase+wd_sector, sector);
1161 outb(iobase+wd_seccnt, count);
1162
1163 /* Send command. */
1164 outb(iobase+wd_command, command);
1165
1166 return 0;
1167 }
1168
1169 /*
1170 * Simplified version of wdcommand().
1171 */
1172 int
1173 wdcommandshort(wdc, drive, command)
1174 struct wdc_softc *wdc;
1175 int drive;
1176 int command;
1177 {
1178 int iobase = wdc->sc_iobase;
1179
1180 /* Select drive. */
1181 outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
1182
1183 if (wdcwait(wdc, WDCS_DRDY) < 0)
1184 return -1;
1185
1186 outb(iobase+wd_command, command);
1187
1188 return 0;
1189 }
1190
1191 /*
1192 * Tell the drive what geometry to use.
1193 */
1194 int
1195 wdsetctlr(wd)
1196 struct wd_softc *wd;
1197 {
1198 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1199
1200 #ifdef WDDEBUG
1201 printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, wd->sc_drive,
1202 wd->sc_dk.dk_label.d_ncylinders, wd->sc_dk.dk_label.d_ntracks,
1203 wd->sc_dk.dk_label.d_nsectors);
1204 #endif
1205
1206 if (wdcommand(wd, WDCC_IDP, wd->sc_dk.dk_label.d_ncylinders,
1207 wd->sc_dk.dk_label.d_ntracks - 1, 0, wd->sc_dk.dk_label.d_nsectors)
1208 != 0) {
1209 wderror(wd, NULL, "wdsetctlr: geometry upload failed");
1210 return -1;
1211 }
1212
1213 return 0;
1214 }
1215
1216 /*
1217 * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506.
1218 */
1219 int
1220 wd_get_parms(wd)
1221 struct wd_softc *wd;
1222 {
1223 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1224 int i;
1225 char tb[DEV_BSIZE];
1226 int s, error;
1227
1228 /*
1229 * XXX
1230 * The locking done here, and the length of time this may keep the rest
1231 * of the system suspended, is a kluge. This should be rewritten to
1232 * set up a transfer and queue it through wdstart(), but it's called
1233 * infrequently enough that this isn't a pressing matter.
1234 */
1235
1236 s = splbio();
1237
1238 while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
1239 wdc->sc_flags |= WDCF_WANTED;
1240 if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 0) {
1241 splx(s);
1242 return error;
1243 }
1244 }
1245
1246 if (wdcommandshort(wdc, wd->sc_drive, WDCC_IDENTIFY) != 0 ||
1247 wait_for_drq(wdc) != 0) {
1248 /*
1249 * We `know' there's a drive here; just assume it's old.
1250 * This geometry is only used to read the MBR and print a
1251 * (false) attach message.
1252 */
1253 strncpy(wd->sc_dk.dk_label.d_typename, "ST506",
1254 sizeof wd->sc_dk.dk_label.d_typename);
1255 wd->sc_dk.dk_label.d_type = DTYPE_ST506;
1256
1257 strncpy(wd->sc_params.wdp_model, "unknown",
1258 sizeof wd->sc_params.wdp_model);
1259 wd->sc_params.wdp_config = WD_CFG_FIXED;
1260 wd->sc_params.wdp_cylinders = 1024;
1261 wd->sc_params.wdp_heads = 8;
1262 wd->sc_params.wdp_sectors = 17;
1263 wd->sc_params.wdp_maxmulti = 0;
1264 wd->sc_params.wdp_usedmovsd = 0;
1265 wd->sc_params.wdp_capabilities = 0;
1266 } else {
1267 strncpy(wd->sc_dk.dk_label.d_typename, "ESDI/IDE",
1268 sizeof wd->sc_dk.dk_label.d_typename);
1269 wd->sc_dk.dk_label.d_type = DTYPE_ESDI;
1270
1271 /* Read in parameter block. */
1272 insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
1273 bcopy(tb, &wd->sc_params, sizeof(struct wdparams));
1274
1275 /* Shuffle string byte order. */
1276 for (i = 0; i < sizeof(wd->sc_params.wdp_model); i += 2) {
1277 u_short *p;
1278 p = (u_short *)(wd->sc_params.wdp_model + i);
1279 *p = ntohs(*p);
1280 }
1281 }
1282
1283 /* Clear any leftover interrupt. */
1284 (void) inb(wdc->sc_iobase+wd_status);
1285
1286 /* Restart the queue. */
1287 wdcstart(wdc);
1288
1289 splx(s);
1290 return 0;
1291 }
1292
1293 int
1294 wdioctl(dev, cmd, addr, flag, p)
1295 dev_t dev;
1296 u_long cmd;
1297 caddr_t addr;
1298 int flag;
1299 struct proc *p;
1300 {
1301 struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)];
1302 int error;
1303
1304 if ((wd->sc_flags & WDF_LOADED) == 0)
1305 return EIO;
1306
1307 switch (cmd) {
1308 case DIOCSBAD:
1309 if ((flag & FWRITE) == 0)
1310 return EBADF;
1311 wd->sc_dk.dk_cpulabel.bad = *(struct dkbad *)addr;
1312 wd->sc_dk.dk_label.d_flags |= D_BADSECT;
1313 bad144intern(wd);
1314 return 0;
1315
1316 case DIOCGDINFO:
1317 *(struct disklabel *)addr = wd->sc_dk.dk_label;
1318 return 0;
1319
1320 case DIOCGPART:
1321 ((struct partinfo *)addr)->disklab = &wd->sc_dk.dk_label;
1322 ((struct partinfo *)addr)->part =
1323 &wd->sc_dk.dk_label.d_partitions[WDPART(dev)];
1324 return 0;
1325
1326 case DIOCWDINFO:
1327 case DIOCSDINFO:
1328 if ((flag & FWRITE) == 0)
1329 return EBADF;
1330
1331 if (error = wdlock(wd))
1332 return error;
1333 wd->sc_flags |= WDF_LABELLING;
1334
1335 error = setdisklabel(&wd->sc_dk.dk_label,
1336 (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0,
1337 &wd->sc_dk.dk_cpulabel);
1338 if (error == 0) {
1339 if (wd->sc_state > GEOMETRY)
1340 wd->sc_state = GEOMETRY;
1341 if (cmd == DIOCWDINFO)
1342 error = writedisklabel(WDLABELDEV(dev),
1343 wdstrategy, &wd->sc_dk.dk_label,
1344 &wd->sc_dk.dk_cpulabel);
1345 }
1346
1347 wd->sc_flags &= ~WDF_LABELLING;
1348 wdunlock(wd);
1349 return error;
1350
1351 case DIOCWLABEL:
1352 if ((flag & FWRITE) == 0)
1353 return EBADF;
1354 if (*(int *)addr)
1355 wd->sc_flags |= WDF_WLABEL;
1356 else
1357 wd->sc_flags &= ~WDF_WLABEL;
1358 return 0;
1359
1360 #ifdef notyet
1361 case DIOCWFORMAT:
1362 if ((flag & FWRITE) == 0)
1363 return EBADF;
1364 {
1365 register struct format_op *fop;
1366 struct iovec aiov;
1367 struct uio auio;
1368
1369 fop = (struct format_op *)addr;
1370 aiov.iov_base = fop->df_buf;
1371 aiov.iov_len = fop->df_count;
1372 auio.uio_iov = &aiov;
1373 auio.uio_iovcnt = 1;
1374 auio.uio_resid = fop->df_count;
1375 auio.uio_segflg = 0;
1376 auio.uio_offset =
1377 fop->df_startblk * wd->sc_dk.dk_label.d_secsize;
1378 auio.uio_procp = p;
1379 error = physio(wdformat, NULL, dev, B_WRITE, minphys,
1380 &auio);
1381 fop->df_count -= auio.uio_resid;
1382 fop->df_reg[0] = wdc->sc_status;
1383 fop->df_reg[1] = wdc->sc_error;
1384 return error;
1385 }
1386 #endif
1387
1388 default:
1389 return ENOTTY;
1390 }
1391
1392 #ifdef DIAGNOSTIC
1393 panic("wdioctl: impossible");
1394 #endif
1395 }
1396
1397 #ifdef B_FORMAT
1398 int
1399 wdformat(struct buf *bp)
1400 {
1401
1402 bp->b_flags |= B_FORMAT;
1403 return wdstrategy(bp);
1404 }
1405 #endif
1406
1407 int
1408 wdsize(dev)
1409 dev_t dev;
1410 {
1411 struct wd_softc *wd;
1412 int part;
1413 int size;
1414
1415 if (wdopen(dev, 0, S_IFBLK) != 0)
1416 return -1;
1417 wd = wdcd.cd_devs[WDUNIT(dev)];
1418 part = WDPART(dev);
1419 if (wd->sc_dk.dk_label.d_partitions[part].p_fstype != FS_SWAP)
1420 size = -1;
1421 else
1422 size = wd->sc_dk.dk_label.d_partitions[part].p_size;
1423 if (wdclose(dev, 0, S_IFBLK) != 0)
1424 return -1;
1425 return size;
1426 }
1427
1428
1429 #ifndef __BDEVSW_DUMP_OLD_TYPE
1430 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
1431 static int wddoingadump;
1432 static int wddumprecalibrated;
1433
1434 /*
1435 * Dump core after a system crash.
1436 */
1437 int
1438 wddump(dev, blkno, va, size)
1439 dev_t dev;
1440 daddr_t blkno;
1441 caddr_t va;
1442 size_t size;
1443 {
1444 struct wd_softc *wd; /* disk unit to do the I/O */
1445 struct wdc_softc *wdc; /* disk controller to do the I/O */
1446 struct disklabel *lp; /* disk's disklabel */
1447 int unit, part;
1448 int sectorsize; /* size of a disk sector */
1449 int nsects; /* number of sectors in partition */
1450 int sectoff; /* sector offset of partition */
1451 int totwrt; /* total number of sectors left to write */
1452 int nwrt; /* current number of sectors to write */
1453 int retval;
1454
1455 /* Check if recursive dump; if so, punt. */
1456 if (wddoingadump)
1457 return EFAULT;
1458
1459 /* Mark as active early. */
1460 wddoingadump = 1;
1461
1462 unit = WDUNIT(dev); /* decompose unit & partition */
1463 part = WDPART(dev);
1464
1465 /* Check for acceptable drive number. */
1466 if (unit >= wdcd.cd_ndevs || (wd = wdcd.cd_devs[unit]) == NULL)
1467 return ENXIO;
1468
1469 /* Make sure it was initialized. */
1470 if (wd->sc_state < OPEN)
1471 return ENXIO;
1472
1473 /* Remember the controller device, and sanity check */
1474 if ((wdc = (void *)wd->sc_dev.dv_parent) == NULL)
1475 return ENXIO;
1476
1477 /* Convert to disk sectors. Request must be a multiple of size. */
1478 lp = &wd->sc_dk.dk_label;
1479 sectorsize = lp->d_secsize;
1480 if ((size % sectorsize) != 0)
1481 return EFAULT;
1482 totwrt = size / sectorsize;
1483 blkno = dbtob(blkno) / sectorsize; /* blkno in DEV_BSIZE units */
1484
1485 nsects = lp->d_partitions[part].p_size;
1486 sectoff = lp->d_partitions[part].p_offset;
1487
1488 /* Check transfer bounds against partition size. */
1489 if ((blkno < 0) || ((blkno + totwrt) > nsects))
1490 return EINVAL;
1491
1492 /* Offset block number to start of partition. */
1493 blkno += sectoff;
1494
1495 /* Recalibrate, if first dump transfer. */
1496 if (wddumprecalibrated == 0) {
1497 wddumprecalibrated = 1;
1498 if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0 ||
1499 wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 ||
1500 wait_for_ready(wdc) != 0) {
1501 wderror(wd, NULL, "wddump: recal failed");
1502 return EIO;
1503 }
1504 }
1505
1506 while (totwrt > 0) {
1507 long cylin, head, sector;
1508 daddr_t xlt_blkno;
1509
1510 nwrt = 1; /* ouch XXX */
1511 xlt_blkno = blkno;
1512
1513 if ((lp->d_flags & D_BADSECT) != 0) {
1514 long blkdiff;
1515 int i;
1516
1517 for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
1518 blkdiff -= xlt_blkno;
1519 if (blkdiff < 0)
1520 continue;
1521 if (blkdiff == 0) {
1522 /* Replace current block of transfer. */
1523 xlt_blkno = lp->d_secperunit -
1524 lp->d_nsectors - i - 1;
1525 }
1526 break;
1527 }
1528 /* Tranfer is okay now. */
1529 }
1530
1531 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
1532 sector = (xlt_blkno >> 0) & 0xff;
1533 cylin = (xlt_blkno >> 8) & 0xffff;
1534 head = (xlt_blkno >> 24) & 0xf;
1535 head |= WDSD_LBA;
1536 } else {
1537 sector = xlt_blkno % lp->d_nsectors;
1538 sector++; /* Sectors begin with 1, not 0. */
1539 xlt_blkno /= lp->d_nsectors;
1540 head = xlt_blkno % lp->d_ntracks;
1541 xlt_blkno /= lp->d_ntracks;
1542 cylin = xlt_blkno;
1543 head |= WDSD_CHS;
1544 }
1545
1546 #ifndef WD_DUMP_NOT_TRUSTED
1547 if (wdcommand(wd, WDCC_WRITE, cylin, head, sector, 1) != 0 ||
1548 wait_for_drq(wdc) != 0) {
1549 wderror(wd, NULL, "wddump: write failed");
1550 return EIO;
1551 }
1552
1553 outsw(wdc->sc_iobase+wd_data, va, sectorsize / sizeof(short));
1554
1555 /* Check data request (should be done). */
1556 if (wait_for_ready(wdc) != 0) {
1557 wderror(wd, NULL, "wddump: timeout waiting for ready");
1558 return EIO;
1559 }
1560 if (wdc->sc_status & WDCS_DRQ) {
1561 wderror(wd, NULL, "wddump: extra drq");
1562 return EIO;
1563 }
1564 #else /* WD_DUMP_NOT_TRUSTED */
1565 /* Let's just talk about this first... */
1566 printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",
1567 unit, va, cylin, head, sector);
1568 delay(500 * 1000); /* half a second */
1569 #endif
1570
1571 /* update block count */
1572 totwrt -= nwrt;
1573 blkno += nwrt;
1574 va += sectorsize * nwrt;
1575 }
1576 wddoingadump = 0;
1577 return 0;
1578 }
1579 #else /* __BDEVSW_DUMP_NEW_TYPE */
1580 int
1581 wddump(dev, blkno, va, size)
1582 dev_t dev;
1583 daddr_t blkno;
1584 caddr_t va;
1585 size_t size;
1586 {
1587
1588 /* Not implemented. */
1589 return ENXIO;
1590 }
1591 #endif /* __BDEVSW_DUMP_NEW_TYPE */
1592
1593 /*
1594 * Internalize the bad sector table.
1595 */
1596 void
1597 bad144intern(wd)
1598 struct wd_softc *wd;
1599 {
1600 struct dkbad *bt = &wd->sc_dk.dk_cpulabel.bad;
1601 struct disklabel *lp = &wd->sc_dk.dk_label;
1602 int i = 0;
1603
1604 for (; i < 126; i++) {
1605 if (bt->bt_bad[i].bt_cyl == 0xffff)
1606 break;
1607 wd->sc_badsect[i] =
1608 bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
1609 (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
1610 (bt->bt_bad[i].bt_trksec & 0xff);
1611 }
1612 for (; i < 127; i++)
1613 wd->sc_badsect[i] = -1;
1614 }
1615
1616 int
1617 wdcreset(wdc)
1618 struct wdc_softc *wdc;
1619 {
1620 int iobase = wdc->sc_iobase;
1621
1622 /* Reset the device. */
1623 outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
1624 delay(1000);
1625 outb(iobase+wd_ctlr, WDCTL_IDS);
1626 delay(1000);
1627 (void) inb(iobase+wd_error);
1628 outb(iobase+wd_ctlr, WDCTL_4BIT);
1629
1630 if (wait_for_unbusy(wdc) < 0) {
1631 printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
1632 return 1;
1633 }
1634
1635 return 0;
1636 }
1637
1638 void
1639 wdcrestart(arg)
1640 void *arg;
1641 {
1642 struct wdc_softc *wdc = arg;
1643 int s;
1644
1645 s = splbio();
1646 wdcstart(wdc);
1647 splx(s);
1648 }
1649
1650 /*
1651 * Unwedge the controller after an unexpected error. We do this by resetting
1652 * it, marking all drives for recalibration, and stalling the queue for a short
1653 * period to give the reset time to finish.
1654 * NOTE: We use a timeout here, so this routine must not be called during
1655 * autoconfig or dump.
1656 */
1657 void
1658 wdcunwedge(wdc)
1659 struct wdc_softc *wdc;
1660 {
1661 int unit;
1662
1663 untimeout(wdctimeout, wdc);
1664 (void) wdcreset(wdc);
1665
1666 /* Schedule recalibrate for all drives on this controller. */
1667 for (unit = 0; unit < wdcd.cd_ndevs; unit++) {
1668 struct wd_softc *wd = wdcd.cd_devs[unit];
1669 if (!wd || (void *)wd->sc_dev.dv_parent != wdc)
1670 continue;
1671 if (wd->sc_state > RECAL)
1672 wd->sc_state = RECAL;
1673 }
1674
1675 wdc->sc_flags |= WDCF_ERROR;
1676 ++wdc->sc_errors;
1677
1678 /* Wake up in a little bit and restart the operation. */
1679 timeout(wdcrestart, wdc, RECOVERYTIME);
1680 }
1681
1682 int
1683 wdcwait(wdc, mask)
1684 struct wdc_softc *wdc;
1685 int mask;
1686 {
1687 int iobase = wdc->sc_iobase;
1688 int timeout = 0;
1689 u_char status;
1690 extern int cold;
1691
1692 for (;;) {
1693 wdc->sc_status = status = inb(iobase+wd_status);
1694 if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
1695 break;
1696 if (++timeout > WDCNDELAY)
1697 return -1;
1698 delay(WDCDELAY);
1699 }
1700 if (status & WDCS_ERR) {
1701 wdc->sc_error = inb(iobase+wd_error);
1702 return WDCS_ERR;
1703 }
1704 #ifdef WDCNDELAY_DEBUG
1705 /* After autoconfig, there should be no long delays. */
1706 if (!cold && timeout > WDCNDELAY_DEBUG)
1707 printf("%s: warning: busy-wait took %dus\n",
1708 wdc->sc_dev.dv_xname, WDCDELAY * timeout);
1709 #endif
1710 return 0;
1711 }
1712
1713 void
1714 wdctimeout(arg)
1715 void *arg;
1716 {
1717 struct wdc_softc *wdc = (struct wdc_softc *)arg;
1718 int s;
1719
1720 s = splbio();
1721 if ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
1722 wdc->sc_flags &= ~WDCF_ACTIVE;
1723 wderror(wdc, NULL, "lost interrupt");
1724 wdcunwedge(wdc);
1725 } else
1726 wderror(wdc, NULL, "missing untimeout");
1727 splx(s);
1728 }
1729
1730 void
1731 wderror(dev, bp, msg)
1732 void *dev;
1733 struct buf *bp;
1734 char *msg;
1735 {
1736 struct wd_softc *wd = dev;
1737 struct wdc_softc *wdc = dev;
1738
1739 if (bp) {
1740 diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip / DEV_BSIZE,
1741 &wd->sc_dk.dk_label);
1742 printf("\n");
1743 } else
1744 printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname,
1745 msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS);
1746 }
1747