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