xref: /netbsd-src/sys/arch/vax/mba/hp.c (revision 37b34d511dea595d3ba03a661cf3b775038ea5f8)
1 /*	$NetBSD: hp.c,v 1.29 2002/10/02 16:02:33 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 #include <sys/conf.h>
56 
57 #include <machine/bus.h>
58 #include <machine/trap.h>
59 #include <machine/pte.h>
60 #include <machine/mtpr.h>
61 #include <machine/cpu.h>
62 
63 #include <vax/mba/mbavar.h>
64 #include <vax/mba/mbareg.h>
65 #include <vax/mba/hpreg.h>
66 
67 #include "ioconf.h"
68 #include "locators.h"
69 
70 struct	hp_softc {
71 	struct	device	sc_dev;
72 	struct	disk sc_disk;
73 	bus_space_tag_t sc_iot;
74 	bus_space_handle_t sc_ioh;
75 	struct	mba_device sc_md;	/* Common struct used by mbaqueue. */
76 	int	sc_wlabel;		/* Disklabel area is writable */
77 };
78 
79 int     hpmatch(struct device *, struct cfdata *, void *);
80 void    hpattach(struct device *, struct device *, void *);
81 void	hpstart(struct mba_device *);
82 int	hpattn(struct mba_device *);
83 enum	xfer_action hpfinish(struct mba_device *, int, int *);
84 
85 CFATTACH_DECL(hp, sizeof(struct hp_softc),
86     hpmatch, hpattach, NULL, NULL);
87 
88 dev_type_open(hpopen);
89 dev_type_close(hpclose);
90 dev_type_read(hpread);
91 dev_type_write(hpwrite);
92 dev_type_ioctl(hpioctl);
93 dev_type_strategy(hpstrategy);
94 dev_type_size(hpsize);
95 
96 const struct bdevsw hp_bdevsw = {
97 	hpopen, hpclose, hpstrategy, hpioctl, nulldump, hpsize, D_DISK
98 };
99 
100 const struct cdevsw hp_cdevsw = {
101 	hpopen, hpclose, hpread, hpwrite, hpioctl,
102 	nostop, notty, nopoll, nommap, D_DISK
103 };
104 
105 #define HP_WCSR(reg, val) \
106 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
107 #define HP_RCSR(reg) \
108 	bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
109 
110 
111 /*
112  * Check if this is a disk drive; done by checking type from mbaattach.
113  */
114 int
115 hpmatch(struct device *parent, struct cfdata *cf, void *aux)
116 {
117 	struct	mba_attach_args *ma = aux;
118 
119 	if (cf->cf_loc[MBACF_DRIVE] != MBACF_DRIVE_DEFAULT &&
120 	    cf->cf_loc[MBACF_DRIVE] != ma->ma_unit)
121 		return 0;
122 
123 	if (ma->ma_devtyp != MB_RP)
124 		return 0;
125 
126 	return 1;
127 }
128 
129 /*
130  * Disk drive found; fake a disklabel and try to read the real one.
131  * If the on-disk label can't be read; we lose.
132  */
133 void
134 hpattach(struct device *parent, struct device *self, void *aux)
135 {
136 	struct	hp_softc *sc = (void *)self;
137 	struct	mba_softc *ms = (void *)parent;
138 	struct	disklabel *dl;
139 	struct  mba_attach_args *ma = aux;
140 	char	*msg;
141 
142 	sc->sc_iot = ma->ma_iot;
143 	sc->sc_ioh = ma->ma_ioh;
144 	/*
145 	 * Init the common struct for both the adapter and its slaves.
146 	 */
147 	bufq_alloc(&sc->sc_md.md_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
148 	sc->sc_md.md_softc = (void *)sc;	/* Pointer to this softc */
149 	sc->sc_md.md_mba = (void *)parent;	/* Pointer to parent softc */
150 	sc->sc_md.md_start = hpstart;		/* Disk start routine */
151 	sc->sc_md.md_attn = hpattn;		/* Disk attention routine */
152 	sc->sc_md.md_finish = hpfinish;		/* Disk xfer finish routine */
153 
154 	ms->sc_md[ma->ma_unit] = &sc->sc_md;	/* Per-unit backpointer */
155 
156 	/*
157 	 * Init and attach the disk structure.
158 	 */
159 	sc->sc_disk.dk_name = sc->sc_dev.dv_xname;
160 	disk_attach(&sc->sc_disk);
161 
162 	/*
163 	 * Fake a disklabel to be able to read in the real label.
164 	 */
165 	dl = sc->sc_disk.dk_label;
166 
167 	dl->d_secsize = DEV_BSIZE;
168 	dl->d_ntracks = 1;
169 	dl->d_nsectors = 32;
170 	dl->d_secpercyl = 32;
171 
172 	/*
173 	 * Read in label.
174 	 */
175 	if ((msg = readdisklabel(makedev(0, self->dv_unit * 8), hpstrategy,
176 	    dl, NULL)) != NULL)
177 		printf(": %s", msg);
178 	printf(": %s, size = %d sectors\n", dl->d_typename, dl->d_secperunit);
179 }
180 
181 
182 void
183 hpstrategy(struct buf *bp)
184 {
185 	struct	hp_softc *sc;
186 	struct	buf *gp;
187 	int	unit, s, err;
188 	struct disklabel *lp;
189 
190 	unit = DISKUNIT(bp->b_dev);
191 	sc = hp_cd.cd_devs[unit];
192 	lp = sc->sc_disk.dk_label;
193 
194 	err = bounds_check_with_label(bp, lp, sc->sc_wlabel);
195 	if (err < 0)
196 		goto done;
197 
198 	bp->b_rawblkno =
199 	    bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
200 	bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
201 
202 	s = splbio();
203 
204 	gp = BUFQ_PEEK(&sc->sc_md.md_q);
205 	BUFQ_PUT(&sc->sc_md.md_q, bp);
206 	if (gp == 0)
207 		mbaqueue(&sc->sc_md);
208 
209 	splx(s);
210 	return;
211 
212 done:
213 	bp->b_resid = bp->b_bcount;
214 	biodone(bp);
215 }
216 
217 /*
218  * Start transfer on given disk. Called from mbastart().
219  */
220 void
221 hpstart(struct	mba_device *md)
222 {
223 	struct	hp_softc *sc = md->md_softc;
224 	struct	disklabel *lp = sc->sc_disk.dk_label;
225 	struct	buf *bp = BUFQ_PEEK(&md->md_q);
226 	unsigned bn, cn, sn, tn;
227 
228 	/*
229 	 * Collect statistics.
230 	 */
231 	disk_busy(&sc->sc_disk);
232 	sc->sc_disk.dk_seek++;
233 
234 	bn = bp->b_rawblkno;
235 	if (bn) {
236 		cn = bn / lp->d_secpercyl;
237 		sn = bn % lp->d_secpercyl;
238 		tn = sn / lp->d_nsectors;
239 		sn = sn % lp->d_nsectors;
240 	} else
241 		cn = sn = tn = 0;
242 
243 	HP_WCSR(HP_DC, cn);
244 	HP_WCSR(HP_DA, (tn << 8) | sn);
245 	if (bp->b_flags & B_READ)
246 		HP_WCSR(HP_CS1, HPCS_READ);
247 	else
248 		HP_WCSR(HP_CS1, HPCS_WRITE);
249 }
250 
251 int
252 hpopen(dev_t dev, int flag, int fmt, struct proc *p)
253 {
254 	struct	hp_softc *sc;
255 	int	unit, part;
256 
257 	unit = DISKUNIT(dev);
258 	if (unit >= hp_cd.cd_ndevs)
259 		return ENXIO;
260 	sc = hp_cd.cd_devs[unit];
261 	if (sc == 0)
262 		return ENXIO;
263 
264 	part = DISKPART(dev);
265 
266 	if (part >= sc->sc_disk.dk_label->d_npartitions)
267 		return ENXIO;
268 
269 	switch (fmt) {
270 	case 	S_IFCHR:
271 		sc->sc_disk.dk_copenmask |= (1 << part);
272 		break;
273 
274 	case	S_IFBLK:
275 		sc->sc_disk.dk_bopenmask |= (1 << part);
276 		break;
277 	}
278 	sc->sc_disk.dk_openmask =
279 	    sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
280 
281 	return 0;
282 }
283 
284 int
285 hpclose(dev_t dev, int flag, int fmt, struct proc *p)
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_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
312 {
313 	struct	hp_softc *sc = hp_cd.cd_devs[DISKUNIT(dev)];
314 	struct	disklabel *lp = sc->sc_disk.dk_label;
315 	int	error;
316 
317 	switch (cmd) {
318 	case	DIOCGDINFO:
319 		bcopy(lp, addr, sizeof (struct disklabel));
320 		return 0;
321 
322 	case	DIOCGPART:
323 		((struct partinfo *)addr)->disklab = lp;
324 		((struct partinfo *)addr)->part =
325 		    &lp->d_partitions[DISKPART(dev)];
326 		break;
327 
328 	case	DIOCSDINFO:
329 		if ((flag & FWRITE) == 0)
330 			return EBADF;
331 
332 		return setdisklabel(lp, (struct disklabel *)addr, 0, 0);
333 
334 	case	DIOCWDINFO:
335 		if ((flag & FWRITE) == 0)
336 			error = EBADF;
337 		else {
338 			sc->sc_wlabel = 1;
339 			error = writedisklabel(dev, hpstrategy, lp, 0);
340 			sc->sc_wlabel = 0;
341 		}
342 		return error;
343 	case	DIOCWLABEL:
344 		if ((flag & FWRITE) == 0)
345 			return EBADF;
346 		sc->sc_wlabel = 1;
347 		break;
348 
349 	default:
350 		return ENOTTY;
351 	}
352 	return 0;
353 }
354 
355 /*
356  * Called when a transfer is finished. Check if transfer went OK,
357  * Return info about what-to-do-now.
358  */
359 enum xfer_action
360 hpfinish(struct mba_device *md, int mbasr, int *attn)
361 {
362 	struct	hp_softc *sc = md->md_softc;
363 	struct	buf *bp = BUFQ_PEEK(&md->md_q);
364 	int er1, er2, bc;
365 	unsigned byte;
366 
367 	er1 = HP_RCSR(HP_ER1);
368 	er2 = HP_RCSR(HP_ER2);
369 	HP_WCSR(HP_ER1, 0);
370 	HP_WCSR(HP_ER2, 0);
371 
372 hper1:
373 	switch (ffs(er1) - 1) {
374 	case -1:
375 		HP_WCSR(HP_ER1, 0);
376 		goto hper2;
377 
378 	case HPER1_DCK: /* Corrected? data read. Just notice. */
379 		bc = bus_space_read_4(md->md_mba->sc_iot,
380 		    md->md_mba->sc_ioh, MBA_BC);
381 		byte = ~(bc >> 16);
382 		diskerr(buf, hp_cd.cd_name, "soft ecc", LOG_PRINTF,
383 		    btodb(bp->b_bcount - byte), sc->sc_disk.dk_label);
384 		er1 &= ~(1<<HPER1_DCK);
385 		break;
386 
387 	default:
388 		printf("drive error :%s er1 %x er2 %x\n",
389 		    sc->sc_dev.dv_xname, er1, er2);
390 		HP_WCSR(HP_ER1, 0);
391 		HP_WCSR(HP_ER2, 0);
392 		goto hper2;
393 	}
394 	goto hper1;
395 
396 hper2:
397 	mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN);
398 	if (mbasr)
399 		printf("massbuss error :%s %x\n",
400 		    sc->sc_dev.dv_xname, mbasr);
401 
402 	BUFQ_PEEK(&md->md_q)->b_resid = 0;
403 	disk_unbusy(&sc->sc_disk, BUFQ_PEEK(&md->md_q)->b_bcount);
404 	return XFER_FINISH;
405 }
406 
407 /*
408  * Non-data transfer interrupt; like volume change.
409  */
410 int
411 hpattn(struct mba_device *md)
412 {
413 	struct	hp_softc *sc = md->md_softc;
414 	int	er1, er2;
415 
416         er1 = HP_RCSR(HP_ER1);
417         er2 = HP_RCSR(HP_ER2);
418 
419 	printf("%s: Attention! er1 %x er2 %x\n",
420 		sc->sc_dev.dv_xname, er1, er2);
421 	return 0;
422 }
423 
424 
425 int
426 hpsize(dev_t dev)
427 {
428 	int	size, unit = DISKUNIT(dev);
429 	struct  hp_softc *sc;
430 
431 	if (unit >= hp_cd.cd_ndevs || hp_cd.cd_devs[unit] == 0)
432 		return -1;
433 
434 	sc = hp_cd.cd_devs[unit];
435 	size = sc->sc_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
436 	    (sc->sc_disk.dk_label->d_secsize / DEV_BSIZE);
437 
438 	return size;
439 }
440 
441 int
442 hpread(dev_t dev, struct uio *uio, int ioflag)
443 {
444 	return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio));
445 }
446 
447 int
448 hpwrite(dev_t dev, struct uio *uio, int ioflag)
449 {
450 	return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio));
451 }
452