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