Annotation of sys/arch/sparc/dev/presto.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: presto.c,v 1.13 2007/06/20 18:15:47 deraadt Exp $ */
2: /*
3: * Copyright (c) 2003, Miodrag Vallat.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25: * POSSIBILITY OF SUCH DAMAGE.
26: *
27: */
28:
29: #include <sys/param.h>
30: #include <sys/systm.h>
31: #include <sys/buf.h>
32: #include <sys/device.h>
33: #include <sys/ioctl.h>
34: #include <sys/conf.h>
35: #include <sys/disk.h>
36: #include <sys/disklabel.h>
37: #include <sys/dkio.h>
38: #include <sys/fcntl.h>
39: #include <sys/stat.h>
40:
41: #include <machine/autoconf.h>
42: #include <machine/conf.h>
43:
44: #include <sparc/dev/sbusvar.h>
45:
46: struct presto_softc {
47: struct device sc_dev;
48: struct disk sc_dk;
49:
50: vsize_t sc_memsize; /* total NVRAM size */
51: caddr_t sc_mem; /* NVRAM kva */
52: char sc_model[16]; /* Prestoserve model */
53: };
54:
55: /*
56: * The beginning of the NVRAM contains a few control and status values
57: */
58:
59: #define PSERVE_BATTERYSTATUS 0x07
60: #define PSBAT_CHARGING 0x10
61: #define PSBAT_CONNECTED 0x20
62: #define PSBAT_FAULT 0x40
63:
64: #define PSERVE_DATASTATUS 0x0b
65: #define PSDATA_EMPTY 0x00
66: #define PSDATA_SAVED 0x01
67:
68: /* reserved area size - needs to be rounded to a sector size for i/o */
69: #define PSERVE_RESERVED 0x0010
70: #define PSERVE_OFFSET roundup(PSERVE_RESERVED, DEV_BSIZE)
71:
72: void prestostrategy(struct buf *);
73: void presto_attach(struct device *, struct device *, void *);
74: void presto_getdisklabel(dev_t, struct presto_softc *);
75: int presto_match(struct device *, void *, void *);
76:
77: struct cfattach presto_ca = {
78: sizeof(struct presto_softc), presto_match, presto_attach
79: };
80:
81: struct cfdriver presto_cd = {
82: NULL, "presto", DV_DULL
83: };
84:
85: struct dkdriver presto_dk = {
86: prestostrategy,
87: };
88:
89: int
90: presto_match(struct device *parent, void *vcf, void *aux)
91: {
92: struct confargs *ca = aux;
93: struct romaux *ra = &ca->ca_ra;
94:
95: if (strcmp(ra->ra_name, "MMI,prestoserve") != 0)
96: return (0);
97:
98: if (ra->ra_len < PSERVE_OFFSET) /* no usable memory ? */
99: return (0);
100:
101: return (1);
102: }
103:
104: void
105: presto_attach(struct device *parent, struct device *self, void *args)
106: {
107: struct presto_softc *sc = (struct presto_softc *)self;
108: struct confargs *ca = args;
109: char *model, *submodel;
110: u_int8_t status;
111:
112: /* Get card parameters */
113: model = getpropstring(ca->ca_ra.ra_node, "model");
114: if (*model == '\0')
115: submodel = "fictitious";
116: else {
117: submodel = memchr(model, ',', strlen(model));
118: if (submodel != NULL)
119: submodel++;
120: else
121: submodel = model;
122: }
123: strncpy(sc->sc_model, submodel, 16);
124: sc->sc_memsize = ca->ca_ra.ra_len;
125:
126: printf(": %s\n%s: %d MB NVRAM, ", model,
127: sc->sc_dev.dv_xname, sc->sc_memsize >> 20);
128:
129: /* Map memory */
130: sc->sc_mem = (void *)mapiodev(ca->ca_ra.ra_reg, 0, sc->sc_memsize);
131:
132: /*
133: * Clear the ``disconnect battery'' bit.
134: */
135: *(u_int8_t *)(sc->sc_mem + PSERVE_BATTERYSTATUS) = 0x00;
136:
137: /*
138: * Clear the ``unflushed data'' status. This way, if the card is
139: * reused under SunOS, the system will not try to flush whatever
140: * data the user put in the nvram...
141: */
142: *(u_int8_t *)(sc->sc_mem + PSERVE_DATASTATUS) = 0x00;
143:
144: /*
145: * Decode battery status
146: */
147: status = *(u_int8_t *)(sc->sc_mem + PSERVE_BATTERYSTATUS);
148: printf("battery status %x ", status);
149: if (ISSET(status, PSBAT_FAULT)) {
150: printf("(non-working)");
151: } else if (ISSET(status, PSBAT_CONNECTED)) {
152: if (ISSET(status, PSBAT_CHARGING))
153: printf("(charging)");
154: else
155: printf("(ok)");
156: } else
157: printf("(disabled)");
158: printf("\n");
159:
160: #ifdef DEBUG
161: printf("%s: status codes %02.2x, %02.2x, %02.2x, %02.2x\n",
162: sc->sc_dev.dv_xname,
163: *(u_int8_t *)(sc->sc_mem + 0x03), *(u_int8_t *)(sc->sc_mem + 0x07),
164: *(u_int8_t *)(sc->sc_mem + 0x0b), *(u_int8_t *)(sc->sc_mem + 0x0f));
165: #endif
166:
167: sc->sc_dk.dk_driver = &presto_dk;
168: sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
169: disk_attach(&sc->sc_dk);
170: }
171:
172: /*
173: * Block device i/o operations
174: */
175:
176: int
177: prestodump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
178: {
179: /*
180: * A dump to nvram is theoretically possible, but its size is
181: * very likely to be WAY too small.
182: */
183: return (ENXIO);
184: }
185:
186: daddr64_t
187: prestosize(dev_t dev)
188: {
189: struct presto_softc *sc;
190: int unit, part;
191:
192: unit = DISKUNIT(dev);
193: sc = (struct presto_softc *)device_lookup(&presto_cd, unit);
194: if (sc == NULL)
195: return (0);
196:
197: part = DISKPART(dev);
198: if (part >= sc->sc_dk.dk_label->d_npartitions)
199: return (0);
200: else
201: return (DL_GETPSIZE(&sc->sc_dk.dk_label->d_partitions[part]) *
202: (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE));
203: }
204:
205: int
206: prestoopen(dev_t dev, int flag, int fmt, struct proc *proc)
207: {
208: int unit, part;
209: struct presto_softc *sc;
210:
211: unit = DISKUNIT(dev);
212: sc = (struct presto_softc *)device_lookup(&presto_cd, unit);
213: if (sc == NULL)
214: return (ENXIO);
215:
216: /* read the disk label */
217: presto_getdisklabel(dev, sc);
218:
219: /* only allow valid partitions */
220: part = DISKPART(dev);
221: if (part != RAW_PART &&
222: (part >= sc->sc_dk.dk_label->d_npartitions ||
223: sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED))
224: return (ENXIO);
225:
226: /* update open masks */
227: switch (fmt) {
228: case S_IFCHR:
229: sc->sc_dk.dk_copenmask |= (1 << part);
230: break;
231: case S_IFBLK:
232: sc->sc_dk.dk_bopenmask |= (1 << part);
233: break;
234: }
235: sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
236:
237: return (0);
238: }
239:
240: int
241: prestoclose(dev_t dev, int flag, int fmt, struct proc *proc)
242: {
243: int unit, part;
244: struct presto_softc *sc;
245:
246: unit = DISKUNIT(dev);
247: sc = (struct presto_softc *)device_lookup(&presto_cd, unit);
248:
249: /* update open masks */
250: part = DISKPART(dev);
251: switch (fmt) {
252: case S_IFCHR:
253: sc->sc_dk.dk_copenmask &= ~(1 << part);
254: break;
255: case S_IFBLK:
256: sc->sc_dk.dk_bopenmask &= ~(1 << part);
257: break;
258: }
259: sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
260:
261: return (0);
262: }
263:
264: int
265: prestoread(dev_t dev, struct uio *uio, int flags)
266: {
267: return (physio(prestostrategy, NULL, dev, B_READ, minphys, uio));
268: }
269:
270: int
271: prestowrite(dev_t dev, struct uio *uio, int flags)
272: {
273: return (physio(prestostrategy, NULL, dev, B_WRITE, minphys, uio));
274: }
275:
276: void
277: prestostrategy(struct buf *bp)
278: {
279: int unit, part;
280: struct presto_softc *sc;
281: size_t offset, count;
282: int s;
283:
284: unit = DISKUNIT(bp->b_dev);
285: sc = (struct presto_softc *)device_lookup(&presto_cd, unit);
286:
287: /* Sort rogue requests out */
288: if (sc == NULL || bp->b_blkno < 0 ||
289: (bp->b_bcount % sc->sc_dk.dk_label->d_secsize) != 0) {
290: bp->b_error = EINVAL;
291: goto bad;
292: }
293:
294: /* Do not write on "no trespassing" areas... */
295: part = DISKPART(bp->b_dev);
296: if (part != RAW_PART &&
297: bounds_check_with_label(bp, sc->sc_dk.dk_label, 1) <= 0)
298: goto bad;
299:
300: /* Bound the request size, then move data between buf and nvram */
301: bp->b_resid = bp->b_bcount;
302: offset = (bp->b_blkno << DEV_BSHIFT) + PSERVE_OFFSET;
303: count = bp->b_bcount;
304: if (count > (sc->sc_memsize - offset))
305: count = (sc->sc_memsize - offset);
306: if (ISSET(bp->b_flags, B_READ))
307: bcopy(sc->sc_mem + offset, bp->b_data, count);
308: else
309: bcopy(bp->b_data, sc->sc_mem + offset, count);
310: bp->b_resid -= count;
311: goto done;
312:
313: bad:
314: bp->b_flags |= B_ERROR;
315: bp->b_resid = bp->b_bcount;
316:
317: done:
318: s = splbio();
319: biodone(bp);
320: splx(s);
321: }
322:
323: int
324: prestoioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *proc)
325: {
326: struct presto_softc *sc;
327: int unit;
328: int error;
329:
330: unit = DISKUNIT(dev);
331: sc = (struct presto_softc *)device_lookup(&presto_cd, unit);
332:
333: switch (cmd) {
334: case DIOCGDINFO:
335: bcopy(sc->sc_dk.dk_label, data, sizeof(struct disklabel));
336: return (0);
337:
338: case DIOCSDINFO:
339: if ((flag & FWRITE) == 0)
340: return (EBADF);
341:
342: error = setdisklabel(sc->sc_dk.dk_label,
343: (struct disklabel *)data, /*sd->sc_dk.dk_openmask : */0);
344: return (error);
345:
346: case DIOCWDINFO:
347: if ((flag & FWRITE) == 0)
348: return (EBADF);
349:
350: error = setdisklabel(sc->sc_dk.dk_label,
351: (struct disklabel *)data, /*sd->sc_dk.dk_openmask : */0);
352: if (error == 0) {
353: error = writedisklabel(DISKLABELDEV(dev),
354: prestostrategy, sc->sc_dk.dk_label);
355: }
356:
357: return (error);
358: default:
359: return (EINVAL);
360: }
361: }
362:
363: /*
364: * Read the disklabel. If none is present, use a fictitious one instead.
365: */
366: void
367: presto_getdisklabel(dev_t dev, struct presto_softc *sc)
368: {
369: struct disklabel *lp = sc->sc_dk.dk_label;
370:
371: bzero(sc->sc_dk.dk_label, sizeof(struct disklabel));
372:
373: lp->d_secsize = DEV_BSIZE;
374: lp->d_ntracks = 1;
375: lp->d_nsectors = 32;
376: DL_SETDSIZE(lp, (sc->sc_memsize - PSERVE_OFFSET) >> DEV_BSHIFT);
377: lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_nsectors;
378: lp->d_secpercyl = lp->d_nsectors;
379:
380: strncpy(lp->d_typename, "Prestoserve", 16);
381: lp->d_type = DTYPE_SCSI; /* what better to put here? */
382: strncpy(lp->d_packname, sc->sc_model, 16);
383: lp->d_rpm = 3600;
384: lp->d_interleave = 1;
385: lp->d_version = 1;
386:
387: lp->d_magic = DISKMAGIC;
388: lp->d_magic2 = DISKMAGIC;
389: lp->d_checksum = dkcksum(lp);
390:
391: readdisklabel(DISKLABELDEV(dev), prestostrategy, sc->sc_dk.dk_label, 0);
392: }
CVSweb