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