xref: /netbsd-src/sys/dev/gpib/cs80bus.c (revision 21e37cc72a480a47828990a439cde7ac9ffaf0c6)
1 /*	$NetBSD: cs80bus.c,v 1.1 2003/06/02 03:51:04 gmcgarry Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Gregory McGarry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: cs80bus.c,v 1.1 2003/06/02 03:51:04 gmcgarry Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/endian.h>
46 #include <sys/malloc.h>
47 
48 #include <dev/gpib/gpibvar.h>
49 #include <dev/gpib/cs80busvar.h>
50 
51 #define DEBUG
52 
53 #ifdef DEBUG
54 int cs80busdebug = 0xff;
55 #define DBG_FOLLOW	0x01
56 #define DBG_STATUS	0x02
57 #define DBG_FAIL	0x04
58 #define DPRINTF(mask, str)	if (cs80busdebug & (mask)) printf str
59 #else
60 #define DPRINTF(mask, str)	/* nothing */
61 #endif
62 
63 #include "locators.h"
64 #define	cs80buscf_slave		cf_loc[CS80BUSCF_SLAVE]
65 #define	cs80buscf_punit		cf_loc[CS80BUSCF_PUNIT]
66 
67 int	cs80busmatch(struct device *, struct cfdata *, void *);
68 void	cs80busattach(struct device *, struct device *, void *);
69 
70 CFATTACH_DECL(cs80bus, sizeof(struct cs80bus_softc),
71 	cs80busmatch, cs80busattach, NULL, NULL);
72 
73 static int	cs80bus_alloc(struct cs80bus_softc *, int, int);
74 static int	cs80bussearch(struct device *, struct cfdata *, void *);
75 static int	cs80busprint(void *, const char *);
76 
77 /*
78  * HP's CS80/SS80 command set can be found on `newer' devices, while
79  * the HP's Amigo command set is used on before-you-were-born
80  * devices.  Devices that respond to CS80/SS80 (and probably Amigo, too)
81  * are tagged with a 16-bit ID.
82  *
83  * CS80/SS80 has a 2-level addressing scheme; slave, the analog
84  * of a SCSI ID, and punit, the analog of a SCSI LUN.  Unforunately,
85  * IDs are on a per-slave basis; punits are often used for disk
86  * drives that have an accompanying tape drive on the second punit.
87  *
88  * We treat CS80/SS80 as an indirect bus.  However, since we are given
89  * some ID information, it is unreasonable to disallow cloning of
90  * CS80/SS80 devices.
91  *
92  * To deal with all of this, we use the semi-twisted scheme
93  * in cs80bus_attach_children().  For each GPIB slave, we loop
94  * through all of the possibly-configured children, allowing
95  * them to modify the punit parameter (but NOT the slave!).
96  *
97  */
98 
99 int
100 cs80busmatch(parent, match, aux)
101 	struct device *parent;
102 	struct cfdata *match;
103 	void *aux;
104 {
105 
106 	return (1);
107 }
108 
109 void
110 cs80busattach(parent, self, aux)
111 	struct device *parent, *self;
112 	void *aux;
113 {
114 	struct cs80bus_softc *sc = (struct cs80bus_softc *)self;
115 	struct gpib_attach_args *ga = aux;
116 	struct cs80bus_attach_args ca;
117 	int slave;
118 	u_int16_t id;
119 
120 	printf("\n");
121 
122 	sc->sc_ic = ga->ga_ic;
123 
124 	for (slave = 0; slave < 8; slave++) {
125 
126 		if (gpib_isalloc((void *)sc->sc_dev.dv_parent, slave))
127 			continue;
128 
129 		if (gpibrecv(sc->sc_ic, GPIB_BROADCAST_ADDR,
130 		    slave, &id, 2) != 2)
131 			continue;
132 
133 		BE16TOH(id);
134 
135 		DPRINTF(DBG_STATUS, ("cs80busattach: found id 0x%x\n", id));
136 
137 		if ((id & 0x200) == 0)
138 			continue;
139 
140 		ca.ca_ic = sc->sc_ic;
141 		ca.ca_slave = slave;
142 		ca.ca_id = id;
143 
144 		(void)config_search(cs80bussearch, &sc->sc_dev, &ca);
145 	}
146 }
147 
148 int
149 cs80bussearch(parent, cf, aux)
150 	struct device *parent;
151 	struct cfdata *cf;
152 	void *aux;
153 {
154 	struct cs80bus_softc *sc = (struct cs80bus_softc *)parent;
155 	struct cs80bus_attach_args *ca = aux;
156 
157 	/*
158 	 * Set punit if operator specified one in the kernel
159 	 * configuration file.
160 	 */
161 	if (cf->cs80buscf_punit != CS80BUSCF_PUNIT_DEFAULT &&
162 	    cf->cs80buscf_punit < CS80BUS_NPUNITS)
163 		ca->ca_punit = cf->cs80buscf_punit;
164 	else
165 		/* default punit */
166 		ca->ca_punit = 0;
167 
168 	DPRINTF(DBG_FOLLOW, ("cs80bussearch: id=0x%x slave=%d punit=%d\n",
169 	    ca->ca_id, ca->ca_slave, ca->ca_punit));
170 
171 	if (config_match(parent, cf, ca) > 0) {
172 
173 		DPRINTF(DBG_FOLLOW,
174 		    ("cs80bussearch: got id=0x%x slave=%d punit %d\n",
175 		    ca->ca_id, ca->ca_slave, ca->ca_punit));
176 
177 		/*
178 		 * The device probe has succeeded, and filled in
179 		 * the punit information.  Make sure the configuration
180 		 * allows for this slave/punit combination.
181 		 */
182 		if (cf->cs80buscf_slave != CS80BUSCF_SLAVE_DEFAULT &&
183 		    cf->cs80buscf_slave != ca->ca_slave)
184 			goto out;
185 		if (cf->cs80buscf_punit != CS80BUSCF_PUNIT_DEFAULT &&
186 		    cf->cs80buscf_punit != ca->ca_punit)
187 			goto out;
188 
189 		/*
190 		 * Allocate the device's address from the bus's
191 		 * resource map.
192 		 */
193 		if (cs80bus_alloc(sc, ca->ca_slave, ca->ca_punit))
194 			goto out;
195 
196 		/*
197 		 * This device is allowed; attach it.
198 		 */
199 		config_attach(parent, cf, ca, cs80busprint);
200 	}
201 out:
202 	return (0);
203 }
204 
205 int
206 cs80busprint(aux, pnp)
207 	void *aux;
208 	const char *pnp;
209 {
210 	struct cs80bus_attach_args *ca = aux;
211 
212 	printf(" slave %d punit %d", ca->ca_slave, ca->ca_punit);
213 	return (UNCONF);
214 }
215 
216 static int
217 cs80bus_alloc(sc, slave, punit)
218 	struct cs80bus_softc *sc;
219 	int slave, punit;
220 {
221 
222 	DPRINTF(DBG_FOLLOW, ("cs80bus_alloc: sc=%p\n", sc));
223 
224 	if (slave >= CS80BUS_NSLAVES || punit >= CS80BUS_NPUNITS)
225 		panic("cs80bus_alloc: device address out of range");
226 
227 	gpib_alloc((void *)sc->sc_dev.dv_parent, slave);
228 
229 	if (sc->sc_rmap[slave][punit] == 0) {
230 		sc->sc_rmap[slave][punit] = 1;
231 		return (0);
232 	}
233 	return (1);
234 }
235 
236 
237 
238 /*
239  *  CS80/SS80 (secondary) command functions
240  */
241 
242 int
243 cs80describe(v, slave, punit, csd)
244 	void *v;
245 	int slave;
246 	int punit;
247 	struct cs80_description *csd;
248 {
249 	struct cs80bus_softc *sc = v;
250 	struct cs80_describecmd desc;
251 	u_int8_t stat;
252 
253 	DPRINTF(DBG_FOLLOW, ("cs80describe: sc=%p slave=%d\n", sc, slave));
254 
255         /*
256          * Note command is always issued to unit 0.
257          */
258 
259         desc.c_unit = CS80CMD_SUNIT(0);
260         desc.c_vol = CS80CMD_SVOL(0);
261 	desc.c_cmd = CS80CMD_DESC;
262         (void) gpibsend(sc->sc_ic, slave, CS80CMD_SCMD, &desc, sizeof(desc));
263         (void) gpibrecv(sc->sc_ic, slave, CS80CMD_EXEC, csd, sizeof(*csd));
264         (void) gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1);
265 	if (stat != 0) {
266 		DPRINTF(DBG_FAIL, ("cs80describe: failed, stat=0x%x\n", stat));
267 		return (1);
268 	}
269 	BE16TOH(csd->d_iuw);
270 	BE16TOH(csd->d_cmaxxfr);
271 	BE16TOH(csd->d_sectsize);
272 	BE16TOH(csd->d_blocktime);
273 	BE16TOH(csd->d_uavexfr);
274 	BE16TOH(csd->d_retry);
275 	BE16TOH(csd->d_access);
276 	BE32TOH(csd->d_maxcylhead);
277 	BE16TOH(csd->d_maxsect);
278 	BE16TOH(csd->d_maxvsecth);
279 	BE32TOH(csd->d_maxvsectl);
280 
281 	return (0);
282 }
283 
284 int
285 cs80reset(v, slave, punit)
286 	void *v;
287 	int slave;
288 	int punit;
289 {
290 	struct cs80bus_softc *sc = v;
291 	struct cs80_clearcmd clear;
292 	struct cs80_srcmd sr;
293 	struct cs80_ssmcmd ssm;
294 
295 	DPRINTF(DBG_FOLLOW, ("cs80reset: sc=%p slave=%d punit=%d\n", sc,
296 	    slave, punit));
297 
298 	clear.c_unit = CS80CMD_SUNIT(punit);
299 	clear.c_cmd = CS80CMD_CLEAR;
300 	if (cs80send(sc, slave, punit, CS80CMD_TCMD, &clear, sizeof(clear))) {
301 		DPRINTF(DBG_FAIL, ("cs80reset: CLEAR failed\n"));
302 		return (1);
303 	}
304 
305 	sr.c_unit = CS80CMD_SUNIT(15);		/* XXX */
306 	sr.c_nop = CS80CMD_NOP;
307 	sr.c_cmd = CS80CMD_SREL;
308 	sr.c_param = 0xc0;			/* XXX */
309 	if (cs80send(sc, slave, punit, CS80CMD_SCMD, &sr, sizeof(sr))) {
310 		DPRINTF(DBG_FAIL, ("cs80reset: SREL failed\n"));
311 		return (1);
312 	}
313 
314 	ssm.c_unit = CS80CMD_SUNIT(punit);
315 	ssm.c_cmd = CS80CMD_SSM;
316 	ssm.c_refm = htobe16(REF_MASK);
317 	ssm.c_fefm = htobe16(FEF_MASK);
318 	ssm.c_aefm = htobe16(AEF_MASK);
319 	ssm.c_iefm = htobe16(IEF_MASK);
320 	if (cs80send(sc, slave, punit, CS80CMD_SCMD, &ssm, sizeof(ssm))) {
321 		DPRINTF(DBG_FAIL, ("cs80reset: SSM failed\n"));
322 		return (1);
323 	}
324 
325 	return (0);
326 }
327 
328 int
329 cs80status(v, slave, punit, css)
330 	void *v;
331 	int slave;
332 	int punit;
333 	struct cs80_stat *css;
334 {
335 	struct cs80bus_softc *sc = v;
336 	struct cs80_statuscmd rs;
337 	u_int8_t stat;
338 
339 	rs.c_unit = CS80CMD_SUNIT(punit);
340 	rs.c_sram = CS80CMD_SRAM;
341 	rs.c_param = 0;		/* single vector (i.e. sector number) */
342 	rs.c_cmd = CS80CMD_STATUS;
343 	memset((caddr_t)css, 0, sizeof(*css));
344 	(void) gpibsend(sc->sc_ic, slave, CS80CMD_SCMD, &rs, sizeof(rs));
345 	(void) gpibrecv(sc->sc_ic, slave, CS80CMD_EXEC, css, sizeof(*css));
346 	(void) gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1);
347 	if (stat != 0) {
348 		DPRINTF(DBG_FAIL, ("cs80status: failed, stat=0x%x\n", stat));
349 		return (1);
350 	}
351 	BE16TOH(css->c_ref);
352 	BE16TOH(css->c_fef);
353 	BE16TOH(css->c_aef);
354 	BE16TOH(css->c_ief);
355 	BE32TOH(css->c_blk);
356 
357 	return (0);
358 }
359 
360 int
361 cs80setoptions(v, slave, punit, options)
362 	void *v;
363 	int slave;
364 	int punit;
365 	u_int8_t options;
366 {
367 	struct cs80bus_softc *sc = v;
368 	struct cs80_soptcmd opt;
369 
370 	opt.c_unit = CS80CMD_SUNIT(punit);
371 	opt.c_nop = CS80CMD_NOP;
372 	opt.c_opt = CS80CMD_SOPT;
373 	opt.c_param = options;
374 	if (cs80send(sc, slave, punit, CS80CMD_SCMD, &opt, sizeof(opt))) {
375 		DPRINTF(DBG_FAIL, ("cs80setoptions: failed\n"));
376 		return (1);
377 	}
378 
379 	return (0);
380 }
381 
382 int
383 cs80send(v, slave, punit, cmd, ptr, cnt)
384 	void *v;
385 	int slave;
386 	int punit;
387 	int cmd;
388 	void *ptr;
389 	int cnt;
390 {
391 	struct cs80bus_softc *sc = v;
392 	u_int8_t *buf = ptr;
393 	u_int8_t stat;
394 
395 	DPRINTF(DBG_FOLLOW,
396 	    ("cs80send: sc=%p slave=%d punit=%d cmd=%d ptr=%p cnt=%d\n", sc,
397 	    slave, punit, cmd, buf, cnt));
398 
399 	if (gpibsend(sc->sc_ic, slave, cmd, buf, cnt) != cnt) {
400 		DPRINTF(DBG_FAIL, ("cs80send: SCMD failed\n"));
401 		return (1);
402 	}
403 	if (gpibswait(sc->sc_ic, slave)) {
404 		DPRINTF(DBG_FAIL, ("cs80send: wait failed\n"));
405 		return (1);
406 	}
407 	if (gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1) != 1) {
408 		DPRINTF(DBG_FAIL, ("cs80send: QSTAT failed\n"));
409 		return (1);
410 	}
411 	if (stat != 0) {
412 		DPRINTF(DBG_FAIL, ("cs80send: failed, stat=0x%x\n", stat));
413 		return (1);
414 	}
415 
416 	return (0);
417 }
418