|
|
1.1 root 1: /*
2: * Copyright (c) 1988 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Harris Corp.
7: *
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.
23: *
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: * @(#)hd.c 7.12 (Berkeley) 12/16/90
37: */
38:
39: #include "hd.h"
40:
41: #if NHD > 0
42: #include "sys/param.h"
43: #include "sys/buf.h"
44: #include "sys/conf.h"
45: #include "sys/dkstat.h"
46: #include "sys/disklabel.h"
47: #include "sys/file.h"
48: #include "sys/systm.h"
49: #include "sys/vmmac.h"
50: #include "sys/time.h"
51: #include "sys/proc.h"
52: #include "sys/uio.h"
53: #include "sys/syslog.h"
54: #include "sys/kernel.h"
55: #include "sys/ioctl.h"
56: #include "sys/stat.h"
57: #include "sys/errno.h"
58:
59: #include "../include/cpu.h"
60: #include "../include/mtpr.h"
61:
62: #include "../vba/vbavar.h"
63: #include "../vba/hdreg.h"
64:
65: #define b_cylin b_resid
66:
67: #define hdunit(dev) (minor(dev)>>3)
68: #define hdpart(dev) (minor(dev)&0x07)
69: #define hdminor(unit, part) (((unit)<<3)|(part))
70:
71: struct vba_ctlr *hdcminfo[NHDC];
72: struct vba_device *hddinfo[NHD];
73: int hdcprobe(), hdslave(), hdattach(), hddgo(), hdstrategy();
74: long hdstd[] = { 0 };
75: struct vba_driver hdcdriver =
76: { hdcprobe, hdslave, hdattach, hddgo, hdstd, "hd", hddinfo, "hdc", hdcminfo };
77:
78: /*
79: * Per-controller state.
80: */
81: struct hdcsoftc {
82: u_short hdc_flags;
83: #define HDC_INIT 0x01 /* controller initialized */
84: #define HDC_STARTED 0x02 /* start command issued */
85: #define HDC_LOCKED 0x04 /* locked for direct controller access */
86: #define HDC_WAIT 0x08 /* someone needs direct controller access */
87: u_short hdc_wticks; /* timeout */
88: struct master_mcb *hdc_mcbp; /* address of controller mcb */
89: struct registers *hdc_reg; /* base address of i/o regs */
90: struct vb_buf hdc_rbuf; /* vba resources */
91: struct master_mcb hdc_mcb; /* controller mcb */
92: } hdcsoftc[NHDC];
93:
94: #define HDCMAXTIME 20 /* max time for operation, sec. */
95: #define HDCINTERRUPT 0xf0 /* interrupt vector */
96:
97: /*
98: * Per-drive state; probably everything should be "hd_", not "dk_",
99: * but it's not worth it, and dk is a better mnemonic for disk anyway.
100: */
101: struct dksoftc {
102: #ifdef COMPAT_42
103: u_short dk_def_cyl; /* definition track cylinder address */
104: #endif
105: int dk_state; /* open fsm */
106: u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */
107: int dk_wlabel; /* if label sector is writeable */
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: int dk_unit; /* unit# */
112: int dk_ctlr; /* controller# */
113: int dk_format; /* if format program is using disk */
114: struct buf dk_utab; /* i/o queue header */
115: struct disklabel dk_label; /* disklabel for this disk */
116: struct mcb dk_mcb; /* disk mcb */
117: } dksoftc[NHD];
118:
119: /*
120: * Drive states. Used during steps of open/initialization.
121: * States < OPEN (> 0) are transient, during an open operation.
122: * OPENRAW is used for unlabeled disks, to allow format operations.
123: */
124: #define CLOSED 0 /* disk is closed */
125: #define WANTOPEN 1 /* open requested, not started */
126: #define WANTOPENRAW 2 /* open requested, no label */
127: #define RDLABEL 3 /* reading pack label */
128: #define OPEN 4 /* intialized and ready */
129: #define OPENRAW 5 /* open, no label */
130:
131: int hdcwstart, hdcwatch();
132:
133: /* see if the controller is really there, if so, init it. */
134: /* ARGSUSED */
135: hdcprobe(reg, vm)
136: caddr_t reg;
137: /* register */ struct vba_ctlr *vm;
138: {
139: register int br, cvec; /* must be r12, r11 */
140: register struct hdcsoftc *hdc;
141: static struct module_id id;
142: struct pte *dummypte;
143: caddr_t putl;
144:
145: /* initialize the hdc controller structure. */
146: hdc = &hdcsoftc[vm->um_ctlr];
147: if (!vbmemalloc(1, reg, &dummypte, &putl)) {
148: printf("hdc%d: vbmemalloc failed.\n", vm->um_ctlr);
149: return(0);
150: }
151: hdc->hdc_reg = (struct registers *)putl;
152:
153: /*
154: * try and ping the MID register; side effect of wbadaddr is to read
155: * the module id; the controller is bad if it's not an hdc, the hdc's
156: * writeable control store is not loaded, or the hdc failed the
157: * functional integrity test;
158: */
159: if (wbadaddr(&hdc->hdc_reg->module_id, 4,
160: vtoph((struct process *)NULL, &id)))
161: return(0);
162: DELAY(10000);
163: mtpr(PADC, 0);
164: if (id.module_id != (u_char)HDC_MID) {
165: printf("hdc%d: bad module id; id = %x.\n",
166: vm->um_ctlr, id.module_id);
167: return(0);
168: }
169: if (id.code_rev == (u_char)0xff) {
170: printf("hdc%d: micro-code not loaded.\n", vm->um_ctlr);
171: return(0);
172: }
173: if (id.fit != (u_char)0xff) {
174: printf("hdc%d: FIT test failed.\n", vm->um_ctlr);
175: return(0);
176: }
177:
178: /* reset that pup; flag as inited */
179: hdc->hdc_reg->soft_reset = 0;
180: DELAY(1000000);
181: hdc->hdc_flags |= HDC_INIT;
182:
183: /* allocate page tables and i/o buffer. */
184: if (!vbainit(&hdc->hdc_rbuf, MAXPHYS, VB_32BIT|VB_SCATTER)) {
185: printf("hdc%d: vbainit failed\n", vm->um_ctlr);
186: return (0);
187: }
188:
189: /* set pointer to master control block */
190: hdc->hdc_mcbp =
191: (struct master_mcb *)vtoph((struct proc *)NULL, &hdc->hdc_mcb);
192:
193: br = 0x17, cvec = HDCINTERRUPT + vm->um_ctlr; /* XXX */
194: return(sizeof(struct registers));
195: }
196:
197: /* ARGSUSED */
198: hdslave(vi, vdaddr)
199: struct vba_device *vi;
200: struct vddevice *vdaddr;
201: {
202: register struct mcb *mcb;
203: register struct disklabel *lp;
204: register struct dksoftc *dk;
205: static struct status status;
206:
207: dk = &dksoftc[vi->ui_unit];
208: dk->dk_unit = vi->ui_unit;
209: dk->dk_ctlr = vi->ui_ctlr;
210:
211: mcb = &dk->dk_mcb;
212: mcb->command = HCMD_STATUS;
213: mcb->chain[0].wcount = sizeof(struct status) / sizeof(long);
214: mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &status);
215: if (hdimcb(dk)) {
216: printf(" (no status)\n");
217: return(0);
218: }
219:
220: /*
221: * Report the drive down if anything in the drive status looks bad.
222: * If the drive is offline and it is not on cylinder, then the drive
223: * is not there. If there is a fault condition, the hdc will try to
224: * clear it when we read the disklabel information.
225: */
226: if (!(status.drs&DRS_ONLINE)) {
227: if (status.drs&DRS_ON_CYLINDER)
228: printf(" (not online)\n");
229: return(0);
230: }
231: if (status.drs&DRS_FAULT)
232: printf(" (clearing fault)");
233:
234: lp = &dk->dk_label;
235: #ifdef RAW_SIZE
236: lp->d_secsize = status.bytes_per_sec;
237: #else
238: lp->d_secsize = 512;
239: #endif
240: lp->d_nsectors = status.max_sector + 1;
241: lp->d_ntracks = status.max_head + 1;
242: lp->d_ncylinders = status.max_cyl + 1;
243: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
244: lp->d_npartitions = 1;
245: lp->d_partitions[0].p_offset = 0;
246: lp->d_partitions[0].p_size = LABELSECTOR + 1;
247: lp->d_rpm = status.rpm;
248: lp->d_typename[0] = 'h';
249: lp->d_typename[1] = 'd';
250: lp->d_typename[2] = '\0';
251: #ifdef COMPAT_42
252: dk->dk_def_cyl = status.def_cyl;
253: #endif
254: return(1);
255: }
256:
257: hdattach(vi)
258: register struct vba_device *vi;
259: {
260: register struct dksoftc *dk;
261: register struct disklabel *lp;
262: register int unit;
263:
264: unit = vi->ui_unit;
265: if (hdinit(hdminor(unit, 0), 0)) {
266: printf(": unknown drive type");
267: return;
268: }
269: dk = &dksoftc[unit];
270: lp = &dk->dk_label;
271: hd_setsecsize(dk, lp);
272: if (dk->dk_state == OPEN)
273: printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
274: lp->d_typename, lp->d_secsize, lp->d_ntracks,
275: lp->d_ncylinders, lp->d_nsectors);
276:
277: /*
278: * (60 / rpm) / (sectors per track * (bytes per sector / 2))
279: */
280: if (vi->ui_dk >= 0)
281: dk_wpms[vi->ui_dk] =
282: (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;
283: #ifdef notyet
284: addswap(makedev(HDMAJOR, hdminor(unit, 0)), lp);
285: #endif
286: }
287:
288: hdopen(dev, flags, fmt)
289: dev_t dev;
290: int flags, fmt;
291: {
292: register struct disklabel *lp;
293: register struct dksoftc *dk;
294: register struct partition *pp;
295: register int unit;
296: struct vba_device *vi;
297: int s, error, part = hdpart(dev), mask = 1 << part;
298: daddr_t start, end;
299:
300: unit = hdunit(dev);
301: if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0)
302: return(ENXIO);
303: dk = &dksoftc[unit];
304: lp = &dk->dk_label;
305: s = spl7();
306: while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
307: dk->dk_state != CLOSED)
308: if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH,
309: devopn, 0)) {
310: splx(s);
311: return (error);
312: }
313: splx(s);
314: if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
315: if (error = hdinit(dev, flags))
316: return(error);
317:
318: if (hdcwstart == 0) {
319: timeout(hdcwatch, (caddr_t)0, hz);
320: hdcwstart++;
321: }
322: /*
323: * Warn if a partion is opened that overlaps another partition
324: * which is open unless one is the "raw" partition (whole disk).
325: */
326: #define RAWPART 8 /* 'x' partition */ /* XXX */
327: if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
328: pp = &lp->d_partitions[part];
329: start = pp->p_offset;
330: end = pp->p_offset + pp->p_size;
331: for (pp = lp->d_partitions;
332: pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
333: if (pp->p_offset + pp->p_size <= start ||
334: pp->p_offset >= end)
335: continue;
336: if (pp - lp->d_partitions == RAWPART)
337: continue;
338: if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
339: log(LOG_WARNING,
340: "hd%d%c: overlaps open partition (%c)\n",
341: unit, part + 'a',
342: pp - lp->d_partitions + 'a');
343: }
344: }
345: if (part >= lp->d_npartitions)
346: return(ENXIO);
347: dk->dk_openpart |= mask;
348: switch (fmt) {
349: case S_IFCHR:
350: dk->dk_copenpart |= mask;
351: break;
352: case S_IFBLK:
353: dk->dk_bopenpart |= mask;
354: break;
355: }
356: return(0);
357: }
358:
359: /* ARGSUSED */
360: hdclose(dev, flags, fmt)
361: dev_t dev;
362: int flags, fmt;
363: {
364: register struct dksoftc *dk;
365: int mask;
366:
367: dk = &dksoftc[hdunit(dev)];
368: mask = 1 << hdpart(dev);
369: switch (fmt) {
370: case S_IFCHR:
371: dk->dk_copenpart &= ~mask;
372: break;
373: case S_IFBLK:
374: dk->dk_bopenpart &= ~mask;
375: break;
376: }
377: if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
378: dk->dk_openpart &= ~mask;
379: /*
380: * Should wait for i/o to complete on this partition
381: * even if others are open, but wait for work on blkflush().
382: */
383: if (dk->dk_openpart == 0) {
384: int s = spl7();
385: while (dk->dk_utab.b_actf)
386: sleep((caddr_t)dk, PZERO-1);
387: splx(s);
388: dk->dk_state = CLOSED;
389: dk->dk_wlabel = 0;
390: }
391: return(0);
392: }
393:
394: hdinit(dev, flags)
395: dev_t dev;
396: int flags;
397: {
398: register struct dksoftc *dk;
399: register struct disklabel *lp;
400: struct vba_device *vi;
401: int error, unit;
402: char *msg, *readdisklabel();
403: extern int cold;
404:
405: vi = hddinfo[unit = hdunit(dev)];
406: dk = &dksoftc[unit];
407: dk->dk_unit = vi->ui_slave;
408: dk->dk_ctlr = vi->ui_ctlr;
409:
410: if (flags & O_NDELAY) {
411: dk->dk_state = OPENRAW;
412: return(0);
413: }
414:
415: error = 0;
416: lp = &dk->dk_label;
417: dk->dk_state = RDLABEL;
418: if (msg = readdisklabel(dev, hdstrategy, lp)) {
419: if (cold) {
420: printf(": %s\n", msg);
421: dk->dk_state = CLOSED;
422: } else {
423: log(LOG_ERR, "hd%d: %s\n", unit, msg);
424: dk->dk_state = OPENRAW;
425: }
426: #ifdef COMPAT_42
427: hdclock(vi->ui_ctlr);
428: if (!(error = hdreadgeometry(dk)))
429: dk->dk_state = OPEN;
430: hdcunlock(vi->ui_ctlr);
431: #endif
432: } else
433: dk->dk_state = OPEN;
434: wakeup((caddr_t)dk);
435: return(error);
436: }
437:
438: hd_setsecsize(dk, lp)
439: register struct dksoftc *dk;
440: struct disklabel *lp;
441: {
442: register int mul;
443:
444: /*
445: * Calculate scaling shift for mapping
446: * DEV_BSIZE blocks to drive sectors.
447: */
448: mul = DEV_BSIZE / lp->d_secsize;
449: dk->dk_bshift = 0;
450: while ((mul >>= 1) > 0)
451: dk->dk_bshift++;
452: }
453:
454: /* ARGSUSED */
455: hddgo(vm)
456: struct vba_device *vm;
457: {}
458:
459: extern int name_ext;
460: hdstrategy(bp)
461: register struct buf *bp;
462: {
463: register struct vba_device *vi;
464: register struct disklabel *lp;
465: register struct dksoftc *dk;
466: struct buf *dp;
467: register int unit;
468: daddr_t sn, sz, maxsz;
469: int part, s;
470:
471: vi = hddinfo[unit = hdunit(bp->b_dev)];
472: if (unit >= NHD || vi == 0 || vi->ui_alive == 0) {
473: bp->b_error = ENXIO;
474: goto bad;
475: }
476: dk = &dksoftc[unit];
477: if (dk->dk_state < OPEN)
478: goto q;
479: if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
480: bp->b_error = EROFS;
481: goto bad;
482: }
483: part = hdpart(bp->b_dev);
484: if ((dk->dk_openpart & (1 << part)) == 0) {
485: bp->b_error = ENODEV;
486: goto bad;
487: }
488: lp = &dk->dk_label;
489: sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
490: maxsz = lp->d_partitions[part].p_size;
491: sn = bp->b_blkno << dk->dk_bshift;
492: if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
493: #if LABELSECTOR != 0
494: sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
495: #endif
496: (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
497: bp->b_error = EROFS;
498: goto bad;
499: }
500: if (sn < 0 || sn + sz > maxsz) {
501: if (sn == maxsz) {
502: bp->b_resid = bp->b_bcount;
503: goto done;
504: }
505: sz = maxsz - sn;
506: if (sz <= 0) {
507: bp->b_error = EINVAL;
508: goto bad;
509: }
510: bp->b_bcount = sz * lp->d_secsize;
511: }
512: bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
513:
514: q: s = spl7();
515: dp = &dk->dk_utab;
516: disksort(dp, bp);
517: if (!dp->b_active) {
518: (void)hdustart(vi);
519: if (!vi->ui_mi->um_tab.b_active)
520: hdcstart(vi->ui_mi);
521: }
522: splx(s);
523: return;
524: bad:
525: bp->b_flags |= B_ERROR;
526: done:
527: biodone(bp);
528: }
529:
530: hdustart(vi)
531: register struct vba_device *vi;
532: {
533: register struct buf *bp, *dp;
534: register struct vba_ctlr *vm;
535: register struct dksoftc *dk;
536:
537: dk = &dksoftc[vi->ui_unit];
538: dp = &dk->dk_utab;
539:
540: /* if queue empty, nothing to do. impossible? */
541: if (dp->b_actf == NULL)
542: return;
543:
544: /* place on controller transfer queue */
545: vm = vi->ui_mi;
546: if (vm->um_tab.b_actf == NULL)
547: vm->um_tab.b_actf = dp;
548: else
549: vm->um_tab.b_actl->b_forw = dp;
550: vm->um_tab.b_actl = dp;
551: dp->b_forw = NULL;
552: dp->b_active++;
553: }
554:
555: hdcstart(vm)
556: register struct vba_ctlr *vm;
557: {
558: register struct buf *bp;
559: register struct dksoftc *dk;
560: register struct disklabel *lp;
561: register struct master_mcb *master;
562: register struct mcb *mcb;
563: struct vba_device *vi;
564: struct hdcsoftc *hdc;
565: struct buf *dp;
566: int sn;
567:
568: /* pull a request off the controller queue */
569: for (;;) {
570: if ((dp = vm->um_tab.b_actf) == NULL)
571: return;
572: if (bp = dp->b_actf)
573: break;
574: vm->um_tab.b_actf = dp->b_forw;
575: }
576:
577: /* mark controller active */
578: vm->um_tab.b_active++;
579:
580: vi = hddinfo[hdunit(bp->b_dev)];
581: dk = &dksoftc[vi->ui_unit];
582: lp = &dk->dk_label;
583: sn = bp->b_blkno << dk->dk_bshift;
584:
585: /* fill in mcb */
586: mcb = &dk->dk_mcb;
587: mcb->forw_phaddr = 0;
588: /* mcb->priority = 0; */
589: mcb->interrupt = 1;
590: mcb->command = (bp->b_flags & B_READ) ? HCMD_READ:HCMD_WRITE;
591: mcb->cyl = bp->b_cylin;
592: /* assumes partition starts on cylinder boundary */
593: mcb->head = (sn / lp->d_nsectors) % lp->d_ntracks;
594: mcb->sector = sn % lp->d_nsectors;
595: mcb->drive = vi->ui_slave;
596: /* mcb->context = 0; /* what do we want on interrupt? */
597:
598: hdc = &hdcsoftc[vm->um_ctlr];
599: if (!hd_sgsetup(bp, &hdc->hdc_rbuf, mcb->chain)) {
600: mcb->chain[0].wcount = (bp->b_bcount+3) >> 2;
601: mcb->chain[0].memadr =
602: vbasetup(bp, &hdc->hdc_rbuf, (int)lp->d_secsize);
603: }
604:
605: if (vi->ui_dk >= 0) {
606: dk_busy |= 1<<vi->ui_dk;
607: dk_xfer[vi->ui_dk]++;
608: dk_wds[vi->ui_dk] += bp->b_bcount>>6;
609: }
610:
611: master = &hdc->hdc_mcb;
612: master->mcw = MCL_QUEUED;
613: master->interrupt = HDCINTERRUPT + vm->um_ctlr;
614: master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb);
615: hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp;
616: }
617:
618: /*
619: * Wait for controller to finish current operation
620: * so that direct controller accesses can be done.
621: */
622: hdclock(ctlr)
623: int ctlr;
624: {
625: register struct vba_ctlr *vm = hdcminfo[ctlr];
626: register struct hdcsoftc *hdc;
627: int s;
628:
629: hdc = &hdcsoftc[ctlr];
630: s = spl7();
631: while (vm->um_tab.b_active || hdc->hdc_flags & HDC_LOCKED) {
632: hdc->hdc_flags |= HDC_WAIT;
633: sleep((caddr_t)hdc, PRIBIO);
634: }
635: hdc->hdc_flags |= HDC_LOCKED;
636: splx(s);
637: }
638:
639: /*
640: * Continue normal operations after pausing for
641: * munging the controller directly.
642: */
643: hdcunlock(ctlr)
644: int ctlr;
645: {
646: register struct vba_ctlr *vm;
647: register struct hdcsoftc *hdc = &hdcsoftc[ctlr];
648:
649: hdc->hdc_flags &= ~HDC_LOCKED;
650: if (hdc->hdc_flags & HDC_WAIT) {
651: hdc->hdc_flags &= ~HDC_WAIT;
652: wakeup((caddr_t)hdc);
653: } else {
654: vm = hdcminfo[ctlr];
655: if (vm->um_tab.b_actf)
656: hdcstart(vm);
657: }
658: }
659:
660: hdintr(ctlr)
661: int ctlr;
662: {
663: register struct buf *bp, *dp;
664: register struct vba_ctlr *vm;
665: register struct vba_device *vi;
666: register struct hdcsoftc *hdc;
667: register struct mcb *mcb;
668: struct master_mcb *master;
669: register int status;
670: int timedout;
671: struct dksoftc *dk;
672:
673: hdc = &hdcsoftc[ctlr];
674: master = &hdc->hdc_mcb;
675: uncache(&master->mcs);
676: uncache(&master->context);
677:
678: vm = hdcminfo[ctlr];
679: if (!vm->um_tab.b_active || !(master->mcs&MCS_DONE)) {
680: printf("hd%d: stray interrupt\n", ctlr);
681: return;
682: }
683:
684: dp = vm->um_tab.b_actf;
685: bp = dp->b_actf;
686: vi = hddinfo[hdunit(bp->b_dev)];
687: dk = &dksoftc[vi->ui_unit];
688: if (vi->ui_dk >= 0)
689: dk_busy &= ~(1<<vi->ui_dk);
690: timedout = (hdc->hdc_wticks >= HDCMAXTIME);
691:
692: mcb = &dk->dk_mcb;
693:
694: if (master->mcs & (MCS_SOFTERROR | MCS_FATALERROR) || timedout)
695: hdcerror(ctlr, *(u_long *)master->xstatus);
696: else
697: hdc->hdc_wticks = 0;
698: if (vm->um_tab.b_active) {
699: vm->um_tab.b_active = 0;
700: vm->um_tab.b_actf = dp->b_forw;
701: dp->b_active = 0;
702: dp->b_errcnt = 0;
703: dp->b_actf = bp->av_forw;
704: bp->b_resid = 0;
705: vbadone(bp, &hdc->hdc_rbuf);
706: biodone(bp);
707: /* start up now, if more work to do */
708: if (dp->b_actf)
709: hdustart(vi);
710: else if (dk->dk_openpart == 0)
711: wakeup((caddr_t)dk);
712: }
713: /* if there are devices ready to transfer, start the controller. */
714: if (hdc->hdc_flags & HDC_WAIT) {
715: hdc->hdc_flags &= ~HDC_WAIT;
716: wakeup((caddr_t)hdc);
717: } else if (vm->um_tab.b_actf)
718: hdcstart(vm);
719: }
720:
721: hdioctl(dev, cmd, data, flag)
722: dev_t dev;
723: int cmd, flag;
724: caddr_t data;
725: {
726: register int unit;
727: register struct dksoftc *dk;
728: register struct disklabel *lp;
729: int error;
730:
731: unit = hdunit(dev);
732: dk = &dksoftc[unit];
733: lp = &dk->dk_label;
734: error = 0;
735: switch (cmd) {
736: case DIOCGDINFO:
737: *(struct disklabel *)data = *lp;
738: break;
739: case DIOCGPART:
740: ((struct partinfo *)data)->disklab = lp;
741: ((struct partinfo *)data)->part =
742: &lp->d_partitions[hdpart(dev)];
743: break;
744: case DIOCSDINFO:
745: if ((flag & FWRITE) == 0)
746: error = EBADF;
747: else
748: error = setdisklabel(lp, (struct disklabel *)data,
749: (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
750: if (error == 0 && dk->dk_state == OPENRAW)
751: dk->dk_state = OPEN;
752: break;
753: case DIOCWLABEL:
754: if ((flag & FWRITE) == 0)
755: error = EBADF;
756: else
757: dk->dk_wlabel = *(int *)data;
758: break;
759: case DIOCWDINFO:
760: if ((flag & FWRITE) == 0)
761: error = EBADF;
762: else if ((error = setdisklabel(lp, (struct disklabel *)data,
763: (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
764: int wlab;
765:
766: if (error == 0 && dk->dk_state == OPENRAW)
767: dk->dk_state = OPEN;
768: /* simulate opening partition 0 so write succeeds */
769: dk->dk_openpart |= (1 << 0); /* XXX */
770: wlab = dk->dk_wlabel;
771: dk->dk_wlabel = 1;
772: error = writedisklabel(dev, hdstrategy, lp);
773: dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
774: dk->dk_wlabel = wlab;
775: }
776: break;
777: default:
778: error = ENOTTY;
779: break;
780: }
781: return (error);
782: }
783:
784: /*
785: * Watch for lost interrupts.
786: */
787: hdcwatch()
788: {
789: register struct hdcsoftc *hdc;
790: register struct vba_ctlr **vmp;
791: register int ctlr;
792: int s;
793:
794: timeout(hdcwatch, (caddr_t)0, hz);
795: for (vmp = hdcminfo, hdc = hdcsoftc, ctlr = 0; ctlr < NHDC;
796: ++ctlr, ++vmp, ++hdc) {
797: if (*vmp == 0 || (*vmp)->um_alive == 0)
798: continue;
799: s = spl7();
800: if ((*vmp)->um_tab.b_active &&
801: hdc->hdc_wticks++ >= HDCMAXTIME) {
802: printf("hd%d: lost interrupt\n", ctlr);
803: hdintr(ctlr);
804: }
805: splx(s);
806: }
807: }
808:
809: hddump(dev)
810: dev_t dev;
811: {
812: return(ENXIO);
813: }
814:
815: hdsize(dev)
816: dev_t dev;
817: {
818: register int unit = hdunit(dev);
819: register struct dksoftc *dk;
820: struct vba_device *vi;
821: struct disklabel *lp;
822:
823: if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0 ||
824: (dk = &dksoftc[unit])->dk_state != OPEN)
825: return (-1);
826: lp = &dk->dk_label;
827: return ((int)lp->d_partitions[hdpart(dev)].p_size >> dk->dk_bshift);
828: }
829:
830: hdimcb(dk)
831: register struct dksoftc *dk;
832: {
833: register struct master_mcb *master;
834: register struct mcb *mcb;
835: register struct hdcsoftc *hdc;
836: int timeout;
837:
838: /* fill in mcb */
839: mcb = &dk->dk_mcb;
840: mcb->interrupt = 0;
841: mcb->forw_phaddr = 0;
842: mcb->drive = dk->dk_unit;
843:
844: hdc = &hdcsoftc[dk->dk_ctlr];
845: master = &hdc->hdc_mcb;
846:
847: /* fill in master mcb */
848: master->mcw = MCL_IMMEDIATE;
849: master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb);
850: master->mcs = 0;
851:
852: /* kick controller and wait */
853: hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp;
854: for (timeout = 15000; timeout; --timeout) {
855: DELAY(1000);
856: mtpr(PADC, 0);
857: if (master->mcs&MCS_FATALERROR) {
858: printf("hdc%d: fatal error\n", dk->dk_ctlr);
859: hdcerror(dk->dk_ctlr, *(u_long *)master->xstatus);
860: return(1);
861: }
862: if (master->mcs&MCS_DONE)
863: return(0);
864: }
865: printf("hdc%d: timed out\n", dk->dk_ctlr);
866: return(1);
867: }
868:
869: hdcerror(ctlr, code)
870: int ctlr;
871: u_long code;
872: {
873: printf("hd%d: error %lx\n", ctlr, code);
874: }
875:
876: #ifdef COMPAT_42
877: hdreadgeometry(dk)
878: struct dksoftc *dk;
879: {
880: static geometry_sector geometry;
881: register struct mcb *mcb;
882: register struct disklabel *lp;
883: geometry_block *geo;
884: int cnt;
885:
886: /*
887: * Read the geometry block (at head = 0 sector = 0 of the drive
888: * definition cylinder), validate it (must have the correct version
889: * number, header, and checksum).
890: */
891: mcb = &dk->dk_mcb;
892: mcb->command = HCMD_READ;
893: mcb->cyl = dk->dk_def_cyl;
894: mcb->head = 0;
895: mcb->sector = 0;
896: mcb->chain[0].wcount = sizeof(geometry_sector) / sizeof(long);
897: mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &geometry);
898: /* mcb->chain[0].memadr = (long)&geometry; */
899: if (hdimcb(dk)) {
900: printf("hd%d: can't read default geometry.\n", dk->dk_unit);
901: return(1);
902: }
903: geo = &geometry.geometry_block;
904: if (geo->version > 64000 || geo->version < 0) {
905: printf("hd%d: bad default geometry version#.\n", dk->dk_unit);
906: return(1);
907: }
908: if (bcmp(&geo->id[0], GB_ID, GB_ID_LEN)) {
909: printf("hd%d: bad default geometry header.\n", dk->dk_unit);
910: return(1);
911: }
912: GB_CHECKSUM(geo, cnt);
913: if (geometry.checksum != cnt) {
914: printf("hd%d: bad default geometry checksum.\n", dk->dk_unit);
915: return(1);
916: }
917: lp = &dk->dk_label;
918:
919: /* 1K block in Harris geometry; convert to sectors for disklabels */
920: for (cnt = 0; cnt < GB_MAXPART; cnt++) {
921: lp->d_partitions[cnt].p_offset =
922: geo->partition[cnt].start * (1024 / lp->d_secsize);
923: lp->d_partitions[cnt].p_size =
924: geo->partition[cnt].length * (1024 / lp->d_secsize);
925: }
926: lp->d_npartitions = GB_MAXPART;
927: return(0);
928: }
929: #endif /* COMPAT_42 */
930: #endif /* NHD */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.