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