Annotation of sys/arch/vax/mba/hp.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: hp.c,v 1.18 2007/06/07 05:22:32 deraadt Exp $ */
2: /* $NetBSD: hp.c,v 1.22 2000/02/12 16:09:33 ragge Exp $ */
3: /*
4: * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed at Ludd, University of
18: * Lule}, Sweden and its contributors.
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34: /*
35: * Simple device driver routine for massbuss disks.
36: * TODO:
37: * Fix support for Standard DEC BAD144 bad block forwarding.
38: * Be able to to handle soft/hard transfer errors.
39: * Handle non-data transfer interrupts.
40: * Autoconfiguration of disk drives 'on the fly'.
41: * Handle disk media changes.
42: * Dual-port operations should be supported.
43: */
44: #include <sys/param.h>
45: #include <sys/systm.h>
46: #include <sys/device.h>
47: #include <sys/disklabel.h>
48: #include <sys/disk.h>
49: #include <sys/dkio.h>
50: #include <sys/buf.h>
51: #include <sys/stat.h>
52: #include <sys/ioccom.h>
53: #include <sys/fcntl.h>
54: #include <sys/syslog.h>
55: #include <sys/reboot.h>
56:
57: #include <machine/trap.h>
58: #include <machine/pte.h>
59: #include <machine/mtpr.h>
60: #include <machine/cpu.h>
61: #include <machine/rpb.h>
62:
63: #include <vax/mba/mbavar.h>
64: #include <vax/mba/mbareg.h>
65: #include <vax/mba/hpreg.h>
66:
67: #define HPMASK 0xffff
68:
69: struct hp_softc {
70: struct device sc_dev;
71: struct disk sc_disk;
72: struct mba_device sc_md; /* Common struct used by mbaqueue. */
73: int sc_wlabel; /* Disklabel area is writable */
74: int sc_physnr; /* Physical disk number */
75: };
76:
77: int hpmatch(struct device *, struct cfdata *, void *);
78: void hpattach(struct device *, struct device *, void *);
79: void hpstrategy(struct buf *);
80: void hpstart(struct mba_device *);
81: int hpattn(struct mba_device *);
82: enum xfer_action hpfinish(struct mba_device *, int, int *);
83: int hpopen(dev_t, int, int);
84: int hpclose(dev_t, int, int);
85: int hpioctl(dev_t, u_long, caddr_t, int, struct proc *);
86: int hpdump(dev_t, daddr64_t, caddr_t, size_t);
87: int hpread(dev_t, struct uio *);
88: int hpwrite(dev_t, struct uio *);
89: daddr64_t hpsize(dev_t);
90:
91: struct cfattach hp_ca = {
92: sizeof(struct hp_softc), hpmatch, hpattach
93: };
94:
95: extern struct cfdriver hp_cd;
96:
97: /*
98: * Check if this is a disk drive; done by checking type from mbaattach.
99: */
100: int
101: hpmatch(parent, cf, aux)
102: struct device *parent;
103: struct cfdata *cf;
104: void *aux;
105: {
106: struct mba_attach_args *ma = aux;
107:
108: if (cf->cf_loc[MBACF_DRIVE] != MBACF_DRIVE_DEFAULT &&
109: cf->cf_loc[MBACF_DRIVE] != ma->unit)
110: return 0;
111:
112: if (ma->devtyp != MB_RP)
113: return 0;
114:
115: return 1;
116: }
117:
118: /*
119: * Disk drive found; fake a disklabel and try to read the real one.
120: * If the on-disk label can't be read; we lose.
121: */
122: void
123: hpattach(parent, self, aux)
124: struct device *parent, *self;
125: void *aux;
126: {
127: struct hp_softc *sc = (void *)self;
128: struct mba_softc *ms = (void *)parent;
129: struct disklabel *dl;
130: struct mba_attach_args *ma = aux;
131: char *msg;
132:
133: /*
134: * Init the common struct for both the adapter and its slaves.
135: */
136: BUFQ_INIT(&sc->sc_md.md_q);
137: sc->sc_md.md_softc = (void *)sc; /* Pointer to this softc */
138: sc->sc_md.md_mba = (void *)parent; /* Pointer to parent softc */
139: sc->sc_md.md_start = hpstart; /* Disk start routine */
140: sc->sc_md.md_attn = hpattn; /* Disk attention routine */
141: sc->sc_md.md_finish = hpfinish; /* Disk xfer finish routine */
142:
143: ms->sc_md[ma->unit] = &sc->sc_md; /* Per-unit backpointer */
144:
145: sc->sc_physnr = ma->unit;
146: /*
147: * Init and attach the disk structure.
148: */
149: sc->sc_disk.dk_name = sc->sc_dev.dv_xname;
150: disk_attach(&sc->sc_disk);
151:
152: /*
153: * Fake a disklabel to be able to read in the real label.
154: */
155: dl = sc->sc_disk.dk_label;
156:
157: dl->d_secsize = DEV_BSIZE;
158: dl->d_ntracks = 1;
159: dl->d_nsectors = 32;
160: dl->d_secpercyl = 32;
161:
162: /*
163: * Read in label.
164: */
165: if ((msg = readdisklabel(makedev(0, self->dv_unit * 8), hpstrategy,
166: dl, NULL)) != NULL) {
167: /*printf(": %s", msg);*/
168: }
169: printf(": %.*s, size = %d sectors\n",
170: (int)sizeof(dl->d_typename), dl->d_typename, DL_GETDSIZE(dl));
171: /*
172: * check if this was what we booted from.
173: */
174: if ((B_TYPE(bootdev) == BDEV_HP) && (ma->unit == B_UNIT(bootdev)) &&
175: (ms->sc_physnr == B_ADAPTOR(bootdev)))
176: booted_from = self;
177: }
178:
179:
180: void
181: hpstrategy(bp)
182: struct buf *bp;
183: {
184: struct hp_softc *sc;
185: struct buf *gp;
186: int unit, s;
187: struct disklabel *lp;
188:
189: unit = DISKUNIT(bp->b_dev);
190: sc = hp_cd.cd_devs[unit];
191: lp = sc->sc_disk.dk_label;
192:
193: if (bounds_check_with_label(bp, lp, sc->sc_wlabel) <= 0)
194: goto done;
195:
196: bp->b_rawblkno =
197: bp->b_blkno + DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]);
198: bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
199:
200: s = splbio();
201:
202: gp = BUFQ_FIRST(&sc->sc_md.md_q);
203: disksort_cylinder(&sc->sc_md.md_q, bp);
204: if (gp == 0)
205: mbaqueue(&sc->sc_md);
206:
207: splx(s);
208: return;
209:
210: done:
211: bp->b_resid = bp->b_bcount;
212: s = splbio();
213: biodone(bp);
214: splx(s);
215: }
216:
217: /*
218: * Start transfer on given disk. Called from mbastart().
219: */
220: void
221: hpstart(md)
222: struct mba_device *md;
223: {
224: struct hp_softc *sc = md->md_softc;
225: struct mba_regs *mr = md->md_mba->sc_mbareg;
226: volatile struct hp_regs *hr;
227: struct disklabel *lp = sc->sc_disk.dk_label;
228: struct buf *bp = BUFQ_FIRST(&md->md_q);
229: unsigned bn, cn, sn, tn;
230:
231: /*
232: * Collect statistics.
233: */
234: disk_busy(&sc->sc_disk);
235: sc->sc_disk.dk_seek++;
236:
237: hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)];
238:
239: bn = bp->b_rawblkno;
240: if (bn) {
241: cn = bn / lp->d_secpercyl;
242: sn = bn % lp->d_secpercyl;
243: tn = sn / lp->d_nsectors;
244: sn = sn % lp->d_nsectors;
245: } else
246: cn = sn = tn = 0;
247:
248: hr->hp_dc = cn;
249: hr->hp_da = (tn << 8) | sn;
250: if (bp->b_flags & B_READ)
251: hr->hp_cs1 = HPCS_READ; /* GO */
252: else
253: hr->hp_cs1 = HPCS_WRITE;
254: }
255:
256: int
257: hpopen(dev, flag, fmt)
258: dev_t dev;
259: int flag, fmt;
260: {
261: struct hp_softc *sc;
262: int unit, part;
263:
264: unit = DISKUNIT(dev);
265: if (unit >= hp_cd.cd_ndevs)
266: return ENXIO;
267: sc = hp_cd.cd_devs[unit];
268: if (sc == 0)
269: return ENXIO;
270:
271: part = DISKPART(dev);
272:
273: if (part >= sc->sc_disk.dk_label->d_npartitions)
274: return ENXIO;
275:
276: switch (fmt) {
277: case S_IFCHR:
278: sc->sc_disk.dk_copenmask |= (1 << part);
279: break;
280:
281: case S_IFBLK:
282: sc->sc_disk.dk_bopenmask |= (1 << part);
283: break;
284: }
285: sc->sc_disk.dk_openmask =
286: sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
287:
288: return 0;
289: }
290:
291: int
292: hpclose(dev, flag, fmt)
293: dev_t dev;
294: int flag, fmt;
295: {
296: struct hp_softc *sc;
297: int unit, part;
298:
299: unit = DISKUNIT(dev);
300: sc = hp_cd.cd_devs[unit];
301:
302: part = DISKPART(dev);
303:
304: switch (fmt) {
305: case S_IFCHR:
306: sc->sc_disk.dk_copenmask &= ~(1 << part);
307: break;
308:
309: case S_IFBLK:
310: sc->sc_disk.dk_bopenmask &= ~(1 << part);
311: break;
312: }
313: sc->sc_disk.dk_openmask =
314: sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
315:
316: return 0;
317: }
318:
319: int
320: hpioctl(dev, cmd, addr, flag, p)
321: dev_t dev;
322: u_long cmd;
323: caddr_t addr;
324: int flag;
325: struct proc *p;
326: {
327: struct hp_softc *sc = hp_cd.cd_devs[DISKUNIT(dev)];
328: struct disklabel *lp = sc->sc_disk.dk_label;
329: int error;
330:
331: switch (cmd) {
332: case DIOCGDINFO:
333: bcopy(lp, addr, sizeof (struct disklabel));
334: return 0;
335:
336: case DIOCGPART:
337: ((struct partinfo *)addr)->disklab = lp;
338: ((struct partinfo *)addr)->part =
339: &lp->d_partitions[DISKPART(dev)];
340: break;
341:
342: case DIOCSDINFO:
343: if ((flag & FWRITE) == 0)
344: return EBADF;
345:
346: return setdisklabel(lp, (struct disklabel *)addr, 0, 0);
347:
348: case DIOCWDINFO:
349: if ((flag & FWRITE) == 0)
350: error = EBADF;
351: else {
352: sc->sc_wlabel = 1;
353: error = writedisklabel(dev, hpstrategy, lp, 0);
354: sc->sc_wlabel = 0;
355: }
356: return error;
357: case DIOCWLABEL:
358: if ((flag & FWRITE) == 0)
359: return EBADF;
360: sc->sc_wlabel = 1;
361: break;
362:
363: default:
364: printf("hpioctl: command %x\n", (unsigned int)cmd);
365: return ENOTTY;
366: }
367: return 0;
368: }
369:
370: /*
371: * Called when a transfer is finished. Check if transfer went OK,
372: * Return info about what-to-do-now.
373: */
374: enum xfer_action
375: hpfinish(md, mbasr, attn)
376: struct mba_device *md;
377: int mbasr, *attn;
378: {
379: struct hp_softc *sc = md->md_softc;
380: struct buf *bp = BUFQ_FIRST(&md->md_q);
381: volatile struct mba_regs *mr = md->md_mba->sc_mbareg;
382: volatile struct hp_regs *hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)];
383: int er1, er2;
384: volatile int bc; /* to get GCC read whole longword */
385: unsigned byte;
386:
387: er1 = hr->hp_er1 & HPMASK;
388: er2 = hr->hp_er2 & HPMASK;
389: hr->hp_er1 = hr->hp_er2 = 0;
390: hper1:
391: switch (ffs(er1) - 1) {
392: case -1:
393: hr->hp_er1 = 0;
394: goto hper2;
395:
396: case HPER1_DCK: /* Corrected? data read. Just notice. */
397: bc = mr->mba_bc;
398: byte = ~(bc >> 16);
399: diskerr(buf, hp_cd.cd_name, "soft ecc", LOG_PRINTF,
400: btodb(bp->b_bcount - byte), sc->sc_disk.dk_label);
401: er1 &= ~(1<<HPER1_DCK);
402: er1 &= HPMASK;
403: break;
404:
405: default:
406: printf("drive error :%s er1 %x er2 %x\n",
407: sc->sc_dev.dv_xname, er1, er2);
408: hr->hp_er1 = hr->hp_er2 = 0;
409: goto hper2;
410: }
411: goto hper1;
412:
413: hper2:
414: mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN);
415: if (mbasr)
416: printf("massbuss error :%s %x\n",
417: sc->sc_dev.dv_xname, mbasr);
418:
419: BUFQ_FIRST(&md->md_q)->b_resid = 0;
420: disk_unbusy(&sc->sc_disk, BUFQ_FIRST(&md->md_q)->b_bcount,
421: (BUFQ_FIRST(&md->md_q)->b_flags & B_READ));
422: return XFER_FINISH;
423: }
424:
425: /*
426: * Non-data transfer interrupt; like volume change.
427: */
428: int
429: hpattn(md)
430: struct mba_device *md;
431: {
432: struct hp_softc *sc = md->md_softc;
433: struct mba_softc *ms = (void *)sc->sc_dev.dv_parent;
434: struct mba_regs *mr = ms->sc_mbareg;
435: struct hp_regs *hr = (void *)&mr->mba_md[sc->sc_dev.dv_unit];
436: int er1, er2;
437:
438: er1 = hr->hp_er1 & HPMASK;
439: er2 = hr->hp_er2 & HPMASK;
440:
441: printf("%s: Attention! er1 %x er2 %x\n",
442: sc->sc_dev.dv_xname, er1, er2);
443: return 0;
444: }
445:
446:
447: daddr64_t
448: hpsize(dev)
449: dev_t dev;
450: {
451: int size, unit = DISKUNIT(dev);
452: struct hp_softc *sc;
453:
454: if (unit >= hp_cd.cd_ndevs || hp_cd.cd_devs[unit] == 0)
455: return -1;
456:
457: sc = hp_cd.cd_devs[unit];
458: size = DL_GETPSIZE(&sc->sc_disk.dk_label->d_partitions[DISKPART(dev)]) *
459: (sc->sc_disk.dk_label->d_secsize / DEV_BSIZE);
460:
461: return size;
462: }
463:
464: int
465: hpdump(dev, a1, a2, size)
466: dev_t dev;
467: daddr64_t a1;
468: caddr_t a2;
469: size_t size;
470: {
471: printf("hpdump: Not implemented yet.\n");
472: return 0;
473: }
474:
475: int
476: hpread(dev, uio)
477: dev_t dev;
478: struct uio *uio;
479: {
480: return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio));
481: }
482:
483: int
484: hpwrite(dev, uio)
485: dev_t dev;
486: struct uio *uio;
487: {
488: return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio));
489: }
CVSweb