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