Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / sys / i386 / isa / wd.c
CommitLineData
cae41ec5
WN
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
af359dea
C
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
cae41ec5 23 *
af359dea
C
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)wd.c 7.2 (Berkeley) 5/9/91
cae41ec5 37 */
88b2b5dc 38
af359dea
C
39/* TODO:peel out buffer at low ipl,
40 speed improvement, rewrite to clean code from garbage artifacts */
41
42
cae41ec5
WN
43#include "wd.h"
44#if NWD > 0
cae41ec5
WN
45
46#include "param.h"
47#include "dkbad.h"
48#include "systm.h"
49#include "conf.h"
50#include "file.h"
af359dea 51#include "stat.h"
cae41ec5 52#include "ioctl.h"
af359dea 53#include "disklabel.h"
cae41ec5 54#include "buf.h"
cae41ec5 55#include "uio.h"
af359dea
C
56#include "i386/isa/isa_device.h"
57#include "i386/isa/icu.h"
58#include "i386/isa/wdreg.h"
cae41ec5 59#include "syslog.h"
af359dea 60#include "vm/vm.h"
cae41ec5
WN
61
62#define RETRIES 5 /* number of retries before giving up */
af359dea 63#define MAXTRANSFER 32 /* max size of transfer in page clusters */
cae41ec5 64
af359dea
C
65#define wdctlr(dev) ((minor(dev) & 0x80) >> 7)
66#define wdunit(dev) ((minor(dev) & 0x60) >> 5)
67#define wdpart(dev) ((minor(dev) & 0x1f))
cae41ec5
WN
68
69#define b_cylin b_resid /* cylinder number for doing IO to */
70 /* shares an entry in the buf struct */
71
72/*
73 * Drive states. Used for open and format operations.
74 * States < OPEN (> 0) are transient, during an open operation.
75 * OPENRAW is used for unlabeled disks, and for floppies, to inhibit
76 * bad-sector forwarding.
77 */
78#define RAWDISK 8 /* raw disk operation, no translation*/
79#define ISRAWSTATE(s) (RAWDISK&(s)) /* are we in a raw state? */
80#define DISKSTATE(s) (~RAWDISK&(s)) /* are we in a given state regardless
81 of raw or cooked mode? */
82
83#define CLOSED 0 /* disk is closed. */
84 /* "cooked" disk states */
85#define WANTOPEN 1 /* open requested, not started */
86#define RECAL 2 /* doing restore */
87#define RDLABEL 3 /* reading pack label */
88#define RDBADTBL 4 /* reading bad-sector table */
89#define OPEN 5 /* done with open */
90
91#define WANTOPENRAW (WANTOPEN|RAWDISK) /* raw WANTOPEN */
92#define RECALRAW (RECAL|RAWDISK) /* raw open, doing restore */
93#define OPENRAW (OPEN|RAWDISK) /* open, but unlabeled disk or floppy */
94
95
96/*
97 * The structure of a disk drive.
98 */
99struct disk {
af359dea
C
100 struct disklabel dk_dd; /* device configuration data */
101 long dk_bc; /* byte count left */
102 short dk_skip; /* blocks already transferred */
103 char dk_unit; /* physical unit number */
104 char dk_state; /* control state */
105 u_char dk_status; /* copy of status reg. */
106 u_char dk_error; /* copy of error reg. */
107 short dk_open; /* open/closed refcnt */
108 u_long dk_copenpart; /* character units open on this drive */
109 u_long dk_bopenpart; /* block units open on this drive */
110 u_long dk_openpart; /* all units open on this drive */
111 short dk_wlabel; /* label writable? */
cae41ec5
WN
112};
113
114/*
115 * This label is used as a default when initializing a new or raw disk.
116 * It really only lets us access the first track until we know more.
117 */
118struct disklabel dflt_sizes = {
af359dea 119 DISKMAGIC, DTYPE_ST506, 0, "default", "",
cae41ec5 120 512, /* sector size */
af359dea
C
121 17, /* # of sectors per track */
122 8, /* # of tracks per cylinder */
123 766, /* # of cylinders per unit */
124 17*8, /* # of sectors per cylinder */
125 766*8*17, /* # of sectors per unit */
126 0, /* # of spare sectors per track */
127 0, /* # of spare sectors per cylinder */
128 0, /* # of alt. cylinders per unit */
129 3600, /* rotational speed */
130 1, /* hardware sector interleave */
131 0, /* sector 0 skew, per track */
132 0, /* sector 0 skew, per cylinder */
133 0, /* head switch time, usec */
134 0, /* track-to-track seek, usec */
135 0, /* generic flags */
136 0,0,0,0,0,
137 0,0,0,0,0,
138 DISKMAGIC,
139 0,
140 8,
141 8192,
142 8192,
143
144 {{21600, 0, 0,0,0,0}, /* A=root filesystem */
145 {21600, 40, 0,0,0,0},
146 {660890, 0, 0,0,0,0}, /* C=whole disk */
147 {216000, 80, 0,0,0,0},
148 {0, 0, 0,0,0,0},
149 {0, 0, 0,0,0,0},
150 {0, 0, 0,0,0,0},
151 {399600, 480, 0,0,0,0}}
cae41ec5 152};
d405e6a8 153
cae41ec5
WN
154static struct dkbad dkbad[NWD];
155struct disk wddrives[NWD] = {0}; /* table of units */
156struct buf wdtab = {0};
157struct buf wdutab[NWD] = {0}; /* head of queue per drive */
158struct buf rwdbuf[NWD] = {0}; /* buffers for raw IO */
159long wdxfer[NWD] = {0}; /* count of transfers */
160int writeprotected[NWD] = { 0 };
161int wdprobe(), wdattach(), wdintr();
db8f0de7 162struct isa_driver wddriver = {
cae41ec5
WN
163 wdprobe, wdattach, "wd",
164};
cae41ec5 165\f
db8f0de7 166static wdc;
cae41ec5
WN
167/*
168 * Probe routine
169 */
170wdprobe(dvp)
db8f0de7 171 struct isa_device *dvp;
cae41ec5 172{
db8f0de7 173wdc = dvp->id_iobase;
cae41ec5
WN
174
175#ifdef lint
176 wdintr(0);
177#endif
af359dea 178 /* XXX sorry, needs to be better */
cae41ec5 179 outb(wdc+wd_error, 0x5a) ; /* error register not writable */
cae41ec5 180 outb(wdc+wd_cyl_lo, 0xa5) ; /* but all of cyllo are implemented */
af359dea 181 if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5)
cae41ec5
WN
182 return(1) ;
183 return (0);
184}
185
186/*
187 * attach each drive if possible.
188 */
189wdattach(dvp)
db8f0de7 190 struct isa_device *dvp;
cae41ec5 191{
db8f0de7 192 int unit = dvp->id_unit;
cae41ec5 193
db8f0de7
BJ
194 outb(wdc+wd_ctlr,12);
195 DELAY(1000);
196 outb(wdc+wd_ctlr,8);
cae41ec5
WN
197}
198
199/* Read/write routine for a buffer. Finds the proper unit, range checks
200 * arguments, and schedules the transfer. Does not wait for the transfer
201 * to complete. Multi-page transfers are supported. All I/O requests must
202 * be a multiple of a sector in length.
203 */
204wdstrategy(bp)
205 register struct buf *bp; /* IO operation to perform */
206{
207 register struct buf *dp;
208 register struct disk *du; /* Disk unit to do the IO. */
af359dea
C
209 register struct partition *p;
210 long maxsz, sz;
211 int unit = wdunit(bp->b_dev);
cae41ec5
WN
212 int s;
213
214 if ((unit >= NWD) || (bp->b_blkno < 0)) {
88b2b5dc 215 printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",
cae41ec5 216 unit, bp->b_blkno, bp->b_bcount);
88b2b5dc 217 pg("wd:error in wdstrategy");
cae41ec5
WN
218 bp->b_flags |= B_ERROR;
219 goto bad;
220 }
221 if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {
222 printf("wd%d: write protected\n", unit);
223 goto bad;
224 }
225 du = &wddrives[unit];
226 if (DISKSTATE(du->dk_state) != OPEN)
227 goto q;
af359dea 228#ifdef old
cae41ec5
WN
229 /*
230 * Convert DEV_BSIZE "blocks" to sectors.
231 * Note: doing the conversions this way limits the partition size
232 * to about 8 million sectors (1-8 Gb).
233 */
af359dea
C
234 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize;
235 if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) ||
88b2b5dc 236 bp->b_bcount >= MAXTRANSFER * CLBYTES) {
cae41ec5 237 bp->b_flags |= B_ERROR;
cae41ec5
WN
238 goto bad;
239 }
af359dea
C
240 nblocks = du->dk_dd.d_partitions[part].p_size;
241 cyloff = du->dk_dd.d_partitions[part].p_offset;
242 if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) {
cae41ec5
WN
243 if (blknum == nblocks)
244 bp->b_resid = bp->b_bcount;
245 else
246 bp->b_flags |= B_ERROR;
247 goto bad;
248 }
af359dea
C
249 bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff;
250#else
251 /*
252 * Determine the size of the transfer, and make sure it is
253 * within the boundaries of the partition.
254 */
255 p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)];
256 maxsz = p->p_size;
257 sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
258 if (bp->b_blkno + p->p_offset <= LABELSECTOR &&
259#if LABELSECTOR != 0
260 bp->b_blkno + p->p_offset + sz > LABELSECTOR &&
261#endif
262 (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) {
263 bp->b_error = EROFS;
264 goto bad;
265 }
266 if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
267 /* if exactly at end of disk, return an EOF */
268 if (bp->b_blkno == maxsz) {
269 bp->b_resid = bp->b_bcount;
270 biodone(bp);
271 return;
272 }
273 /* or truncate if part of it fits */
274 sz = maxsz - bp->b_blkno;
275 if (sz <= 0)
276 goto bad;
277 bp->b_bcount = sz << DEV_BSHIFT;
278 }
279 bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl;
280#endif
cae41ec5
WN
281q:
282 dp = &wdutab[unit];
d405e6a8 283 s = splhigh();
cae41ec5
WN
284 disksort(dp, bp);
285 if (dp->b_active == 0)
286 wdustart(du); /* start drive if idle */
287 if (wdtab.b_active == 0)
288 wdstart(s); /* start IO if controller idle */
289 splx(s);
290 return;
291
292bad:
293 bp->b_error = EINVAL;
294 biodone(bp);
295}
296
297/* Routine to queue a read or write command to the controller. The request is
298 * linked into the active list for the controller. If the controller is idle,
299 * the transfer is started.
300 */
301wdustart(du)
302 register struct disk *du;
303{
304 register struct buf *bp, *dp;
305
306 dp = &wdutab[du->dk_unit];
307 if (dp->b_active)
308 return;
309 bp = dp->b_actf;
310 if (bp == NULL)
311 return;
312 dp->b_forw = NULL;
313 if (wdtab.b_actf == NULL) /* link unit into active list */
314 wdtab.b_actf = dp;
315 else
316 wdtab.b_actl->b_forw = dp;
317 wdtab.b_actl = dp;
318 dp->b_active = 1; /* mark the drive as busy */
319}
320
321/*
322 * Controller startup routine. This does the calculation, and starts
323 * a single-sector read or write operation. Called to start a transfer,
324 * or from the interrupt routine to continue a multi-sector transfer.
325 * RESTRICTIONS:
326 * 1. The transfer length must be an exact multiple of the sector size.
327 */
328
d405e6a8
BJ
329static wd_sebyse;
330
cae41ec5
WN
331wdstart()
332{
333 register struct disk *du; /* disk unit for IO */
cae41ec5
WN
334 register struct buf *bp;
335 struct buf *dp;
336 register struct bt_bad *bt_ptr;
337 long blknum, pagcnt, cylin, head, sector;
338 long secpertrk, secpercyl, addr, i;
af359dea 339 int unit, s;
cae41ec5
WN
340
341loop:
342 dp = wdtab.b_actf;
343 if (dp == NULL)
344 return;
345 bp = dp->b_actf;
346 if (bp == NULL) {
347 wdtab.b_actf = dp->b_forw;
348 goto loop;
349 }
af359dea 350 unit = wdunit(bp->b_dev);
cae41ec5
WN
351 du = &wddrives[unit];
352 if (DISKSTATE(du->dk_state) <= RDLABEL) {
353 if (wdcontrol(bp)) {
354 dp->b_actf = bp->av_forw;
355 goto loop; /* done */
356 }
357 return;
358 }
af359dea
C
359 secpertrk = du->dk_dd.d_nsectors;
360 secpercyl = du->dk_dd.d_secpercyl;
cae41ec5
WN
361 /*
362 * Convert DEV_BSIZE "blocks" to sectors.
363 */
af359dea 364 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize
cae41ec5
WN
365 + du->dk_skip;
366#ifdef WDDEBUG
367 if (du->dk_skip == 0) {
368 dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,
369 (bp->b_flags & B_READ) ? "read" : "write",
370 bp->b_bcount, blknum);
371 } else {
d405e6a8 372 dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts));
cae41ec5
WN
373 }
374#endif
375
376 addr = (int) bp->b_un.b_addr;
377 if(du->dk_skip==0) du->dk_bc = bp->b_bcount;
378 cylin = blknum / secpercyl;
379 head = (blknum % secpercyl) / secpertrk;
d405e6a8 380 sector = blknum % secpertrk;
cae41ec5 381 if (DISKSTATE(du->dk_state) == OPEN)
af359dea
C
382 cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset
383 / secpercyl;
cae41ec5 384
cae41ec5
WN
385 /*
386 * See if the current block is in the bad block list.
387 * (If we have one, and not formatting.)
388 */
d405e6a8 389 if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse)
cae41ec5
WN
390 for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
391 if (bt_ptr->bt_cyl > cylin)
392 /* Sorted list, and we passed our cylinder. quit. */
393 break;
394 if (bt_ptr->bt_cyl == cylin &&
395 bt_ptr->bt_trksec == (head << 8) + sector) {
396 /*
397 * Found bad block. Calculate new block addr.
398 * This starts at the end of the disk (skip the
399 * last track which is used for the bad block list),
400 * and works backwards to the front of the disk.
401 */
402#ifdef WDDEBUG
403 dprintf(DDSK,"--- badblock code -> Old = %d; ",
404 blknum);
405#endif
af359dea 406 blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
cae41ec5
WN
407 - (bt_ptr - dkbad[unit].bt_bad) - 1;
408 cylin = blknum / secpercyl;
409 head = (blknum % secpercyl) / secpertrk;
410 sector = blknum % secpertrk;
411#ifdef WDDEBUG
412 dprintf(DDSK, "new = %d\n", blknum);
413#endif
414 break;
415 }
416 }
d405e6a8 417 sector += 1; /* sectors begin with 1, not 0 */
cae41ec5
WN
418
419 wdtab.b_active = 1; /* mark controller active */
420
d405e6a8
BJ
421 if(du->dk_skip==0 || wd_sebyse) {
422 if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512;
423 while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ;
424 /*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/
cae41ec5
WN
425 outb(wdc+wd_precomp, 0xff);
426 /*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/
427 /*if (bp->b_flags & B_FORMAT) {
428 wr(wdc+wd_sector, du->dk_dd.dk_gap3);
429 wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
430 } else {*/
d405e6a8
BJ
431 if(wd_sebyse)
432 outb(wdc+wd_seccnt, 1);
433 else
434 outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512));
cae41ec5
WN
435 outb(wdc+wd_sector, sector);
436
437 outb(wdc+wd_cyl_lo, cylin);
438 outb(wdc+wd_cyl_hi, cylin >> 8);
439
440 /* Set up the SDH register (select drive). */
441 outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
edf6b89d 442 while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
cae41ec5
WN
443
444 /*if (bp->b_flags & B_FORMAT)
445 wr(wdc+wd_command, WDCC_FORMAT);
446 else*/
447 outb(wdc+wd_command,
448 (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
449#ifdef WDDEBUG
d405e6a8
BJ
450 dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n",
451 sector, cylin, head, addr, inb(wdc+wd_altsts));
cae41ec5 452#endif
d405e6a8 453}
cae41ec5
WN
454
455 /* If this is a read operation, just go away until it's done. */
456 if (bp->b_flags & B_READ) return;
457
458 /* Ready to send data? */
af359dea 459 while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);
cae41ec5
WN
460
461 /* ASSUMES CONTIGUOUS MEMORY */
d405e6a8 462 outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
cae41ec5
WN
463 du->dk_bc -= 512;
464}
465
466/*
467 * these are globally defined so they can be found
468 * by the debugger easily in the case of a system crash
469 */
470daddr_t wd_errsector;
471daddr_t wd_errbn;
472unsigned char wd_errstat;
473
474/* Interrupt routine for the controller. Acknowledge the interrupt, check for
475 * errors on the current operation, mark it done if necessary, and start
476 * the next request. Also check for a partially done transfer, and
477 * continue with the next chunk if so.
478 */
af359dea 479wdintr(unit)
cae41ec5
WN
480{
481 register struct disk *du;
cae41ec5
WN
482 register struct buf *bp, *dp;
483 int status;
484 char partch ;
af359dea 485 static wd_haderror;
cae41ec5
WN
486
487 /* Shouldn't need this, but it may be a slow controller. */
af359dea 488 while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
cae41ec5
WN
489 if (!wdtab.b_active) {
490 printf("wd: extra interrupt\n");
491 return;
492 }
493
ceab7d1a 494#ifdef WDDEBUG
cae41ec5
WN
495 dprintf(DDSK,"I ");
496#endif
497 dp = wdtab.b_actf;
498 bp = dp->b_actf;
af359dea
C
499 du = &wddrives[wdunit(bp->b_dev)];
500 partch = wdpart(bp->b_dev) + 'a';
cae41ec5
WN
501 if (DISKSTATE(du->dk_state) <= RDLABEL) {
502 if (wdcontrol(bp))
503 goto done;
504 return;
505 }
506 if (status & (WDCS_ERR | WDCS_ECCCOR)) {
d405e6a8 507 wd_errstat = inb(wdc+wd_error); /* save error status */
cae41ec5 508#ifdef WDDEBUG
d405e6a8 509 printf("status %x error %x\n", status, wd_errstat);
cae41ec5 510#endif
d405e6a8
BJ
511 if(wd_sebyse == 0) {
512 wd_haderror = 1;
513 goto outt;
514 }
cae41ec5
WN
515 /*if (bp->b_flags & B_FORMAT) {
516 du->dk_status = status;
517 du->dk_error = wdp->wd_error;
518 bp->b_flags |= B_ERROR;
519 goto done;
520 }*/
521
af359dea 522 wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +
cae41ec5 523 (((unsigned long) bp->b_blkno * DEV_BSIZE /
af359dea 524 du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +
cae41ec5
WN
525 du->dk_skip;
526 wd_errbn = bp->b_blkno
af359dea 527 + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;
cae41ec5 528 if (status & WDCS_ERR) {
d405e6a8 529 if (++wdtab.b_errcnt < RETRIES) {
cae41ec5 530 wdtab.b_active = 0;
d405e6a8 531 } else {
cae41ec5
WN
532 printf("wd%d%c: ", du->dk_unit, partch);
533 printf(
534 "hard %s error, sn %d bn %d status %b error %b\n",
535 (bp->b_flags & B_READ)? "read":"write",
536 wd_errsector, wd_errbn, status, WDCS_BITS,
537 wd_errstat, WDERR_BITS);
538 bp->b_flags |= B_ERROR; /* flag the error */
539 }
540 } else
541 log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
542 du->dk_unit, partch, wd_errsector,
543 wd_errbn);
544 }
d405e6a8 545outt:
cae41ec5
WN
546
547 /*
548 * If this was a successful read operation, fetch the data.
549 */
550 if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
551 int chk, dummy;
552
d405e6a8 553 chk = min(256,du->dk_bc/2);
cae41ec5 554 /* Ready to receive data? */
af359dea 555 while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
cae41ec5
WN
556
557/*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
558 insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
88b2b5dc 559 du->dk_bc -= 2*chk;
d405e6a8 560 while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
cae41ec5
WN
561 }
562
563 wdxfer[du->dk_unit]++;
564 if (wdtab.b_active) {
565 if ((bp->b_flags & B_ERROR) == 0) {
566 du->dk_skip++; /* Add to successful sectors. */
567 if (wdtab.b_errcnt) {
568 log(LOG_WARNING, "wd%d%c: ",
569 du->dk_unit, partch);
570 log(LOG_WARNING,
571 "soft %s error, sn %d bn %d error %b retries %d\n",
572 (bp->b_flags & B_READ) ? "read" : "write",
573 wd_errsector, wd_errbn, wd_errstat,
574 WDERR_BITS, wdtab.b_errcnt);
575 }
576 wdtab.b_errcnt = 0;
577
578 /* see if more to transfer */
88b2b5dc 579 /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
d405e6a8 580 if (du->dk_bc > 0 && wd_haderror == 0) {
cae41ec5
WN
581 wdstart();
582 return; /* next chunk is started */
d405e6a8
BJ
583 } else if (wd_haderror && wd_sebyse == 0) {
584 du->dk_skip = 0;
585 wd_haderror = 0;
586 wd_sebyse = 1;
587 wdstart();
588 return; /* redo xfer sector by sector */
cae41ec5
WN
589 }
590 }
591
592done:
d405e6a8 593 wd_sebyse = 0;
cae41ec5
WN
594 /* done with this transfer, with or without error */
595 wdtab.b_actf = dp->b_forw;
596 wdtab.b_errcnt = 0;
597 du->dk_skip = 0;
598 dp->b_active = 0;
599 dp->b_actf = bp->av_forw;
600 dp->b_errcnt = 0;
601 bp->b_resid = 0;
602 biodone(bp);
603 }
604 wdtab.b_active = 0;
605 if (dp->b_actf)
606 wdustart(du); /* requeue disk if more io to do */
607 if (wdtab.b_actf)
608 wdstart(); /* start IO on next drive */
609}
610
611/*
612 * Initialize a drive.
613 */
af359dea
C
614wdopen(dev, flags, fmt)
615 dev_t dev;
616 int flags, fmt;
cae41ec5
WN
617{
618 register unsigned int unit;
619 register struct buf *bp;
620 register struct disk *du;
af359dea
C
621 int part = wdpart(dev), mask = 1 << part;
622 struct partition *pp;
cae41ec5
WN
623 struct dkbad *db;
624 int i, error = 0;
625
af359dea 626 unit = wdunit(dev);
cae41ec5
WN
627 if (unit >= NWD) return (ENXIO) ;
628 du = &wddrives[unit];
af359dea 629#ifdef notdef
cae41ec5
WN
630 if (du->dk_open){
631 du->dk_open++ ;
632 return(0); /* already is open, don't mess with it */
633 }
cae41ec5
WN
634#endif
635 du->dk_unit = unit;
636 wdutab[unit].b_actf = NULL;
637 /*if (flags & O_NDELAY)
638 du->dk_state = WANTOPENRAW;
639 else*/
640 du->dk_state = WANTOPEN;
641 /*
642 * Use the default sizes until we've read the label,
643 * or longer if there isn't one there.
644 */
645 du->dk_dd = dflt_sizes;
646
647 /*
648 * Recal, read of disk label will be done in wdcontrol
649 * during first read operation.
650 */
651 bp = geteblk(512);
ceab7d1a 652 bp->b_dev = dev & 0xff00;
af359dea
C
653 bp->b_bcount = 0;
654 bp->b_blkno = LABELSECTOR;
cae41ec5
WN
655 bp->b_flags = B_READ;
656 wdstrategy(bp);
657 biowait(bp);
658 if (bp->b_flags & B_ERROR) {
cae41ec5
WN
659 error = ENXIO;
660 du->dk_state = CLOSED;
661 goto done;
662 }
663 if (du->dk_state == OPENRAW) {
664 du->dk_state = OPENRAW;
665 goto done;
666 }
cae41ec5
WN
667 /*
668 * Read bad sector table into memory.
669 */
670 i = 0;
671 do {
cae41ec5 672 bp->b_flags = B_BUSY | B_READ;
af359dea 673 bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
cae41ec5 674 + i;
af359dea
C
675 if (du->dk_dd.d_secsize > DEV_BSIZE)
676 bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;
cae41ec5 677 else
af359dea
C
678 bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;
679 bp->b_bcount = du->dk_dd.d_secsize;
680 bp->b_cylin = du->dk_dd.d_ncylinders - 1;
cae41ec5
WN
681 wdstrategy(bp);
682 biowait(bp);
683 } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
af359dea 684 i < du->dk_dd.d_nsectors);
cae41ec5 685 db = (struct dkbad *)(bp->b_un.b_addr);
d405e6a8 686#define DKBAD_MAGIC 0x4321
cae41ec5
WN
687 if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
688 db->bt_flag == DKBAD_MAGIC) {
689 dkbad[unit] = *db;
690 du->dk_state = OPEN;
691 } else {
692 printf("wd%d: %s bad-sector file\n", unit,
693 (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
af359dea 694 error = ENXIO ;
cae41ec5
WN
695 du->dk_state = OPENRAW;
696 }
cae41ec5
WN
697done:
698 bp->b_flags = B_INVAL | B_AGE;
699 brelse(bp);
700 if (error == 0)
701 du->dk_open = 1;
af359dea
C
702
703 /*
704 * Warn if a partion is opened
705 * that overlaps another partition which is open
706 * unless one is the "raw" partition (whole disk).
707 */
708#define RAWPART 8 /* 'x' partition */ /* XXX */
709 if ((du->dk_openpart & mask) == 0 && part != RAWPART) {
710 int start, end;
711
712 pp = &du->dk_dd.d_partitions[part];
713 start = pp->p_offset;
714 end = pp->p_offset + pp->p_size;
715 for (pp = du->dk_dd.d_partitions;
716 pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
717 pp++) {
718 if (pp->p_offset + pp->p_size <= start ||
719 pp->p_offset >= end)
720 continue;
721 if (pp - du->dk_dd.d_partitions == RAWPART)
722 continue;
723 if (du->dk_openpart & (1 << (pp -
724 du->dk_dd.d_partitions)))
725 log(LOG_WARNING,
726 "wd%d%c: overlaps open partition (%c)\n",
727 unit, part + 'a',
728 pp - du->dk_dd.d_partitions + 'a');
729 }
730 }
731 if (part >= du->dk_dd.d_npartitions)
732 return (ENXIO);
733 du->dk_openpart |= mask;
734 switch (fmt) {
735 case S_IFCHR:
736 du->dk_copenpart |= mask;
737 break;
738 case S_IFBLK:
739 du->dk_bopenpart |= mask;
740 break;
741 }
cae41ec5
WN
742 return (error);
743}
744
745/*
746 * Implement operations other than read/write.
747 * Called from wdstart or wdintr during opens and formats.
748 * Uses finite-state-machine to track progress of operation in progress.
749 * Returns 0 if operation still in progress, 1 if completed.
750 */
751wdcontrol(bp)
752 register struct buf *bp;
753{
754 register struct disk *du;
cae41ec5
WN
755 register unit;
756 unsigned char stat;
757 int s, cnt;
758 extern int bootdev, cyloffset;
759
af359dea 760 du = &wddrives[wdunit(bp->b_dev)];
cae41ec5
WN
761 unit = du->dk_unit;
762 switch (DISKSTATE(du->dk_state)) {
763
764 tryagainrecal:
765 case WANTOPEN: /* set SDH, step rate, do restore */
766#ifdef WDDEBUG
767 dprintf(DDSK,"wd%d: recal ", unit);
768#endif
769 s = splbio(); /* not called from intr level ... */
770 outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
771 wdtab.b_active = 1;
772 outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
773 du->dk_state++;
774 splx(s);
775 return(0);
776
777 case RECAL:
edf6b89d 778 if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
cae41ec5
WN
779 printf("wd%d: recal", du->dk_unit);
780 if (unit == 0) {
781 printf(": status %b error %b\n",
782 stat, WDCS_BITS,
783 inb(wdc+wd_error), WDERR_BITS);
784 if (++wdtab.b_errcnt < RETRIES)
785 goto tryagainrecal;
786 }
787 goto badopen;
788 }
af359dea
C
789
790 /* some compaq controllers require this ... */
791 wdsetctlr(bp->b_dev, du);
792
cae41ec5
WN
793 wdtab.b_errcnt = 0;
794 if (ISRAWSTATE(du->dk_state)) {
795 du->dk_state = OPENRAW;
796 return(1);
797 }
798retry:
799#ifdef WDDEBUG
800 dprintf(DDSK,"rdlabel ");
801#endif
af359dea 802if( cyloffset < 0 || cyloffset > 8192) cyloffset=0;
cae41ec5 803 /*
af359dea
C
804 * Read in sector LABELSECTOR to get the pack label
805 * and geometry.
cae41ec5
WN
806 */
807 outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
808 outb(wdc+wd_seccnt, 1);
af359dea 809 outb(wdc+wd_sector, LABELSECTOR+1);
cae41ec5
WN
810 /*if (bp->b_dev == bootdev) {
811 (wdc+wd_cyl_lo = cyloffset & 0xff;
812 (wdc+wd_cyl_hi = cyloffset >> 8;
813 } else {
814 (wdc+wd_cyl_lo = 0;
815 (wdc+wd_cyl_hi = 0;
816 }*/
817 outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
818 outb(wdc+wd_cyl_hi, (cyloffset >> 8));
819 outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
820 outb(wdc+wd_command, WDCC_READ);
821 du->dk_state = RDLABEL;
822 return(0);
823
824 case RDLABEL:
825 if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
826 if (++wdtab.b_errcnt < RETRIES)
827 goto retry;
828 printf("wd%d: read label", unit);
829 goto badopen;
830 }
831
832 insw(wdc+wd_data, bp->b_un.b_addr, 256);
833
834 if (((struct disklabel *)
af359dea 835 (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) {
cae41ec5
WN
836 du->dk_dd =
837 * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET);
838 } else {
839 printf("wd%d: bad disk label\n", du->dk_unit);
840 du->dk_state = OPENRAW;
841 }
db8f0de7
BJ
842
843 s = splbio(); /* not called from intr level ... */
af359dea
C
844 while ((stat = inb(wdc+wd_status)) & WDCS_BUSY);
845
846 wdsetctlr(bp->b_dev, du);
847
db8f0de7
BJ
848 outb(wdc+wd_seccnt, 0);
849 splx(s);
850
cae41ec5
WN
851 if (du->dk_state == RDLABEL)
852 du->dk_state = RDBADTBL;
853 /*
854 * The rest of the initialization can be done
855 * by normal means.
856 */
857 return(1);
858
859 default:
af359dea 860 panic("wdcontrol");
cae41ec5
WN
861 }
862 /* NOTREACHED */
863
864badopen:
865 printf(": status %b error %b\n",
866 stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
867 du->dk_state = OPENRAW;
868 return(1);
869}
870
af359dea
C
871wdsetctlr(dev, du) dev_t dev; struct disk *du; {
872 int stat;
873
874 outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders);
875 outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8);
876 outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
877 outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
878 outb(wdc+wd_command, 0x91);
879
880 while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ;
881 stat = inb(wdc+wd_error);
882 return(stat);
883}
884
885/* ARGSUSED */
886wdclose(dev, flags, fmt)
887 dev_t dev;
888 int flags, fmt;
889{
890 register struct disk *du;
cae41ec5 891
af359dea 892 du = &wddrives[wdunit(dev)];
cae41ec5
WN
893 du->dk_open-- ;
894 /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
895}
896
897wdioctl(dev,cmd,addr,flag)
898 dev_t dev;
899 caddr_t addr;
900{
af359dea 901 int unit = wdunit(dev);
cae41ec5
WN
902 register struct disk *du;
903 int error = 0;
904 struct uio auio;
905 struct iovec aiov;
906 /*int wdformat();*/
907
908 du = &wddrives[unit];
909
910 switch (cmd) {
911
912 case DIOCGDINFO:
913 *(struct disklabel *)addr = du->dk_dd;
914 break;
915
af359dea
C
916 case DIOCGPART:
917 ((struct partinfo *)addr)->disklab = &du->dk_dd;
918 ((struct partinfo *)addr)->part =
919 &du->dk_dd.d_partitions[wdpart(dev)];
920 break;
921
922 case DIOCSDINFO:
923 if ((flag & FWRITE) == 0)
924 error = EBADF;
925 else
926 error = setdisklabel(&du->dk_dd,
927 (struct disklabel *)addr,
928 0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/);
929 /*if (error == 0 && dk->dk_state == OPENRAW &&
930 vdreset_drive(vddinfo[unit]))
931 dk->dk_state = OPEN;*/
932 wdsetctlr(dev, du);
933 break;
934
935 case DIOCWLABEL:
936 if ((flag & FWRITE) == 0)
937 error = EBADF;
938 else
939 du->dk_wlabel = *(int *)addr;
940 break;
941
942 case DIOCWDINFO:
943 if ((flag & FWRITE) == 0)
944 error = EBADF;
945 else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
946 0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) {
947 int wlab;
948
949 /*if (error == 0 && dk->dk_state == OPENRAW &&
950 vdreset_drive(vddinfo[unit]))
951 dk->dk_state = OPEN; */
952 wdsetctlr(dev, du);
953
954 /* simulate opening partition 0 so write succeeds */
955 /* dk->dk_openpart |= (1 << 0); /* XXX */
956 wlab = du->dk_wlabel;
957 du->dk_wlabel = 1;
958 error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev));
959 /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/
960 du->dk_wlabel = wlab;
961 }
962 break;
963
964#ifdef notyet
cae41ec5
WN
965 case DIOCGDINFOP:
966 *(struct disklabel **)addr = &(du->dk_dd);
967 break;
968
cae41ec5
WN
969 case DIOCWFORMAT:
970 if ((flag & FWRITE) == 0)
971 error = EBADF;
972 else {
973 register struct format_op *fop;
974
975 fop = (struct format_op *)addr;
976 aiov.iov_base = fop->df_buf;
977 aiov.iov_len = fop->df_count;
978 auio.uio_iov = &aiov;
979 auio.uio_iovcnt = 1;
980 auio.uio_resid = fop->df_count;
981 auio.uio_segflg = 0;
982 auio.uio_offset =
af359dea 983 fop->df_startblk * du->dk_dd.d_secsize;
cae41ec5
WN
984 error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
985 minphys, &auio);
986 fop->df_count -= auio.uio_resid;
987 fop->df_reg[0] = du->dk_status;
988 fop->df_reg[1] = du->dk_error;
989 }
990 break;
991#endif
992
993 default:
994 error = ENOTTY;
995 break;
996 }
997 return (error);
998}
999
1000/*wdformat(bp)
1001 struct buf *bp;
1002{
1003
1004 bp->b_flags |= B_FORMAT;
1005 return (wdstrategy(bp));
1006}*/
1007
1008/*
1009 * Routines to do raw IO for a unit.
1010 */
1011wdread(dev, uio) /* character read routine */
1012 dev_t dev;
1013 struct uio *uio;
1014{
af359dea 1015 int unit = wdunit(dev) ;
cae41ec5
WN
1016
1017 if (unit >= NWD) return(ENXIO);
1018 return(physio(wdstrategy, &rwdbuf[unit], dev, B_READ, minphys, uio));
1019}
1020
1021
1022wdwrite(dev, uio) /* character write routine */
1023 dev_t dev;
1024 struct uio *uio;
1025{
af359dea 1026 int unit = wdunit(dev) ;
cae41ec5
WN
1027
1028 if (unit >= NWD) return(ENXIO);
1029 return(physio(wdstrategy, &rwdbuf[unit], dev, B_WRITE, minphys, uio));
1030}
1031
1032wdsize(dev)
1033 dev_t dev;
1034{
af359dea
C
1035 register unit = wdunit(dev);
1036 register part = wdpart(dev);
cae41ec5
WN
1037 register struct disk *du;
1038 register val ;
1039
cae41ec5 1040 if (unit >= NWD) return(-1);
af359dea
C
1041 if (wddrives[unit].dk_state == 0) {
1042 val = wdopen (dev, 0);
1043 if (val < 0)
1044 return (-1);
1045 }
cae41ec5 1046 du = &wddrives[unit];
af359dea
C
1047 return((int)((u_long)du->dk_dd.d_partitions[part].p_size *
1048 du->dk_dd.d_secsize / 512));
cae41ec5
WN
1049}
1050
af359dea
C
1051extern char *vmmap; /* poor name! */
1052
cae41ec5
WN
1053wddump(dev) /* dump core after a system crash */
1054 dev_t dev;
1055{
cae41ec5 1056 register struct disk *du; /* disk unit to do the IO */
cae41ec5
WN
1057 register struct bt_bad *bt_ptr;
1058 long num; /* number of sectors to write */
af359dea 1059 int unit, part;
cae41ec5 1060 long cyloff, blknum, blkcnt;
af359dea 1061 long cylin, head, sector, stat;
cae41ec5 1062 long secpertrk, secpercyl, nblocks, i;
af359dea
C
1063 char *addr;
1064 extern int Maxmem;
cae41ec5 1065 static wddoingadump = 0 ;
af359dea
C
1066 extern CMAP1;
1067 extern char CADDR1[];
cae41ec5 1068
af359dea
C
1069
1070#ifdef ARGO
1071outb(0x461,0); /* disable failsafe timer */
1072#endif
1073 addr = (char *) 0; /* starting address */
cae41ec5 1074 /* size of memory to dump */
af359dea
C
1075 num = Maxmem;
1076 unit = wdunit(dev); /* eventually support floppies? */
1077 part = wdpart(dev); /* file system */
cae41ec5
WN
1078 /* check for acceptable drive number */
1079 if (unit >= NWD) return(ENXIO);
1080
1081 du = &wddrives[unit];
1082 /* was it ever initialized ? */
1083 if (du->dk_state < OPEN) return (ENXIO) ;
1084
1085 /* Convert to disk sectors */
af359dea 1086 num = (u_long) num * NBPG / du->dk_dd.d_secsize;
cae41ec5
WN
1087
1088 /* check if controller active */
1089 /*if (wdtab.b_active) return(EFAULT); */
1090 if (wddoingadump) return(EFAULT);
1091
af359dea
C
1092 secpertrk = du->dk_dd.d_nsectors;
1093 secpercyl = du->dk_dd.d_secpercyl;
1094 nblocks = du->dk_dd.d_partitions[part].p_size;
1095 cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl;
cae41ec5 1096
af359dea 1097/*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
cae41ec5 1098 /* check transfer bounds against partition size */
af359dea 1099 if ((dumplo < 0) || ((dumplo + num) > nblocks))
cae41ec5
WN
1100 return(EINVAL);
1101
1102 /*wdtab.b_active = 1; /* mark controller active for if we
1103 panic during the dump */
1104 wddoingadump = 1 ; i = 100000 ;
af359dea
C
1105 while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
1106 outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
1107 outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1108 while (inb(wdc+wd_status) & WDCS_BUSY) ;
1109
1110 /* some compaq controllers require this ... */
1111 wdsetctlr(dev, du);
cae41ec5
WN
1112
1113 blknum = dumplo;
1114 while (num > 0) {
1115#ifdef notdef
1116 if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
1117 if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
1118 blkcnt = secpercyl - (blknum % secpercyl);
1119 /* keep transfer within current cylinder */
1120#endif
af359dea 1121 pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE);
cae41ec5
WN
1122
1123 /* compute disk address */
1124 cylin = blknum / secpercyl;
1125 head = (blknum % secpercyl) / secpertrk;
1126 sector = blknum % secpertrk;
88b2b5dc 1127 cylin += cyloff;
cae41ec5 1128
af359dea 1129#ifdef notyet
cae41ec5
WN
1130 /*
1131 * See if the current block is in the bad block list.
1132 * (If we have one.)
1133 */
1134 for (bt_ptr = dkbad[unit].bt_bad;
1135 bt_ptr->bt_cyl != -1; bt_ptr++) {
1136 if (bt_ptr->bt_cyl > cylin)
1137 /* Sorted list, and we passed our cylinder.
1138 quit. */
1139 break;
1140 if (bt_ptr->bt_cyl == cylin &&
1141 bt_ptr->bt_trksec == (head << 8) + sector) {
1142 /*
1143 * Found bad block. Calculate new block addr.
1144 * This starts at the end of the disk (skip the
1145 * last track which is used for the bad block list),
1146 * and works backwards to the front of the disk.
1147 */
af359dea
C
1148 blknum = (du->dk_dd.d_secperunit)
1149 - du->dk_dd.d_nsectors
cae41ec5
WN
1150 - (bt_ptr - dkbad[unit].bt_bad) - 1;
1151 cylin = blknum / secpercyl;
1152 head = (blknum % secpercyl) / secpertrk;
1153 sector = blknum % secpertrk;
1154 break;
1155 }
1156
af359dea
C
1157#endif
1158 sector++; /* origin 1 */
1159
cae41ec5 1160 /* select drive. */
af359dea
C
1161 outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
1162 while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
cae41ec5
WN
1163
1164 /* transfer some blocks */
af359dea
C
1165 outb(wdc+wd_sector, sector);
1166 outb(wdc+wd_seccnt,1);
1167 outb(wdc+wd_cyl_lo, cylin);
1168 outb(wdc+wd_cyl_hi, cylin >> 8);
cae41ec5
WN
1169#ifdef notdef
1170 /* lets just talk about this first...*/
af359dea
C
1171 pg ("sdh 0%o sector %d cyl %d addr 0x%x",
1172 inb(wdc+wd_sdh), inb(wdc+wd_sector),
1173 inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
1174#endif
1175#ifdef ODYSSEUS
1176if(cylin < 46 || cylin > 91)pg("oops");
1177#endif
1178#ifdef PRIAM
1179if(cylin < 40 || cylin > 79)pg("oops");
cae41ec5 1180#endif
af359dea 1181 outb(wdc+wd_command, WDCC_WRITE);
cae41ec5
WN
1182
1183 /* Ready to send data? */
af359dea
C
1184 while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
1185 if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1186
1187 outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
1188 (int) addr += 512;
1189
1190 if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
cae41ec5 1191 /* Check data request (should be done). */
af359dea 1192 if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
cae41ec5
WN
1193
1194 /* wait for completion */
af359dea 1195 for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
cae41ec5 1196 if (i < 0) return (EIO) ;
cae41ec5
WN
1197 }
1198 /* error check the xfer */
af359dea 1199 if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
cae41ec5
WN
1200 /* update block count */
1201 num--;
1202 blknum++ ;
cae41ec5 1203if (num % 100 == 0) printf(".") ;
cae41ec5
WN
1204 }
1205 return(0);
cae41ec5
WN
1206}
1207#endif