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