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