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