1 /* $NetBSD: cs80bus.c,v 1.10 2008/04/28 20:23:48 martin 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.10 2008/04/28 20:23:48 martin 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(struct device *, struct cfdata *, void *); 61 void cs80busattach(struct device *, struct device *, 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(struct device *, struct cfdata *, 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(parent, match, aux) 95 struct device *parent; 96 struct cfdata *match; 97 void *aux; 98 { 99 100 return (1); 101 } 102 103 void 104 cs80busattach(parent, self, aux) 105 struct device *parent, *self; 106 void *aux; 107 { 108 struct cs80bus_softc *sc = device_private(self); 109 struct gpib_attach_args *ga = aux; 110 struct cs80bus_attach_args ca; 111 int slave; 112 u_int16_t id; 113 114 printf("\n"); 115 116 sc->sc_ic = ga->ga_ic; 117 118 for (slave = 0; slave < 8; slave++) { 119 120 if (gpib_isalloc((void *)device_parent(&sc->sc_dev), slave)) 121 continue; 122 123 if (gpibrecv(sc->sc_ic, GPIB_BROADCAST_ADDR, 124 slave, &id, 2) != 2) 125 continue; 126 127 BE16TOH(id); 128 129 DPRINTF(DBG_STATUS, ("cs80busattach: found id 0x%x\n", id)); 130 131 if ((id & 0x200) == 0) 132 continue; 133 134 ca.ca_ic = sc->sc_ic; 135 ca.ca_slave = slave; 136 ca.ca_id = id; 137 138 (void)config_search_ia(cs80bussearch, &sc->sc_dev, "cs80bus", &ca); 139 } 140 } 141 142 int 143 cs80bussearch(parent, cf, ldesc, aux) 144 struct device *parent; 145 struct cfdata *cf; 146 const int *ldesc; 147 void *aux; 148 { 149 struct cs80bus_softc *sc = (struct cs80bus_softc *)parent; 150 struct cs80bus_attach_args *ca = aux; 151 152 /* 153 * Set punit if operator specified one in the kernel 154 * configuration file. 155 */ 156 if (cf->cs80buscf_punit != CS80BUSCF_PUNIT_DEFAULT && 157 cf->cs80buscf_punit < CS80BUS_NPUNITS) 158 ca->ca_punit = cf->cs80buscf_punit; 159 else 160 /* default punit */ 161 ca->ca_punit = 0; 162 163 DPRINTF(DBG_FOLLOW, ("cs80bussearch: id=0x%x slave=%d punit=%d\n", 164 ca->ca_id, ca->ca_slave, ca->ca_punit)); 165 166 if (config_match(parent, cf, ca) > 0) { 167 168 DPRINTF(DBG_FOLLOW, 169 ("cs80bussearch: got id=0x%x slave=%d punit %d\n", 170 ca->ca_id, ca->ca_slave, ca->ca_punit)); 171 172 /* 173 * The device probe has succeeded, and filled in 174 * the punit information. Make sure the configuration 175 * allows for this slave/punit combination. 176 */ 177 if (cf->cs80buscf_slave != CS80BUSCF_SLAVE_DEFAULT && 178 cf->cs80buscf_slave != ca->ca_slave) 179 goto out; 180 if (cf->cs80buscf_punit != CS80BUSCF_PUNIT_DEFAULT && 181 cf->cs80buscf_punit != ca->ca_punit) 182 goto out; 183 184 /* 185 * Allocate the device's address from the bus's 186 * resource map. 187 */ 188 if (cs80bus_alloc(sc, ca->ca_slave, ca->ca_punit)) 189 goto out; 190 191 /* 192 * This device is allowed; attach it. 193 */ 194 config_attach(parent, cf, ca, cs80busprint); 195 } 196 out: 197 return (0); 198 } 199 200 int 201 cs80busprint(aux, pnp) 202 void *aux; 203 const char *pnp; 204 { 205 struct cs80bus_attach_args *ca = aux; 206 207 printf(" slave %d punit %d", ca->ca_slave, ca->ca_punit); 208 return (UNCONF); 209 } 210 211 static int 212 cs80bus_alloc(sc, slave, punit) 213 struct cs80bus_softc *sc; 214 int slave, punit; 215 { 216 217 DPRINTF(DBG_FOLLOW, ("cs80bus_alloc: sc=%p\n", sc)); 218 219 if (slave >= CS80BUS_NSLAVES || punit >= CS80BUS_NPUNITS) 220 panic("cs80bus_alloc: device address out of range"); 221 222 gpib_alloc((void *)device_parent(&sc->sc_dev), slave); 223 224 if (sc->sc_rmap[slave][punit] == 0) { 225 sc->sc_rmap[slave][punit] = 1; 226 return (0); 227 } 228 return (1); 229 } 230 231 232 233 /* 234 * CS80/SS80 (secondary) command functions 235 */ 236 237 int 238 cs80describe(v, slave, punit, csd) 239 void *v; 240 int slave; 241 int punit; 242 struct cs80_description *csd; 243 { 244 struct cs80bus_softc *sc = v; 245 struct cs80_describecmd desc; 246 u_int8_t stat; 247 248 DPRINTF(DBG_FOLLOW, ("cs80describe: sc=%p slave=%d\n", sc, slave)); 249 250 /* 251 * Note command is always issued to unit 0. 252 */ 253 254 desc.c_unit = CS80CMD_SUNIT(0); 255 desc.c_vol = CS80CMD_SVOL(0); 256 desc.c_cmd = CS80CMD_DESC; 257 (void) gpibsend(sc->sc_ic, slave, CS80CMD_SCMD, &desc, sizeof(desc)); 258 (void) gpibrecv(sc->sc_ic, slave, CS80CMD_EXEC, csd, sizeof(*csd)); 259 (void) gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1); 260 if (stat != 0) { 261 DPRINTF(DBG_FAIL, ("cs80describe: failed, stat=0x%x\n", stat)); 262 return (1); 263 } 264 BE16TOH(csd->d_iuw); 265 BE16TOH(csd->d_cmaxxfr); 266 BE16TOH(csd->d_sectsize); 267 BE16TOH(csd->d_blocktime); 268 BE16TOH(csd->d_uavexfr); 269 BE16TOH(csd->d_retry); 270 BE16TOH(csd->d_access); 271 BE32TOH(csd->d_maxcylhead); 272 BE16TOH(csd->d_maxsect); 273 BE16TOH(csd->d_maxvsecth); 274 BE32TOH(csd->d_maxvsectl); 275 276 return (0); 277 } 278 279 int 280 cs80reset(v, slave, punit) 281 void *v; 282 int slave; 283 int punit; 284 { 285 struct cs80bus_softc *sc = v; 286 struct cs80_clearcmd clear; 287 struct cs80_srcmd sr; 288 struct cs80_ssmcmd ssm; 289 290 DPRINTF(DBG_FOLLOW, ("cs80reset: sc=%p slave=%d punit=%d\n", sc, 291 slave, punit)); 292 293 clear.c_unit = CS80CMD_SUNIT(punit); 294 clear.c_cmd = CS80CMD_CLEAR; 295 if (cs80send(sc, slave, punit, CS80CMD_TCMD, &clear, sizeof(clear))) { 296 DPRINTF(DBG_FAIL, ("cs80reset: CLEAR failed\n")); 297 return (1); 298 } 299 300 sr.c_unit = CS80CMD_SUNIT(15); /* XXX */ 301 sr.c_nop = CS80CMD_NOP; 302 sr.c_cmd = CS80CMD_SREL; 303 sr.c_param = 0xc0; /* XXX */ 304 if (cs80send(sc, slave, punit, CS80CMD_SCMD, &sr, sizeof(sr))) { 305 DPRINTF(DBG_FAIL, ("cs80reset: SREL failed\n")); 306 return (1); 307 } 308 309 ssm.c_unit = CS80CMD_SUNIT(punit); 310 ssm.c_cmd = CS80CMD_SSM; 311 ssm.c_refm = htobe16(REF_MASK); 312 ssm.c_fefm = htobe16(FEF_MASK); 313 ssm.c_aefm = htobe16(AEF_MASK); 314 ssm.c_iefm = htobe16(IEF_MASK); 315 if (cs80send(sc, slave, punit, CS80CMD_SCMD, &ssm, sizeof(ssm))) { 316 DPRINTF(DBG_FAIL, ("cs80reset: SSM failed\n")); 317 return (1); 318 } 319 320 return (0); 321 } 322 323 int 324 cs80status(v, slave, punit, css) 325 void *v; 326 int slave; 327 int punit; 328 struct cs80_stat *css; 329 { 330 struct cs80bus_softc *sc = v; 331 struct cs80_statuscmd rs; 332 u_int8_t stat; 333 334 rs.c_unit = CS80CMD_SUNIT(punit); 335 rs.c_sram = CS80CMD_SRAM; 336 rs.c_param = 0; /* single vector (i.e. sector number) */ 337 rs.c_cmd = CS80CMD_STATUS; 338 memset((void *)css, 0, sizeof(*css)); 339 (void) gpibsend(sc->sc_ic, slave, CS80CMD_SCMD, &rs, sizeof(rs)); 340 (void) gpibrecv(sc->sc_ic, slave, CS80CMD_EXEC, css, sizeof(*css)); 341 (void) gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1); 342 if (stat != 0) { 343 DPRINTF(DBG_FAIL, ("cs80status: failed, stat=0x%x\n", stat)); 344 return (1); 345 } 346 BE16TOH(css->c_ref); 347 BE16TOH(css->c_fef); 348 BE16TOH(css->c_aef); 349 BE16TOH(css->c_ief); 350 BE32TOH(css->c_blk); 351 352 return (0); 353 } 354 355 int 356 cs80setoptions(v, slave, punit, options) 357 void *v; 358 int slave; 359 int punit; 360 u_int8_t options; 361 { 362 struct cs80bus_softc *sc = v; 363 struct cs80_soptcmd opt; 364 365 opt.c_unit = CS80CMD_SUNIT(punit); 366 opt.c_nop = CS80CMD_NOP; 367 opt.c_opt = CS80CMD_SOPT; 368 opt.c_param = options; 369 if (cs80send(sc, slave, punit, CS80CMD_SCMD, &opt, sizeof(opt))) { 370 DPRINTF(DBG_FAIL, ("cs80setoptions: failed\n")); 371 return (1); 372 } 373 374 return (0); 375 } 376 377 int 378 cs80send(v, slave, punit, cmd, ptr, cnt) 379 void *v; 380 int slave; 381 int punit; 382 int cmd; 383 void *ptr; 384 int cnt; 385 { 386 struct cs80bus_softc *sc = v; 387 u_int8_t *buf = ptr; 388 u_int8_t stat; 389 390 DPRINTF(DBG_FOLLOW, 391 ("cs80send: sc=%p slave=%d punit=%d cmd=%d ptr=%p cnt=%d\n", sc, 392 slave, punit, cmd, buf, cnt)); 393 394 if (gpibsend(sc->sc_ic, slave, cmd, buf, cnt) != cnt) { 395 DPRINTF(DBG_FAIL, ("cs80send: SCMD failed\n")); 396 return (1); 397 } 398 if (gpibswait(sc->sc_ic, slave)) { 399 DPRINTF(DBG_FAIL, ("cs80send: wait failed\n")); 400 return (1); 401 } 402 if (gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1) != 1) { 403 DPRINTF(DBG_FAIL, ("cs80send: QSTAT failed\n")); 404 return (1); 405 } 406 if (stat != 0) { 407 DPRINTF(DBG_FAIL, ("cs80send: failed, stat=0x%x\n", stat)); 408 return (1); 409 } 410 411 return (0); 412 } 413