hp.c revision 1.7 1 /* $NetBSD: hp.c,v 1.7 1996/03/17 22:56:38 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/device.h>
45 #include <sys/disklabel.h>
46 #include <sys/disk.h>
47 #include <sys/dkio.h>
48 #include <sys/buf.h>
49 #include <sys/stat.h>
50 #include <sys/ioccom.h>
51 #include <sys/fcntl.h>
52 #include <sys/syslog.h>
53
54 #include <machine/trap.h>
55 #include <machine/pte.h>
56 #include <machine/mtpr.h>
57
58 #include <vax/mba/mbavar.h>
59 #include <vax/mba/mbareg.h>
60 #include <vax/mba/hpreg.h>
61
62 #define HPMASK 0xffff
63
64 struct hp_softc {
65 struct device sc_dev;
66 struct disk sc_disk;
67 struct mba_device sc_md; /* Common struct used by mbaqueue. */
68 int sc_wlabel; /* Disklabel area is writable */
69 int sc_physnr; /* Physical disk number */
70 };
71
72 int hpmatch __P((struct device *, void *, void *));
73 void hpattach __P((struct device *, struct device *, void *));
74 void hpstrategy __P((struct buf *));
75 void hpstart __P((struct mba_device *));
76 int hpattn __P((struct mba_device *));
77 enum xfer_action hpfinish __P((struct mba_device *, int, int *));
78 int hpopen __P((dev_t, int, int));
79 int hpclose __P((dev_t, int, int));
80 int hpioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
81 int hpdump __P((dev_t, caddr_t, caddr_t, size_t));
82 int hpread __P((dev_t, struct uio *));
83 int hpwrite __P((dev_t, struct uio *));
84 int hpsize __P((dev_t));
85
86 struct cfdriver hp_cd = {
87 NULL, "hp", DV_DISK
88 };
89
90 struct cfattach hp_ca = {
91 sizeof(struct hp_softc), hpmatch, hpattach
92 };
93
94 /*
95 * Check if this is a disk drive; done by checking type from mbaattach.
96 */
97 int
98 hpmatch(parent, match, aux)
99 struct device *parent;
100 void *match, *aux;
101 {
102 struct cfdata *cf = match;
103 struct mba_attach_args *ma = aux;
104
105 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ma->unit)
106 return 0;
107
108 if (ma->devtyp != MB_RP)
109 return 0;
110
111 return 1;
112 }
113
114 /*
115 * Disk drive found; fake a disklabel and try to read the real one.
116 * If the on-disk label can't be read; we lose.
117 */
118 void
119 hpattach(parent, self, aux)
120 struct device *parent, *self;
121 void *aux;
122 {
123 struct hp_softc *sc = (void *)self;
124 struct mba_softc *ms = (void *)parent;
125 struct disklabel *dl;
126 struct mba_attach_args *ma = aux;
127 char *msg;
128
129 /*
130 * Init the common struct for both the adapter and its slaves.
131 */
132 sc->sc_md.md_softc = (void *)sc; /* Pointer to this softc */
133 sc->sc_md.md_mba = (void *)parent; /* Pointer to parent softc */
134 sc->sc_md.md_start = hpstart; /* Disk start routine */
135 sc->sc_md.md_attn = hpattn; /* Disk attention routine */
136 sc->sc_md.md_finish = hpfinish; /* Disk xfer finish routine */
137
138 ms->sc_md[ma->unit] = &sc->sc_md; /* Per-unit backpointer */
139
140 sc->sc_physnr = ma->unit;
141 /*
142 * Init and attach the disk structure.
143 */
144 sc->sc_disk.dk_name = sc->sc_dev.dv_xname;
145 disk_attach(&sc->sc_disk);
146
147 /*
148 * Fake a disklabel to be able to read in the real label.
149 */
150 dl = sc->sc_disk.dk_label;
151
152 dl->d_secsize = DEV_BSIZE;
153 dl->d_ntracks = 1;
154 dl->d_nsectors = 32;
155 dl->d_secpercyl = 32;
156
157 /*
158 * Read in label.
159 */
160 if ((msg = readdisklabel(makedev(0, self->dv_unit * 8), hpstrategy,
161 dl, NULL)) != NULL)
162 printf(": %s", msg);
163 printf(": %s, size = %d sectors\n", dl->d_typename, dl->d_secperunit);
164 }
165
166
167 void
168 hpstrategy(bp)
169 struct buf *bp;
170 {
171 struct hp_softc *sc;
172 struct buf *gp;
173 int unit, s;
174
175 unit = DISKUNIT(bp->b_dev);
176 sc = hp_cd.cd_devs[unit];
177
178 if (bounds_check_with_label(bp, sc->sc_disk.dk_label, sc->sc_wlabel)
179 <= 0)
180 goto done;
181 s = splbio();
182
183 gp = sc->sc_md.md_q.b_actf;
184 disksort(&sc->sc_md.md_q, bp);
185 if (gp == 0)
186 mbaqueue(&sc->sc_md);
187
188 splx(s);
189 return;
190
191 done:
192 bp->b_resid = bp->b_bcount;
193 err:
194 biodone(bp);
195 }
196
197 /*
198 * Start transfer on given disk. Called from mbastart().
199 */
200 void
201 hpstart(md)
202 struct mba_device *md;
203 {
204 struct hp_softc *sc = md->md_softc;
205 struct mba_regs *mr = md->md_mba->sc_mbareg;
206 volatile struct hp_regs *hr;
207 struct disklabel *lp = sc->sc_disk.dk_label;
208 struct buf *bp = md->md_q.b_actf;
209 unsigned bn, cn, sn, tn;
210 int part = DISKPART(bp->b_dev);
211
212 /*
213 * Collect statistics.
214 */
215 disk_busy(&sc->sc_disk);
216 sc->sc_disk.dk_seek++;
217
218 hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)];
219
220 bn = bp->b_blkno + lp->d_partitions[part].p_offset;
221 if (bn) {
222 cn = bn / lp->d_secpercyl;
223 sn = bn % lp->d_secpercyl;
224 tn = sn / lp->d_nsectors;
225 sn = sn % lp->d_nsectors;
226 } else
227 cn = sn = tn = 0;
228
229 hr->hp_dc = cn;
230 hr->hp_da = (tn << 8) | sn;
231 if (bp->b_flags & B_READ)
232 hr->hp_cs1 = HPCS_READ; /* GO */
233 else
234 hr->hp_cs1 = HPCS_WRITE;
235 }
236
237 int
238 hpopen(dev, flag, fmt)
239 dev_t dev;
240 int flag, fmt;
241 {
242 struct hp_softc *sc;
243 int unit, part;
244
245 unit = DISKUNIT(dev);
246 if (unit >= hp_cd.cd_ndevs)
247 return ENXIO;
248 sc = hp_cd.cd_devs[unit];
249 if (sc == 0)
250 return ENXIO;
251
252 part = DISKPART(dev);
253
254 if (part >= sc->sc_disk.dk_label->d_npartitions)
255 return ENXIO;
256
257 switch (fmt) {
258 case S_IFCHR:
259 sc->sc_disk.dk_copenmask |= (1 << part);
260 break;
261
262 case S_IFBLK:
263 sc->sc_disk.dk_bopenmask |= (1 << part);
264 break;
265 }
266 sc->sc_disk.dk_openmask =
267 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
268
269 return 0;
270 }
271
272 int
273 hpclose(dev, flag, fmt)
274 dev_t dev;
275 int flag, fmt;
276 {
277 struct hp_softc *sc;
278 int unit, part;
279
280 unit = DISKUNIT(dev);
281 sc = hp_cd.cd_devs[unit];
282
283 part = DISKPART(dev);
284
285 switch (fmt) {
286 case S_IFCHR:
287 sc->sc_disk.dk_copenmask &= ~(1 << part);
288 break;
289
290 case S_IFBLK:
291 sc->sc_disk.dk_bopenmask &= ~(1 << part);
292 break;
293 }
294 sc->sc_disk.dk_openmask =
295 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
296
297 return 0;
298 }
299
300 int
301 hpioctl(dev, cmd, addr, flag, p)
302 dev_t dev;
303 u_long cmd;
304 caddr_t addr;
305 int flag;
306 struct proc *p;
307 {
308 struct hp_softc *sc = hp_cd.cd_devs[DISKUNIT(dev)];
309 struct disklabel *lp = sc->sc_disk.dk_label;
310 int error;
311
312 switch (cmd) {
313 case DIOCGDINFO:
314 bcopy(lp, addr, sizeof (struct disklabel));
315 return 0;
316
317 case DIOCGPART:
318 ((struct partinfo *)addr)->disklab = lp;
319 ((struct partinfo *)addr)->part =
320 &lp->d_partitions[DISKPART(dev)];
321 break;
322
323 case DIOCSDINFO:
324 if ((flag & FWRITE) == 0)
325 return EBADF;
326
327 return setdisklabel(lp, (struct disklabel *)addr, 0, 0);
328
329 case DIOCWDINFO:
330 if ((flag & FWRITE) == 0)
331 error = EBADF;
332 else {
333 sc->sc_wlabel = 1;
334 error = writedisklabel(dev, hpstrategy, lp, 0);
335 sc->sc_wlabel = 0;
336 }
337 return error;
338 case DIOCWLABEL:
339 if ((flag & FWRITE) == 0)
340 return EBADF;
341 sc->sc_wlabel = 1;
342 break;
343
344 default:
345 printf("hpioctl: command %x\n", cmd);
346 return ENOTTY;
347 }
348 return 0;
349 }
350
351 /*
352 * Called when a transfer is finished. Check if transfer went OK,
353 * Return info about what-to-do-now.
354 */
355 enum xfer_action
356 hpfinish(md, mbasr, attn)
357 struct mba_device *md;
358 int mbasr, *attn;
359 {
360 struct hp_softc *sc = md->md_softc;
361 struct buf *bp = md->md_q.b_actf;
362 volatile struct mba_regs *mr = md->md_mba->sc_mbareg;
363 volatile struct hp_regs *hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)];
364 int er1, er2;
365 volatile int bc; /* to get GCC read whole longword */
366 unsigned byte;
367
368 er1 = hr->hp_er1 & HPMASK;
369 er2 = hr->hp_er2 & HPMASK;
370 hr->hp_er1 = hr->hp_er2 = 0;
371 hper1:
372 switch (ffs(er1) - 1) {
373 case -1:
374 hr->hp_er1 = 0;
375 goto hper2;
376
377 case HPER1_DCK: /* Corrected? data read. Just notice. */
378 bc = mr->mba_bc;
379 byte = ~(bc >> 16);
380 diskerr(buf, hp_cd.cd_name, "soft ecc", LOG_PRINTF,
381 btodb(bp->b_bcount - byte), sc->sc_disk.dk_label);
382 er1 &= ~(1<<HPER1_DCK);
383 er1 &= HPMASK;
384 break;
385
386 default:
387 printf("drive error :%s er1 %x er2 %x\n",
388 sc->sc_dev.dv_xname, er1, er2);
389 hr->hp_er1 = hr->hp_er2 = 0;
390 goto hper2;
391 }
392 goto hper1;
393
394 hper2:
395 mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN);
396 if (mbasr)
397 printf("massbuss error :%s %x\n",
398 sc->sc_dev.dv_xname, mbasr);
399
400 md->md_q.b_actf->b_resid = 0;
401 disk_unbusy(&sc->sc_disk, md->md_q.b_actf->b_bcount);
402 return XFER_FINISH;
403 }
404
405 /*
406 * Non-data transfer interrupt; like volume change.
407 */
408 int
409 hpattn(md)
410 struct mba_device *md;
411 {
412 struct hp_softc *sc = md->md_softc;
413 struct mba_softc *ms = (void *)sc->sc_dev.dv_parent;
414 struct mba_regs *mr = ms->sc_mbareg;
415 struct hp_regs *hr = (void *)&mr->mba_md[sc->sc_dev.dv_unit];
416 int er1, er2;
417
418 er1 = hr->hp_er1 & HPMASK;
419 er2 = hr->hp_er2 & HPMASK;
420
421 printf("%s: Attention! er1 %x er2 %x\n",
422 sc->sc_dev.dv_xname, er1, er2);
423 return 0;
424 }
425
426
427 int
428 hpsize(dev)
429 dev_t dev;
430 {
431 int size, unit = DISKUNIT(dev);
432 struct hp_softc *sc;
433
434 if (unit >= hp_cd.cd_ndevs || hp_cd.cd_devs[unit] == 0)
435 return -1;
436
437 sc = hp_cd.cd_devs[unit];
438 size = sc->sc_disk.dk_label->d_partitions[DISKPART(dev)].p_size;
439
440 return size;
441 }
442
443 int
444 hpdump(dev, a1, a2, size)
445 dev_t dev;
446 caddr_t a1, a2;
447 size_t size;
448 {
449 printf("hpdump: Not implemented yet.\n");
450 }
451
452 int
453 hpread(dev, uio)
454 dev_t dev;
455 struct uio *uio;
456 {
457 return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio));
458 }
459
460 int
461 hpwrite(dev, uio)
462 dev_t dev;
463 struct uio *uio;
464 {
465 return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio));
466 }
467
468 /*
469 * Convert physical adapternr and unit to the unit number used by kernel.
470 */
471 int
472 hp_getdev(mbanr, unit)
473 int mbanr, unit;
474 {
475 struct mba_softc *ms;
476 struct hp_softc *sc;
477 int i;
478
479 for (i = 0; i < hp_cd.cd_ndevs; i++) {
480 if (hp_cd.cd_devs[i] == 0)
481 continue;
482
483 sc = hp_cd.cd_devs[i];
484 ms = (void *)sc->sc_dev.dv_parent;
485 if (ms->sc_physnr == mbanr && sc->sc_physnr == unit)
486 return i;
487 }
488 return -1;
489 }
490
491