1 1.119 skrll /* $NetBSD: if_se.c,v 1.119 2023/12/20 18:09:19 skrll Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) 1997 Ian W. Dall <ian.dall (at) dsto.defence.gov.au> 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Redistribution and use in source and binary forms, with or without 8 1.1 thorpej * modification, are permitted provided that the following conditions 9 1.1 thorpej * are met: 10 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 11 1.1 thorpej * notice, this list of conditions and the following disclaimer. 12 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 14 1.1 thorpej * documentation and/or other materials provided with the distribution. 15 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 16 1.1 thorpej * must display the following acknowledgement: 17 1.1 thorpej * This product includes software developed by Ian W. Dall. 18 1.1 thorpej * 4. The name of the author may not be used to endorse or promote products 19 1.1 thorpej * derived from this software without specific prior written permission. 20 1.1 thorpej * 21 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 thorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 thorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 1.1 thorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.1 thorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 thorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.1 thorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 1.1 thorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.1 thorpej */ 32 1.1 thorpej 33 1.1 thorpej /* 34 1.11 matthias * Driver for Cabletron EA41x scsi ethernet adaptor. 35 1.11 matthias * 36 1.1 thorpej * Written by Ian Dall <ian.dall (at) dsto.defence.gov.au> Feb 3, 1997 37 1.11 matthias * 38 1.11 matthias * Acknowledgement: Thanks are due to Philip L. Budne <budd (at) cs.bu.edu> 39 1.27 soren * who reverse engineered the EA41x. In developing this code, 40 1.114 andvar * Phil's userland daemon "etherd", was referred to extensively in lieu 41 1.11 matthias * of accurate documentation for the device. 42 1.1 thorpej * 43 1.1 thorpej * This is a weird device! It doesn't conform to the scsi spec in much 44 1.19 is * at all. About the only standard command supported is inquiry. Most 45 1.1 thorpej * commands are 6 bytes long, but the recv data is only 1 byte. Data 46 1.1 thorpej * must be received by periodically polling the device with the recv 47 1.1 thorpej * command. 48 1.1 thorpej * 49 1.1 thorpej * This driver is also a bit unusual. It must look like a network 50 1.1 thorpej * interface and it must also appear to be a scsi device to the scsi 51 1.1 thorpej * system. Hence there are cases where there are two entry points. eg 52 1.115 msaitoh * sedone is to be called from the scsi subsystem and se_ifstart from 53 1.1 thorpej * the network interface subsystem. In addition, to facilitate scsi 54 1.1 thorpej * commands issued by userland programs, there are open, close and 55 1.1 thorpej * ioctl entry points. This allows a user program to, for example, 56 1.1 thorpej * display the ea41x stats and download new code into the adaptor --- 57 1.1 thorpej * functions which can't be performed through the ifconfig interface. 58 1.5 matthias * Normal operation does not require any special userland program. 59 1.1 thorpej */ 60 1.38 lukem 61 1.38 lukem #include <sys/cdefs.h> 62 1.119 skrll __KERNEL_RCSID(0, "$NetBSD: if_se.c,v 1.119 2023/12/20 18:09:19 skrll Exp $"); 63 1.1 thorpej 64 1.88 pooka #ifdef _KERNEL_OPT 65 1.14 jonathan #include "opt_inet.h" 66 1.14 jonathan #include "opt_atalk.h" 67 1.88 pooka #endif 68 1.1 thorpej 69 1.1 thorpej #include <sys/param.h> 70 1.110 riastrad #include <sys/types.h> 71 1.110 riastrad 72 1.110 riastrad #include <sys/buf.h> 73 1.28 thorpej #include <sys/callout.h> 74 1.110 riastrad #include <sys/conf.h> 75 1.110 riastrad #include <sys/device.h> 76 1.110 riastrad #include <sys/disk.h> 77 1.110 riastrad #include <sys/disklabel.h> 78 1.110 riastrad #include <sys/errno.h> 79 1.1 thorpej #include <sys/file.h> 80 1.1 thorpej #include <sys/ioctl.h> 81 1.110 riastrad #include <sys/kernel.h> 82 1.1 thorpej #include <sys/malloc.h> 83 1.110 riastrad #include <sys/mbuf.h> 84 1.110 riastrad #include <sys/mutex.h> 85 1.1 thorpej #include <sys/proc.h> 86 1.110 riastrad #include <sys/socket.h> 87 1.110 riastrad #include <sys/stat.h> 88 1.110 riastrad #include <sys/syslog.h> 89 1.110 riastrad #include <sys/systm.h> 90 1.110 riastrad #include <sys/uio.h> 91 1.106 jdc #include <sys/workqueue.h> 92 1.1 thorpej 93 1.9 bouyer #include <dev/scsipi/scsi_ctron_ether.h> 94 1.9 bouyer #include <dev/scsipi/scsiconf.h> 95 1.110 riastrad #include <dev/scsipi/scsipi_all.h> 96 1.1 thorpej 97 1.110 riastrad #include <net/bpf.h> 98 1.1 thorpej #include <net/if.h> 99 1.1 thorpej #include <net/if_dl.h> 100 1.1 thorpej #include <net/if_ether.h> 101 1.5 matthias #include <net/if_media.h> 102 1.1 thorpej 103 1.1 thorpej #ifdef INET 104 1.110 riastrad #include <netinet/if_inarp.h> 105 1.1 thorpej #include <netinet/in.h> 106 1.2 cgd #endif 107 1.2 cgd 108 1.5 matthias #ifdef NETATALK 109 1.5 matthias #include <netatalk/at.h> 110 1.5 matthias #endif 111 1.5 matthias 112 1.1 thorpej #define SETIMEOUT 1000 113 1.1 thorpej #define SEOUTSTANDING 4 114 1.1 thorpej #define SERETRIES 4 115 1.1 thorpej #define SE_PREFIX 4 116 1.1 thorpej #define ETHER_CRC 4 117 1.1 thorpej #define SEMINSIZE 60 118 1.1 thorpej 119 1.1 thorpej /* Make this big enough for an ETHERMTU packet in promiscuous mode. */ 120 1.1 thorpej #define MAX_SNAP (ETHERMTU + sizeof(struct ether_header) + \ 121 1.1 thorpej SE_PREFIX + ETHER_CRC) 122 1.1 thorpej 123 1.11 matthias /* 10 full length packets appears to be the max ever returned. 16k is OK */ 124 1.11 matthias #define RBUF_LEN (16 * 1024) 125 1.11 matthias 126 1.57 perry /* Tuning parameters: 127 1.11 matthias * The EA41x only returns a maximum of 10 packets (regardless of size). 128 1.11 matthias * We will attempt to adapt to polling fast enough to get RDATA_GOAL packets 129 1.11 matthias * per read 130 1.11 matthias */ 131 1.11 matthias #define RDATA_MAX 10 132 1.11 matthias #define RDATA_GOAL 8 133 1.11 matthias 134 1.11 matthias /* se_poll and se_poll0 are the normal polling rate and the minimum 135 1.11 matthias * polling rate respectively. se_poll0 should be chosen so that at 136 1.11 matthias * maximum ethernet speed, we will read nearly RDATA_MAX packets. se_poll 137 1.11 matthias * should be chosen for reasonable maximum latency. 138 1.11 matthias * In practice, if we are being saturated with min length packets, we 139 1.11 matthias * can't poll fast enough. Polling with zero delay actually 140 1.11 matthias * worsens performance. se_poll0 is enforced to be always at least 1 141 1.5 matthias */ 142 1.1 thorpej #define SE_POLL 40 /* default in milliseconds */ 143 1.11 matthias #define SE_POLL0 10 /* default in milliseconds */ 144 1.11 matthias int se_poll = 0; /* Delay in ticks set at attach time */ 145 1.1 thorpej int se_poll0 = 0; 146 1.105 jdc #ifdef SE_DEBUG 147 1.11 matthias int se_max_received = 0; /* Instrumentation */ 148 1.105 jdc #endif 149 1.1 thorpej 150 1.1 thorpej #define PROTOCMD(p, d) \ 151 1.3 thorpej ((d) = (p)) 152 1.1 thorpej 153 1.63 cube #define PROTOCMD_DECL(name) \ 154 1.63 cube static const struct scsi_ctron_ether_generic name 155 1.1 thorpej 156 1.63 cube #define PROTOCMD_DECL_SPECIAL(name) \ 157 1.100 msaitoh static const struct __CONCAT(scsi_, name) name 158 1.3 thorpej 159 1.3 thorpej /* Command initializers for commands using scsi_ctron_ether_generic */ 160 1.101 msaitoh PROTOCMD_DECL(ctron_ether_send) = {CTRON_ETHER_SEND, 0, {0,0}, 0}; 161 1.63 cube PROTOCMD_DECL(ctron_ether_add_proto) = {CTRON_ETHER_ADD_PROTO, 0, {0,0}, 0}; 162 1.63 cube PROTOCMD_DECL(ctron_ether_get_addr) = {CTRON_ETHER_GET_ADDR, 0, {0,0}, 0}; 163 1.63 cube PROTOCMD_DECL(ctron_ether_set_media) = {CTRON_ETHER_SET_MEDIA, 0, {0,0}, 0}; 164 1.63 cube PROTOCMD_DECL(ctron_ether_set_addr) = {CTRON_ETHER_SET_ADDR, 0, {0,0}, 0}; 165 1.63 cube PROTOCMD_DECL(ctron_ether_set_multi) = {CTRON_ETHER_SET_MULTI, 0, {0,0}, 0}; 166 1.63 cube PROTOCMD_DECL(ctron_ether_remove_multi) = 167 1.63 cube {CTRON_ETHER_REMOVE_MULTI, 0, {0,0}, 0}; 168 1.3 thorpej 169 1.3 thorpej /* Command initializers for commands using their own structures */ 170 1.63 cube PROTOCMD_DECL_SPECIAL(ctron_ether_recv) = {CTRON_ETHER_RECV}; 171 1.63 cube PROTOCMD_DECL_SPECIAL(ctron_ether_set_mode) = 172 1.63 cube {CTRON_ETHER_SET_MODE, 0, {0,0}, 0}; 173 1.1 thorpej 174 1.1 thorpej struct se_softc { 175 1.85 chs device_t sc_dev; 176 1.1 thorpej struct ethercom sc_ethercom; /* Ethernet common part */ 177 1.34 bouyer struct scsipi_periph *sc_periph;/* contains our targ, lun, etc. */ 178 1.28 thorpej 179 1.28 thorpej struct callout sc_recv_ch; 180 1.105 jdc struct kmutex sc_iflock; 181 1.105 jdc struct if_percpuq *sc_ipq; 182 1.106 jdc struct workqueue *sc_recv_wq, *sc_send_wq; 183 1.106 jdc struct work sc_recv_work, sc_send_work; 184 1.106 jdc int sc_recv_work_pending, sc_send_work_pending; 185 1.28 thorpej 186 1.1 thorpej char *sc_tbuf; 187 1.1 thorpej char *sc_rbuf; 188 1.1 thorpej int protos; 189 1.5 matthias #define PROTO_IP 0x01 190 1.5 matthias #define PROTO_ARP 0x02 191 1.5 matthias #define PROTO_REVARP 0x04 192 1.5 matthias #define PROTO_AT 0x08 193 1.5 matthias #define PROTO_AARP 0x10 194 1.1 thorpej int sc_debug; 195 1.1 thorpej int sc_flags; 196 1.11 matthias int sc_last_timeout; 197 1.21 thorpej int sc_enabled; 198 1.107 jdc int sc_attach_state; 199 1.1 thorpej }; 200 1.1 thorpej 201 1.78 cegger static int sematch(device_t, cfdata_t, void *); 202 1.78 cegger static void seattach(device_t, device_t, void *); 203 1.107 jdc static int sedetach(device_t, int); 204 1.1 thorpej 205 1.56 perry static void se_ifstart(struct ifnet *); 206 1.1 thorpej 207 1.56 perry static void sedone(struct scsipi_xfer *, int); 208 1.64 christos static int se_ioctl(struct ifnet *, u_long, void *); 209 1.118 skrll #if 0 210 1.56 perry static void sewatchdog(struct ifnet *); 211 1.118 skrll #endif 212 1.56 perry 213 1.91 jakllsch #if 0 214 1.100 msaitoh static inline uint16_t ether_cmp(void *, void *); 215 1.91 jakllsch #endif 216 1.106 jdc static void se_recv_callout(void *); 217 1.106 jdc static void se_recv_worker(struct work *wk, void *cookie); 218 1.106 jdc static void se_recv(struct se_softc *); 219 1.56 perry static struct mbuf *se_get(struct se_softc *, char *, int); 220 1.56 perry static int se_read(struct se_softc *, char *, int); 221 1.118 skrll #if 0 222 1.106 jdc static void se_reset(struct se_softc *); 223 1.118 skrll #endif 224 1.56 perry static int se_add_proto(struct se_softc *, int); 225 1.100 msaitoh static int se_get_addr(struct se_softc *, uint8_t *); 226 1.56 perry static int se_set_media(struct se_softc *, int); 227 1.56 perry static int se_init(struct se_softc *); 228 1.100 msaitoh static int se_set_multi(struct se_softc *, uint8_t *); 229 1.100 msaitoh static int se_remove_multi(struct se_softc *, uint8_t *); 230 1.1 thorpej #if 0 231 1.56 perry static int sc_set_all_multi(struct se_softc *, int); 232 1.1 thorpej #endif 233 1.56 perry static void se_stop(struct se_softc *); 234 1.60 perry static inline int se_scsipi_cmd(struct scsipi_periph *periph, 235 1.10 enami struct scsipi_generic *scsipi_cmd, 236 1.55 reinoud int cmdlen, u_char *data_addr, int datalen, 237 1.10 enami int retries, int timeout, struct buf *bp, 238 1.56 perry int flags); 239 1.106 jdc static void se_send_worker(struct work *wk, void *cookie); 240 1.5 matthias static int se_set_mode(struct se_softc *, int, int); 241 1.1 thorpej 242 1.56 perry int se_enable(struct se_softc *); 243 1.56 perry void se_disable(struct se_softc *); 244 1.21 thorpej 245 1.85 chs CFATTACH_DECL_NEW(se, sizeof(struct se_softc), 246 1.107 jdc sematch, seattach, sedetach, NULL); 247 1.1 thorpej 248 1.13 thorpej extern struct cfdriver se_cd; 249 1.40 gehenna 250 1.40 gehenna dev_type_open(seopen); 251 1.40 gehenna dev_type_close(seclose); 252 1.40 gehenna dev_type_ioctl(seioctl); 253 1.40 gehenna 254 1.40 gehenna const struct cdevsw se_cdevsw = { 255 1.86 dholland .d_open = seopen, 256 1.86 dholland .d_close = seclose, 257 1.86 dholland .d_read = noread, 258 1.86 dholland .d_write = nowrite, 259 1.86 dholland .d_ioctl = seioctl, 260 1.86 dholland .d_stop = nostop, 261 1.86 dholland .d_tty = notty, 262 1.86 dholland .d_poll = nopoll, 263 1.86 dholland .d_mmap = nommap, 264 1.86 dholland .d_kqfilter = nokqfilter, 265 1.87 dholland .d_discard = nodiscard, 266 1.105 jdc .d_flag = D_OTHER | D_MPSAFE 267 1.40 gehenna }; 268 1.1 thorpej 269 1.34 bouyer const struct scsipi_periphsw se_switch = { 270 1.1 thorpej NULL, /* Use default error handler */ 271 1.106 jdc NULL, /* have no queue */ 272 1.1 thorpej NULL, /* have no async handler */ 273 1.107 jdc sedone, /* deal with send/recv completion */ 274 1.1 thorpej }; 275 1.1 thorpej 276 1.45 mycroft const struct scsipi_inquiry_pattern se_patterns[] = { 277 1.1 thorpej {T_PROCESSOR, T_FIXED, 278 1.101 msaitoh "CABLETRN", "EA412", ""}, 279 1.1 thorpej {T_PROCESSOR, T_FIXED, 280 1.101 msaitoh "Cabletrn", "EA412", ""}, 281 1.1 thorpej }; 282 1.1 thorpej 283 1.91 jakllsch #if 0 284 1.1 thorpej /* 285 1.1 thorpej * Compare two Ether/802 addresses for equality, inlined and 286 1.1 thorpej * unrolled for speed. 287 1.37 thorpej * Note: use this like memcmp() 288 1.1 thorpej */ 289 1.100 msaitoh static inline uint16_t 290 1.76 dsl ether_cmp(void *one, void *two) 291 1.1 thorpej { 292 1.100 msaitoh uint16_t *a = (uint16_t *) one; 293 1.100 msaitoh uint16_t *b = (uint16_t *) two; 294 1.100 msaitoh uint16_t diff; 295 1.1 thorpej 296 1.1 thorpej diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]); 297 1.1 thorpej 298 1.1 thorpej return (diff); 299 1.1 thorpej } 300 1.1 thorpej 301 1.1 thorpej #define ETHER_CMP ether_cmp 302 1.91 jakllsch #endif 303 1.1 thorpej 304 1.5 matthias static int 305 1.78 cegger sematch(device_t parent, cfdata_t match, void *aux) 306 1.1 thorpej { 307 1.9 bouyer struct scsipibus_attach_args *sa = aux; 308 1.1 thorpej int priority; 309 1.1 thorpej 310 1.9 bouyer (void)scsipi_inqmatch(&sa->sa_inqbuf, 311 1.58 jdc se_patterns, sizeof(se_patterns) / sizeof(se_patterns[0]), 312 1.1 thorpej sizeof(se_patterns[0]), &priority); 313 1.1 thorpej return (priority); 314 1.1 thorpej } 315 1.1 thorpej 316 1.1 thorpej /* 317 1.1 thorpej * The routine called by the low level scsi routine when it discovers 318 1.1 thorpej * a device suitable for this driver. 319 1.1 thorpej */ 320 1.5 matthias static void 321 1.78 cegger seattach(device_t parent, device_t self, void *aux) 322 1.1 thorpej { 323 1.61 thorpej struct se_softc *sc = device_private(self); 324 1.9 bouyer struct scsipibus_attach_args *sa = aux; 325 1.34 bouyer struct scsipi_periph *periph = sa->sa_periph; 326 1.1 thorpej struct ifnet *ifp = &sc->sc_ethercom.ec_if; 327 1.100 msaitoh uint8_t myaddr[ETHER_ADDR_LEN]; 328 1.106 jdc char wqname[MAXCOMLEN]; 329 1.95 msaitoh int rv; 330 1.1 thorpej 331 1.85 chs sc->sc_dev = self; 332 1.85 chs 333 1.5 matthias printf("\n"); 334 1.34 bouyer SC_DEBUG(periph, SCSIPI_DB2, ("seattach: ")); 335 1.1 thorpej 336 1.107 jdc sc->sc_attach_state = 0; 337 1.105 jdc callout_init(&sc->sc_recv_ch, CALLOUT_MPSAFE); 338 1.111 jdc callout_setfunc(&sc->sc_recv_ch, se_recv_callout, (void *)sc); 339 1.105 jdc mutex_init(&sc->sc_iflock, MUTEX_DEFAULT, IPL_SOFTNET); 340 1.28 thorpej 341 1.1 thorpej /* 342 1.1 thorpej * Store information needed to contact our base driver 343 1.1 thorpej */ 344 1.34 bouyer sc->sc_periph = periph; 345 1.85 chs periph->periph_dev = sc->sc_dev; 346 1.34 bouyer periph->periph_switch = &se_switch; 347 1.34 bouyer 348 1.1 thorpej se_poll = (SE_POLL * hz) / 1000; 349 1.1 thorpej se_poll = se_poll? se_poll: 1; 350 1.1 thorpej se_poll0 = (SE_POLL0 * hz) / 1000; 351 1.1 thorpej se_poll0 = se_poll0? se_poll0: 1; 352 1.1 thorpej 353 1.1 thorpej /* 354 1.106 jdc * Initialize and attach send and receive buffers 355 1.1 thorpej */ 356 1.1 thorpej sc->sc_tbuf = malloc(ETHERMTU + sizeof(struct ether_header), 357 1.103 chs M_DEVBUF, M_WAITOK); 358 1.106 jdc sc->sc_rbuf = malloc(RBUF_LEN, M_DEVBUF, M_WAITOK); 359 1.1 thorpej 360 1.1 thorpej /* Initialize ifnet structure. */ 361 1.85 chs strlcpy(ifp->if_xname, device_xname(sc->sc_dev), sizeof(ifp->if_xname)); 362 1.1 thorpej ifp->if_softc = sc; 363 1.1 thorpej ifp->if_start = se_ifstart; 364 1.1 thorpej ifp->if_ioctl = se_ioctl; 365 1.117 skrll ifp->if_watchdog = NULL; 366 1.99 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 367 1.106 jdc ifp->if_extflags = IFEF_MPSAFE; 368 1.33 thorpej IFQ_SET_READY(&ifp->if_snd); 369 1.1 thorpej 370 1.106 jdc se_get_addr(sc, myaddr); 371 1.107 jdc sc->sc_attach_state = 1; 372 1.106 jdc 373 1.1 thorpej /* Attach the interface. */ 374 1.113 riastrad if_initialize(ifp); 375 1.108 riastrad 376 1.106 jdc snprintf(wqname, sizeof(wqname), "%sRx", device_xname(sc->sc_dev)); 377 1.106 jdc rv = workqueue_create(&sc->sc_recv_wq, wqname, se_recv_worker, sc, 378 1.106 jdc PRI_SOFTNET, IPL_NET, WQ_MPSAFE); 379 1.106 jdc if (rv != 0) { 380 1.106 jdc aprint_error_dev(sc->sc_dev, 381 1.107 jdc "unable to create recv Rx workqueue\n"); 382 1.107 jdc sedetach(sc->sc_dev, 0); 383 1.106 jdc return; /* Error */ 384 1.106 jdc } 385 1.106 jdc sc->sc_recv_work_pending = false; 386 1.107 jdc sc->sc_attach_state = 2; 387 1.107 jdc 388 1.106 jdc snprintf(wqname, sizeof(wqname), "%sTx", device_xname(sc->sc_dev)); 389 1.106 jdc rv = workqueue_create(&sc->sc_send_wq, wqname, se_send_worker, ifp, 390 1.106 jdc PRI_SOFTNET, IPL_NET, WQ_MPSAFE); 391 1.106 jdc if (rv != 0) { 392 1.106 jdc aprint_error_dev(sc->sc_dev, 393 1.107 jdc "unable to create send Tx workqueue\n"); 394 1.107 jdc sedetach(sc->sc_dev, 0); 395 1.106 jdc return; /* Error */ 396 1.106 jdc } 397 1.106 jdc sc->sc_send_work_pending = false; 398 1.107 jdc sc->sc_attach_state = 3; 399 1.107 jdc 400 1.105 jdc sc->sc_ipq = if_percpuq_create(&sc->sc_ethercom.ec_if); 401 1.1 thorpej ether_ifattach(ifp, myaddr); 402 1.89 ozaki if_register(ifp); 403 1.107 jdc sc->sc_attach_state = 4; 404 1.107 jdc } 405 1.107 jdc 406 1.107 jdc static int 407 1.107 jdc sedetach(device_t self, int flags) 408 1.107 jdc { 409 1.107 jdc struct se_softc *sc = device_private(self); 410 1.107 jdc struct ifnet *ifp = &sc->sc_ethercom.ec_if; 411 1.107 jdc 412 1.107 jdc switch(sc->sc_attach_state) { 413 1.107 jdc case 4: 414 1.107 jdc se_stop(sc); 415 1.107 jdc mutex_enter(&sc->sc_iflock); 416 1.107 jdc ifp->if_flags &= ~IFF_RUNNING; 417 1.107 jdc se_disable(sc); 418 1.107 jdc ether_ifdetach(ifp); 419 1.107 jdc if_detach(ifp); 420 1.107 jdc mutex_exit(&sc->sc_iflock); 421 1.107 jdc if_percpuq_destroy(sc->sc_ipq); 422 1.107 jdc /*FALLTHROUGH*/ 423 1.107 jdc case 3: 424 1.107 jdc workqueue_destroy(sc->sc_send_wq); 425 1.107 jdc /*FALLTHROUGH*/ 426 1.107 jdc case 2: 427 1.107 jdc workqueue_destroy(sc->sc_recv_wq); 428 1.107 jdc /*FALLTHROUGH*/ 429 1.107 jdc case 1: 430 1.107 jdc free(sc->sc_rbuf, M_DEVBUF); 431 1.107 jdc free(sc->sc_tbuf, M_DEVBUF); 432 1.107 jdc callout_destroy(&sc->sc_recv_ch); 433 1.107 jdc mutex_destroy(&sc->sc_iflock); 434 1.107 jdc break; 435 1.107 jdc default: 436 1.107 jdc aprint_error_dev(sc->sc_dev, "detach failed (state %d)\n", 437 1.107 jdc sc->sc_attach_state); 438 1.107 jdc return 1; 439 1.107 jdc break; 440 1.107 jdc } 441 1.107 jdc return 0; 442 1.1 thorpej } 443 1.1 thorpej 444 1.105 jdc /* 445 1.105 jdc * Send a command to the device 446 1.105 jdc */ 447 1.60 perry static inline int 448 1.84 christos se_scsipi_cmd(struct scsipi_periph *periph, struct scsipi_generic *cmd, 449 1.84 christos int cmdlen, u_char *data_addr, int datalen, int retries, int timeout, 450 1.84 christos struct buf *bp, int flags) 451 1.1 thorpej { 452 1.1 thorpej int error; 453 1.10 enami 454 1.50 mycroft error = scsipi_command(periph, cmd, cmdlen, data_addr, 455 1.10 enami datalen, retries, timeout, bp, flags); 456 1.10 enami return (error); 457 1.1 thorpej } 458 1.5 matthias 459 1.105 jdc /* 460 1.106 jdc * Start routine for calling from network sub system 461 1.105 jdc */ 462 1.5 matthias static void 463 1.106 jdc se_ifstart(struct ifnet *ifp) 464 1.1 thorpej { 465 1.21 thorpej struct se_softc *sc = ifp->if_softc; 466 1.10 enami 467 1.106 jdc mutex_enter(&sc->sc_iflock); 468 1.111 jdc if (!sc->sc_send_work_pending) { 469 1.106 jdc sc->sc_send_work_pending = true; 470 1.106 jdc workqueue_enqueue(sc->sc_send_wq, &sc->sc_send_work, NULL); 471 1.116 skrll } 472 1.111 jdc /* else: nothing to do - work is already queued */ 473 1.106 jdc mutex_exit(&sc->sc_iflock); 474 1.1 thorpej } 475 1.1 thorpej 476 1.1 thorpej /* 477 1.106 jdc * Invoke the transmit workqueue and transmission on the interface. 478 1.1 thorpej */ 479 1.5 matthias static void 480 1.106 jdc se_send_worker(struct work *wk, void *cookie) 481 1.1 thorpej { 482 1.106 jdc struct ifnet *ifp = cookie; 483 1.1 thorpej struct se_softc *sc = ifp->if_softc; 484 1.1 thorpej struct scsi_ctron_ether_generic send_cmd; 485 1.1 thorpej struct mbuf *m, *m0; 486 1.1 thorpej int len, error; 487 1.55 reinoud u_char *cp; 488 1.1 thorpej 489 1.106 jdc mutex_enter(&sc->sc_iflock); 490 1.106 jdc sc->sc_send_work_pending = false; 491 1.106 jdc mutex_exit(&sc->sc_iflock); 492 1.106 jdc 493 1.106 jdc KASSERT(if_is_mpsafe(ifp)); 494 1.106 jdc 495 1.1 thorpej /* Don't transmit if interface is busy or not running */ 496 1.100 msaitoh if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 497 1.1 thorpej return; 498 1.1 thorpej 499 1.106 jdc while (1) { 500 1.106 jdc IFQ_DEQUEUE(&ifp->if_snd, m0); 501 1.106 jdc if (m0 == 0) 502 1.106 jdc break; 503 1.105 jdc 504 1.106 jdc /* If BPF is listening on this interface, let it see the 505 1.106 jdc * packet before we commit it to the wire. 506 1.106 jdc */ 507 1.106 jdc bpf_mtap(ifp, m0, BPF_D_OUT); 508 1.106 jdc 509 1.106 jdc /* We need to use m->m_pkthdr.len, so require the header */ 510 1.106 jdc if ((m0->m_flags & M_PKTHDR) == 0) 511 1.106 jdc panic("ctscstart: no header mbuf"); 512 1.106 jdc len = m0->m_pkthdr.len; 513 1.106 jdc 514 1.106 jdc /* Mark the interface busy. */ 515 1.106 jdc ifp->if_flags |= IFF_OACTIVE; 516 1.106 jdc 517 1.106 jdc /* Chain; copy into linear buffer allocated at attach time. */ 518 1.106 jdc cp = sc->sc_tbuf; 519 1.106 jdc for (m = m0; m != NULL; ) { 520 1.106 jdc memcpy(cp, mtod(m, u_char *), m->m_len); 521 1.106 jdc cp += m->m_len; 522 1.106 jdc m = m0 = m_free(m); 523 1.106 jdc } 524 1.106 jdc if (len < SEMINSIZE) { 525 1.1 thorpej #ifdef SEDEBUG 526 1.106 jdc if (sc->sc_debug) 527 1.106 jdc printf("se: packet size %d (%zu) < %d\n", len, 528 1.106 jdc cp - (u_char *)sc->sc_tbuf, SEMINSIZE); 529 1.1 thorpej #endif 530 1.106 jdc memset(cp, 0, SEMINSIZE - len); 531 1.106 jdc len = SEMINSIZE; 532 1.106 jdc } 533 1.106 jdc 534 1.106 jdc /* Fill out SCSI command. */ 535 1.106 jdc PROTOCMD(ctron_ether_send, send_cmd); 536 1.106 jdc _lto2b(len, send_cmd.length); 537 1.106 jdc 538 1.106 jdc /* Send command to device. */ 539 1.106 jdc error = se_scsipi_cmd(sc->sc_periph, 540 1.106 jdc (void *)&send_cmd, sizeof(send_cmd), 541 1.106 jdc sc->sc_tbuf, len, SERETRIES, 542 1.106 jdc SETIMEOUT, NULL, XS_CTL_NOSLEEP | XS_CTL_DATA_OUT); 543 1.106 jdc if (error) { 544 1.106 jdc aprint_error_dev(sc->sc_dev, 545 1.106 jdc "not queued, error %d\n", error); 546 1.106 jdc if_statinc(ifp, if_oerrors); 547 1.106 jdc ifp->if_flags &= ~IFF_OACTIVE; 548 1.106 jdc } else 549 1.106 jdc if_statinc(ifp, if_opackets); 550 1.1 thorpej } 551 1.1 thorpej } 552 1.1 thorpej 553 1.1 thorpej 554 1.1 thorpej /* 555 1.1 thorpej * Called from the scsibus layer via our scsi device switch. 556 1.1 thorpej */ 557 1.4 mycroft static void 558 1.75 dsl sedone(struct scsipi_xfer *xs, int error) 559 1.1 thorpej { 560 1.85 chs struct se_softc *sc = device_private(xs->xs_periph->periph_dev); 561 1.9 bouyer struct scsipi_generic *cmd = xs->cmd; 562 1.1 thorpej struct ifnet *ifp = &sc->sc_ethercom.ec_if; 563 1.4 mycroft 564 1.100 msaitoh if (IS_SEND(cmd)) { 565 1.106 jdc ifp->if_flags &= ~IFF_OACTIVE; 566 1.100 msaitoh } else if (IS_RECV(cmd)) { 567 1.4 mycroft /* RECV complete */ 568 1.4 mycroft /* pass data up. reschedule a recv */ 569 1.9 bouyer /* scsipi_free_xs will call start. Harmless. */ 570 1.4 mycroft if (error) { 571 1.4 mycroft /* Reschedule after a delay */ 572 1.111 jdc callout_schedule(&sc->sc_recv_ch, se_poll); 573 1.4 mycroft } else { 574 1.11 matthias int n, ntimeo; 575 1.4 mycroft n = se_read(sc, xs->data, xs->datalen - xs->resid); 576 1.105 jdc #ifdef SE_DEBUG 577 1.11 matthias if (n > se_max_received) 578 1.11 matthias se_max_received = n; 579 1.105 jdc #endif 580 1.11 matthias if (n == 0) 581 1.11 matthias ntimeo = se_poll; 582 1.11 matthias else if (n >= RDATA_MAX) 583 1.11 matthias ntimeo = se_poll0; 584 1.11 matthias else { 585 1.11 matthias ntimeo = sc->sc_last_timeout; 586 1.11 matthias ntimeo = (ntimeo * RDATA_GOAL)/n; 587 1.11 matthias ntimeo = (ntimeo < se_poll0? 588 1.11 matthias se_poll0: ntimeo); 589 1.11 matthias ntimeo = (ntimeo > se_poll? 590 1.11 matthias se_poll: ntimeo); 591 1.1 thorpej } 592 1.11 matthias sc->sc_last_timeout = ntimeo; 593 1.111 jdc callout_schedule(&sc->sc_recv_ch, ntimeo); 594 1.1 thorpej } 595 1.1 thorpej } 596 1.1 thorpej } 597 1.10 enami 598 1.106 jdc /* 599 1.106 jdc * Setup a receive command by queuing the work. 600 1.106 jdc * Usually called from a callout, but also from se_init(). 601 1.106 jdc */ 602 1.5 matthias static void 603 1.106 jdc se_recv_callout(void *v) 604 1.1 thorpej { 605 1.1 thorpej /* do a recv command */ 606 1.1 thorpej struct se_softc *sc = (struct se_softc *) v; 607 1.1 thorpej 608 1.21 thorpej if (sc->sc_enabled == 0) 609 1.21 thorpej return; 610 1.21 thorpej 611 1.106 jdc mutex_enter(&sc->sc_iflock); 612 1.106 jdc if (sc->sc_recv_work_pending == true) { 613 1.111 jdc callout_schedule(&sc->sc_recv_ch, se_poll); 614 1.111 jdc mutex_exit(&sc->sc_iflock); 615 1.106 jdc return; 616 1.106 jdc } 617 1.106 jdc 618 1.106 jdc sc->sc_recv_work_pending = true; 619 1.106 jdc workqueue_enqueue(sc->sc_recv_wq, &sc->sc_recv_work, NULL); 620 1.106 jdc mutex_exit(&sc->sc_iflock); 621 1.106 jdc } 622 1.106 jdc 623 1.106 jdc /* 624 1.106 jdc * Invoke the receive workqueue 625 1.106 jdc */ 626 1.106 jdc static void 627 1.106 jdc se_recv_worker(struct work *wk, void *cookie) 628 1.106 jdc { 629 1.106 jdc struct se_softc *sc = (struct se_softc *) cookie; 630 1.106 jdc 631 1.106 jdc mutex_enter(&sc->sc_iflock); 632 1.106 jdc sc->sc_recv_work_pending = false; 633 1.106 jdc mutex_exit(&sc->sc_iflock); 634 1.106 jdc se_recv(sc); 635 1.106 jdc 636 1.106 jdc } 637 1.106 jdc 638 1.106 jdc /* 639 1.106 jdc * Do the actual work of receiving data. 640 1.106 jdc */ 641 1.106 jdc static void 642 1.106 jdc se_recv(struct se_softc *sc) 643 1.106 jdc { 644 1.106 jdc struct scsi_ctron_ether_recv recv_cmd; 645 1.106 jdc int error; 646 1.106 jdc 647 1.106 jdc /* do a recv command */ 648 1.1 thorpej PROTOCMD(ctron_ether_recv, recv_cmd); 649 1.1 thorpej 650 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 651 1.50 mycroft (void *)&recv_cmd, sizeof(recv_cmd), 652 1.10 enami sc->sc_rbuf, RBUF_LEN, SERETRIES, SETIMEOUT, NULL, 653 1.105 jdc XS_CTL_NOSLEEP | XS_CTL_DATA_IN); 654 1.1 thorpej if (error) 655 1.111 jdc callout_schedule(&sc->sc_recv_ch, se_poll); 656 1.1 thorpej } 657 1.1 thorpej 658 1.1 thorpej /* 659 1.1 thorpej * We copy the data into mbufs. When full cluster sized units are present 660 1.1 thorpej * we copy into clusters. 661 1.1 thorpej */ 662 1.1 thorpej static struct mbuf * 663 1.75 dsl se_get(struct se_softc *sc, char *data, int totlen) 664 1.1 thorpej { 665 1.1 thorpej struct ifnet *ifp = &sc->sc_ethercom.ec_if; 666 1.23 mycroft struct mbuf *m, *m0, *newm; 667 1.23 mycroft int len; 668 1.1 thorpej 669 1.23 mycroft MGETHDR(m0, M_DONTWAIT, MT_DATA); 670 1.23 mycroft if (m0 == 0) 671 1.1 thorpej return (0); 672 1.90 ozaki m_set_rcvif(m0, ifp); 673 1.23 mycroft m0->m_pkthdr.len = totlen; 674 1.23 mycroft len = MHLEN; 675 1.23 mycroft m = m0; 676 1.1 thorpej 677 1.1 thorpej while (totlen > 0) { 678 1.6 mycroft if (totlen >= MINCLSIZE) { 679 1.1 thorpej MCLGET(m, M_DONTWAIT); 680 1.23 mycroft if ((m->m_flags & M_EXT) == 0) 681 1.23 mycroft goto bad; 682 1.6 mycroft len = MCLBYTES; 683 1.1 thorpej } 684 1.23 mycroft 685 1.23 mycroft if (m == m0) { 686 1.65 yamt char *newdata = (char *) 687 1.23 mycroft ALIGN(m->m_data + sizeof(struct ether_header)) - 688 1.23 mycroft sizeof(struct ether_header); 689 1.23 mycroft len -= newdata - m->m_data; 690 1.23 mycroft m->m_data = newdata; 691 1.23 mycroft } 692 1.23 mycroft 693 1.98 riastrad m->m_len = len = uimin(totlen, len); 694 1.64 christos memcpy(mtod(m, void *), data, len); 695 1.1 thorpej data += len; 696 1.23 mycroft 697 1.1 thorpej totlen -= len; 698 1.23 mycroft if (totlen > 0) { 699 1.23 mycroft MGET(newm, M_DONTWAIT, MT_DATA); 700 1.23 mycroft if (newm == 0) 701 1.23 mycroft goto bad; 702 1.23 mycroft len = MLEN; 703 1.23 mycroft m = m->m_next = newm; 704 1.23 mycroft } 705 1.1 thorpej } 706 1.1 thorpej 707 1.23 mycroft return (m0); 708 1.23 mycroft 709 1.23 mycroft bad: 710 1.23 mycroft m_freem(m0); 711 1.23 mycroft return (0); 712 1.1 thorpej } 713 1.1 thorpej 714 1.1 thorpej /* 715 1.1 thorpej * Pass packets to higher levels. 716 1.1 thorpej */ 717 1.1 thorpej static int 718 1.75 dsl se_read(struct se_softc *sc, char *data, int datalen) 719 1.1 thorpej { 720 1.1 thorpej struct mbuf *m; 721 1.1 thorpej struct ifnet *ifp = &sc->sc_ethercom.ec_if; 722 1.1 thorpej int n; 723 1.1 thorpej 724 1.1 thorpej n = 0; 725 1.1 thorpej while (datalen >= 2) { 726 1.1 thorpej int len = _2btol(data); 727 1.1 thorpej data += 2; 728 1.1 thorpej datalen -= 2; 729 1.1 thorpej 730 1.1 thorpej if (len == 0) 731 1.1 thorpej break; 732 1.1 thorpej #ifdef SEDEBUG 733 1.1 thorpej if (sc->sc_debug) { 734 1.1 thorpej printf("se_read: datalen = %d, packetlen = %d, proto = 0x%04x\n", datalen, len, 735 1.1 thorpej ntohs(((struct ether_header *)data)->ether_type)); 736 1.1 thorpej } 737 1.1 thorpej #endif 738 1.1 thorpej if (len <= sizeof(struct ether_header) || 739 1.1 thorpej len > MAX_SNAP) { 740 1.1 thorpej #ifdef SEDEBUG 741 1.1 thorpej printf("%s: invalid packet size %d; dropping\n", 742 1.85 chs device_xname(sc->sc_dev), len); 743 1.1 thorpej #endif 744 1.104 thorpej if_statinc(ifp, if_ierrors); 745 1.1 thorpej goto next_packet; 746 1.1 thorpej } 747 1.1 thorpej 748 1.1 thorpej /* Don't need crc. Must keep ether header for BPF */ 749 1.1 thorpej m = se_get(sc, data, len - ETHER_CRC); 750 1.1 thorpej if (m == 0) { 751 1.1 thorpej #ifdef SEDEBUG 752 1.10 enami if (sc->sc_debug) 753 1.1 thorpej printf("se_read: se_get returned null\n"); 754 1.1 thorpej #endif 755 1.104 thorpej if_statinc(ifp, if_ierrors); 756 1.1 thorpej goto next_packet; 757 1.1 thorpej } 758 1.1 thorpej if ((ifp->if_flags & IFF_PROMISC) != 0) { 759 1.5 matthias m_adj(m, SE_PREFIX); 760 1.1 thorpej } 761 1.1 thorpej 762 1.24 thorpej /* Pass the packet up. */ 763 1.105 jdc if_percpuq_enqueue(sc->sc_ipq, m); 764 1.1 thorpej 765 1.1 thorpej next_packet: 766 1.1 thorpej data += len; 767 1.1 thorpej datalen -= len; 768 1.1 thorpej n++; 769 1.1 thorpej } 770 1.10 enami return (n); 771 1.1 thorpej } 772 1.1 thorpej 773 1.117 skrll #if 0 774 1.5 matthias static void 775 1.75 dsl sewatchdog(struct ifnet *ifp) 776 1.1 thorpej { 777 1.1 thorpej struct se_softc *sc = ifp->if_softc; 778 1.1 thorpej 779 1.85 chs log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 780 1.104 thorpej if_statinc(ifp, if_oerrors); 781 1.1 thorpej 782 1.1 thorpej se_reset(sc); 783 1.1 thorpej } 784 1.1 thorpej 785 1.106 jdc static void 786 1.75 dsl se_reset(struct se_softc *sc) 787 1.1 thorpej { 788 1.1 thorpej #if 0 789 1.1 thorpej /* Maybe we don't *really* want to reset the entire bus 790 1.1 thorpej * because the ctron isn't working. We would like to send a 791 1.1 thorpej * "BUS DEVICE RESET" message, but don't think the ctron 792 1.1 thorpej * understands it. 793 1.1 thorpej */ 794 1.106 jdc se_scsipi_cmd(sc->sc_periph, 0, 0, 0, 0, SERETRIES, 2000, NULL, 795 1.25 thorpej XS_CTL_RESET); 796 1.1 thorpej #endif 797 1.106 jdc se_init(sc); 798 1.1 thorpej } 799 1.118 skrll #endif 800 1.1 thorpej 801 1.5 matthias static int 802 1.75 dsl se_add_proto(struct se_softc *sc, int proto) 803 1.1 thorpej { 804 1.10 enami int error; 805 1.1 thorpej struct scsi_ctron_ether_generic add_proto_cmd; 806 1.100 msaitoh uint8_t data[2]; 807 1.1 thorpej _lto2b(proto, data); 808 1.1 thorpej #ifdef SEDEBUG 809 1.1 thorpej if (sc->sc_debug) 810 1.1 thorpej printf("se: adding proto 0x%02x%02x\n", data[0], data[1]); 811 1.1 thorpej #endif 812 1.1 thorpej 813 1.1 thorpej PROTOCMD(ctron_ether_add_proto, add_proto_cmd); 814 1.1 thorpej _lto2b(sizeof(data), add_proto_cmd.length); 815 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 816 1.50 mycroft (void *)&add_proto_cmd, sizeof(add_proto_cmd), 817 1.30 enami data, sizeof(data), SERETRIES, SETIMEOUT, NULL, 818 1.79 rmind XS_CTL_DATA_OUT); 819 1.10 enami return (error); 820 1.1 thorpej } 821 1.1 thorpej 822 1.5 matthias static int 823 1.100 msaitoh se_get_addr(struct se_softc *sc, uint8_t *myaddr) 824 1.1 thorpej { 825 1.10 enami int error; 826 1.1 thorpej struct scsi_ctron_ether_generic get_addr_cmd; 827 1.1 thorpej 828 1.1 thorpej PROTOCMD(ctron_ether_get_addr, get_addr_cmd); 829 1.1 thorpej _lto2b(ETHER_ADDR_LEN, get_addr_cmd.length); 830 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 831 1.50 mycroft (void *)&get_addr_cmd, sizeof(get_addr_cmd), 832 1.30 enami myaddr, ETHER_ADDR_LEN, SERETRIES, SETIMEOUT, NULL, 833 1.79 rmind XS_CTL_DATA_IN); 834 1.85 chs printf("%s: ethernet address %s\n", device_xname(sc->sc_dev), 835 1.1 thorpej ether_sprintf(myaddr)); 836 1.10 enami return (error); 837 1.1 thorpej } 838 1.1 thorpej 839 1.1 thorpej 840 1.5 matthias static int 841 1.75 dsl se_set_media(struct se_softc *sc, int type) 842 1.1 thorpej { 843 1.10 enami int error; 844 1.1 thorpej struct scsi_ctron_ether_generic set_media_cmd; 845 1.1 thorpej 846 1.1 thorpej PROTOCMD(ctron_ether_set_media, set_media_cmd); 847 1.1 thorpej set_media_cmd.byte3 = type; 848 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 849 1.50 mycroft (void *)&set_media_cmd, sizeof(set_media_cmd), 850 1.10 enami 0, 0, SERETRIES, SETIMEOUT, NULL, 0); 851 1.10 enami return (error); 852 1.1 thorpej } 853 1.1 thorpej 854 1.5 matthias static int 855 1.75 dsl se_set_mode(struct se_softc *sc, int len, int mode) 856 1.1 thorpej { 857 1.10 enami int error; 858 1.1 thorpej struct scsi_ctron_ether_set_mode set_mode_cmd; 859 1.1 thorpej 860 1.1 thorpej PROTOCMD(ctron_ether_set_mode, set_mode_cmd); 861 1.1 thorpej set_mode_cmd.mode = mode; 862 1.1 thorpej _lto2b(len, set_mode_cmd.length); 863 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 864 1.50 mycroft (void *)&set_mode_cmd, sizeof(set_mode_cmd), 865 1.10 enami 0, 0, SERETRIES, SETIMEOUT, NULL, 0); 866 1.10 enami return (error); 867 1.1 thorpej } 868 1.1 thorpej 869 1.1 thorpej 870 1.5 matthias static int 871 1.75 dsl se_init(struct se_softc *sc) 872 1.1 thorpej { 873 1.1 thorpej struct ifnet *ifp = &sc->sc_ethercom.ec_if; 874 1.1 thorpej struct scsi_ctron_ether_generic set_addr_cmd; 875 1.70 dyoung uint8_t enaddr[ETHER_ADDR_LEN]; 876 1.1 thorpej int error; 877 1.1 thorpej 878 1.1 thorpej if (ifp->if_flags & IFF_PROMISC) { 879 1.1 thorpej error = se_set_mode(sc, MAX_SNAP, 1); 880 1.1 thorpej } 881 1.1 thorpej else 882 1.1 thorpej error = se_set_mode(sc, ETHERMTU + sizeof(struct ether_header), 883 1.10 enami 0); 884 1.5 matthias if (error != 0) 885 1.10 enami return (error); 886 1.5 matthias 887 1.1 thorpej PROTOCMD(ctron_ether_set_addr, set_addr_cmd); 888 1.1 thorpej _lto2b(ETHER_ADDR_LEN, set_addr_cmd.length); 889 1.70 dyoung memcpy(enaddr, CLLADDR(ifp->if_sadl), sizeof(enaddr)); 890 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 891 1.50 mycroft (void *)&set_addr_cmd, sizeof(set_addr_cmd), 892 1.70 dyoung enaddr, ETHER_ADDR_LEN, SERETRIES, SETIMEOUT, NULL, 893 1.25 thorpej XS_CTL_DATA_OUT); 894 1.10 enami if (error != 0) 895 1.10 enami return (error); 896 1.1 thorpej 897 1.1 thorpej if ((sc->protos & PROTO_IP) && 898 1.1 thorpej (error = se_add_proto(sc, ETHERTYPE_IP)) != 0) 899 1.10 enami return (error); 900 1.1 thorpej if ((sc->protos & PROTO_ARP) && 901 1.1 thorpej (error = se_add_proto(sc, ETHERTYPE_ARP)) != 0) 902 1.10 enami return (error); 903 1.1 thorpej if ((sc->protos & PROTO_REVARP) && 904 1.1 thorpej (error = se_add_proto(sc, ETHERTYPE_REVARP)) != 0) 905 1.10 enami return (error); 906 1.5 matthias #ifdef NETATALK 907 1.5 matthias if ((sc->protos & PROTO_AT) && 908 1.20 kim (error = se_add_proto(sc, ETHERTYPE_ATALK)) != 0) 909 1.10 enami return (error); 910 1.5 matthias if ((sc->protos & PROTO_AARP) && 911 1.5 matthias (error = se_add_proto(sc, ETHERTYPE_AARP)) != 0) 912 1.10 enami return (error); 913 1.5 matthias #endif 914 1.1 thorpej 915 1.100 msaitoh if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == IFF_UP) { 916 1.1 thorpej ifp->if_flags |= IFF_RUNNING; 917 1.106 jdc mutex_enter(&sc->sc_iflock); 918 1.111 jdc if (!sc->sc_recv_work_pending) { 919 1.111 jdc sc->sc_recv_work_pending = true; 920 1.111 jdc workqueue_enqueue(sc->sc_recv_wq, &sc->sc_recv_work, 921 1.111 jdc NULL); 922 1.116 skrll } 923 1.106 jdc mutex_exit(&sc->sc_iflock); 924 1.1 thorpej ifp->if_flags &= ~IFF_OACTIVE; 925 1.106 jdc mutex_enter(&sc->sc_iflock); 926 1.111 jdc if (!sc->sc_send_work_pending) { 927 1.111 jdc sc->sc_send_work_pending = true; 928 1.111 jdc workqueue_enqueue(sc->sc_send_wq, &sc->sc_send_work, 929 1.111 jdc NULL); 930 1.116 skrll } 931 1.106 jdc mutex_exit(&sc->sc_iflock); 932 1.1 thorpej } 933 1.10 enami return (error); 934 1.1 thorpej } 935 1.1 thorpej 936 1.5 matthias static int 937 1.100 msaitoh se_set_multi(struct se_softc *sc, uint8_t *addr) 938 1.1 thorpej { 939 1.1 thorpej struct scsi_ctron_ether_generic set_multi_cmd; 940 1.1 thorpej int error; 941 1.1 thorpej 942 1.1 thorpej if (sc->sc_debug) 943 1.85 chs printf("%s: set_set_multi: %s\n", device_xname(sc->sc_dev), 944 1.1 thorpej ether_sprintf(addr)); 945 1.1 thorpej 946 1.1 thorpej PROTOCMD(ctron_ether_set_multi, set_multi_cmd); 947 1.106 jdc _lto2b(ETHER_ADDR_LEN, set_multi_cmd.length); 948 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 949 1.50 mycroft (void *)&set_multi_cmd, sizeof(set_multi_cmd), 950 1.106 jdc addr, ETHER_ADDR_LEN, SERETRIES, SETIMEOUT, NULL, XS_CTL_DATA_OUT); 951 1.10 enami return (error); 952 1.1 thorpej } 953 1.1 thorpej 954 1.5 matthias static int 955 1.100 msaitoh se_remove_multi(struct se_softc *sc, uint8_t *addr) 956 1.1 thorpej { 957 1.1 thorpej struct scsi_ctron_ether_generic remove_multi_cmd; 958 1.1 thorpej int error; 959 1.1 thorpej 960 1.1 thorpej if (sc->sc_debug) 961 1.85 chs printf("%s: se_remove_multi: %s\n", device_xname(sc->sc_dev), 962 1.1 thorpej ether_sprintf(addr)); 963 1.1 thorpej 964 1.1 thorpej PROTOCMD(ctron_ether_remove_multi, remove_multi_cmd); 965 1.106 jdc _lto2b(ETHER_ADDR_LEN, remove_multi_cmd.length); 966 1.34 bouyer error = se_scsipi_cmd(sc->sc_periph, 967 1.50 mycroft (void *)&remove_multi_cmd, sizeof(remove_multi_cmd), 968 1.106 jdc addr, ETHER_ADDR_LEN, SERETRIES, SETIMEOUT, NULL, XS_CTL_DATA_OUT); 969 1.10 enami return (error); 970 1.1 thorpej } 971 1.1 thorpej 972 1.1 thorpej #if 0 /* not used --thorpej */ 973 1.5 matthias static int 974 1.75 dsl sc_set_all_multi(struct se_softc *sc, int set) 975 1.1 thorpej { 976 1.1 thorpej int error = 0; 977 1.100 msaitoh uint8_t *addr; 978 1.100 msaitoh struct ethercom *ec = &sc->sc_ethercom; 979 1.1 thorpej struct ether_multi *enm; 980 1.1 thorpej struct ether_multistep step; 981 1.10 enami 982 1.102 msaitoh ETHER_LOCK(ec); 983 1.100 msaitoh ETHER_FIRST_MULTI(step, ec, enm); 984 1.1 thorpej while (enm != NULL) { 985 1.1 thorpej if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) { 986 1.1 thorpej /* 987 1.1 thorpej * We must listen to a range of multicast addresses. 988 1.1 thorpej * For now, just accept all multicasts, rather than 989 1.1 thorpej * trying to set only those filter bits needed to match 990 1.1 thorpej * the range. (At this time, the only use of address 991 1.1 thorpej * ranges is for IP multicast routing, for which the 992 1.1 thorpej * range is big enough to require all bits set.) 993 1.1 thorpej */ 994 1.1 thorpej /* We have no way of adding a range to this device. 995 1.1 thorpej * stepping through all addresses in the range is 996 1.1 thorpej * typically not possible. The only real alternative 997 1.1 thorpej * is to go into promicuous mode and filter by hand. 998 1.1 thorpej */ 999 1.102 msaitoh ETHER_UNLOCK(ec); 1000 1.10 enami return (ENODEV); 1001 1.1 thorpej 1002 1.1 thorpej } 1003 1.1 thorpej 1004 1.1 thorpej addr = enm->enm_addrlo; 1005 1.10 enami if ((error = set ? se_set_multi(sc, addr) : 1006 1.10 enami se_remove_multi(sc, addr)) != 0) 1007 1.10 enami return (error); 1008 1.1 thorpej ETHER_NEXT_MULTI(step, enm); 1009 1.1 thorpej } 1010 1.102 msaitoh ETHER_UNLOCK(ec); 1011 1.102 msaitoh 1012 1.10 enami return (error); 1013 1.1 thorpej } 1014 1.1 thorpej #endif /* not used */ 1015 1.1 thorpej 1016 1.5 matthias static void 1017 1.75 dsl se_stop(struct se_softc *sc) 1018 1.1 thorpej { 1019 1.10 enami 1020 1.1 thorpej /* Don't schedule any reads */ 1021 1.111 jdc callout_halt(&sc->sc_recv_ch, &sc->sc_iflock); 1022 1.5 matthias 1023 1.106 jdc /* Wait for the workqueues to finish */ 1024 1.106 jdc mutex_enter(&sc->sc_iflock); 1025 1.106 jdc workqueue_wait(sc->sc_recv_wq, &sc->sc_recv_work); 1026 1.106 jdc workqueue_wait(sc->sc_send_wq, &sc->sc_send_work); 1027 1.106 jdc mutex_exit(&sc->sc_iflock); 1028 1.106 jdc 1029 1.105 jdc /* Abort any scsi cmds in progress */ 1030 1.105 jdc mutex_enter(chan_mtx(sc->sc_periph->periph_channel)); 1031 1.105 jdc scsipi_kill_pending(sc->sc_periph); 1032 1.105 jdc mutex_exit(chan_mtx(sc->sc_periph->periph_channel)); 1033 1.1 thorpej } 1034 1.1 thorpej 1035 1.1 thorpej 1036 1.1 thorpej /* 1037 1.1 thorpej * Process an ioctl request. 1038 1.1 thorpej */ 1039 1.5 matthias static int 1040 1.73 dyoung se_ioctl(struct ifnet *ifp, u_long cmd, void *data) 1041 1.1 thorpej { 1042 1.29 augustss struct se_softc *sc = ifp->if_softc; 1043 1.1 thorpej struct ifaddr *ifa = (struct ifaddr *)data; 1044 1.1 thorpej struct ifreq *ifr = (struct ifreq *)data; 1045 1.68 dyoung struct sockaddr *sa; 1046 1.105 jdc int error = 0; 1047 1.1 thorpej 1048 1.1 thorpej 1049 1.1 thorpej switch (cmd) { 1050 1.1 thorpej 1051 1.73 dyoung case SIOCINITIFADDR: 1052 1.105 jdc mutex_enter(&sc->sc_iflock); 1053 1.21 thorpej if ((error = se_enable(sc)) != 0) 1054 1.21 thorpej break; 1055 1.1 thorpej ifp->if_flags |= IFF_UP; 1056 1.105 jdc mutex_exit(&sc->sc_iflock); 1057 1.1 thorpej 1058 1.83 mbalmer if ((error = se_set_media(sc, CMEDIA_AUTOSENSE)) != 0) 1059 1.21 thorpej break; 1060 1.5 matthias 1061 1.1 thorpej switch (ifa->ifa_addr->sa_family) { 1062 1.1 thorpej #ifdef INET 1063 1.1 thorpej case AF_INET: 1064 1.1 thorpej sc->protos |= (PROTO_IP | PROTO_ARP | PROTO_REVARP); 1065 1.1 thorpej if ((error = se_init(sc)) != 0) 1066 1.1 thorpej break; 1067 1.1 thorpej arp_ifinit(ifp, ifa); 1068 1.1 thorpej break; 1069 1.1 thorpej #endif 1070 1.5 matthias #ifdef NETATALK 1071 1.5 matthias case AF_APPLETALK: 1072 1.5 matthias sc->protos |= (PROTO_AT | PROTO_AARP); 1073 1.5 matthias if ((error = se_init(sc)) != 0) 1074 1.5 matthias break; 1075 1.5 matthias break; 1076 1.5 matthias #endif 1077 1.1 thorpej default: 1078 1.1 thorpej error = se_init(sc); 1079 1.1 thorpej break; 1080 1.1 thorpej } 1081 1.1 thorpej break; 1082 1.1 thorpej 1083 1.1 thorpej 1084 1.1 thorpej case SIOCSIFFLAGS: 1085 1.73 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 1086 1.73 dyoung break; 1087 1.73 dyoung /* XXX re-use ether_ioctl() */ 1088 1.100 msaitoh switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 1089 1.73 dyoung case IFF_RUNNING: 1090 1.1 thorpej /* 1091 1.1 thorpej * If interface is marked down and it is running, then 1092 1.1 thorpej * stop it. 1093 1.1 thorpej */ 1094 1.1 thorpej se_stop(sc); 1095 1.105 jdc mutex_enter(&sc->sc_iflock); 1096 1.1 thorpej ifp->if_flags &= ~IFF_RUNNING; 1097 1.21 thorpej se_disable(sc); 1098 1.105 jdc mutex_exit(&sc->sc_iflock); 1099 1.73 dyoung break; 1100 1.73 dyoung case IFF_UP: 1101 1.1 thorpej /* 1102 1.1 thorpej * If interface is marked up and it is stopped, then 1103 1.1 thorpej * start it. 1104 1.1 thorpej */ 1105 1.105 jdc mutex_enter(&sc->sc_iflock); 1106 1.105 jdc error = se_enable(sc); 1107 1.105 jdc mutex_exit(&sc->sc_iflock); 1108 1.105 jdc if (error) 1109 1.21 thorpej break; 1110 1.1 thorpej error = se_init(sc); 1111 1.73 dyoung break; 1112 1.73 dyoung default: 1113 1.1 thorpej /* 1114 1.1 thorpej * Reset the interface to pick up changes in any other 1115 1.1 thorpej * flags that affect hardware registers. 1116 1.1 thorpej */ 1117 1.73 dyoung if (sc->sc_enabled) 1118 1.73 dyoung error = se_init(sc); 1119 1.73 dyoung break; 1120 1.1 thorpej } 1121 1.1 thorpej #ifdef SEDEBUG 1122 1.1 thorpej if (ifp->if_flags & IFF_DEBUG) 1123 1.1 thorpej sc->sc_debug = 1; 1124 1.1 thorpej else 1125 1.1 thorpej sc->sc_debug = 0; 1126 1.1 thorpej #endif 1127 1.1 thorpej break; 1128 1.1 thorpej 1129 1.1 thorpej case SIOCADDMULTI: 1130 1.1 thorpej case SIOCDELMULTI: 1131 1.105 jdc mutex_enter(&sc->sc_iflock); 1132 1.103 chs sa = sockaddr_dup(ifreq_getaddr(cmd, ifr), M_WAITOK); 1133 1.105 jdc mutex_exit(&sc->sc_iflock); 1134 1.67 dyoung if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 1135 1.51 thorpej if (ifp->if_flags & IFF_RUNNING) { 1136 1.51 thorpej error = (cmd == SIOCADDMULTI) ? 1137 1.68 dyoung se_set_multi(sc, sa->sa_data) : 1138 1.68 dyoung se_remove_multi(sc, sa->sa_data); 1139 1.51 thorpej } else 1140 1.51 thorpej error = 0; 1141 1.21 thorpej } 1142 1.105 jdc mutex_enter(&sc->sc_iflock); 1143 1.68 dyoung sockaddr_free(sa); 1144 1.105 jdc mutex_exit(&sc->sc_iflock); 1145 1.1 thorpej break; 1146 1.1 thorpej 1147 1.1 thorpej default: 1148 1.1 thorpej 1149 1.73 dyoung error = ether_ioctl(ifp, cmd, data); 1150 1.1 thorpej break; 1151 1.1 thorpej } 1152 1.1 thorpej 1153 1.1 thorpej return (error); 1154 1.1 thorpej } 1155 1.1 thorpej 1156 1.21 thorpej /* 1157 1.21 thorpej * Enable the network interface. 1158 1.21 thorpej */ 1159 1.21 thorpej int 1160 1.75 dsl se_enable(struct se_softc *sc) 1161 1.21 thorpej { 1162 1.34 bouyer struct scsipi_periph *periph = sc->sc_periph; 1163 1.34 bouyer struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; 1164 1.21 thorpej int error = 0; 1165 1.21 thorpej 1166 1.105 jdc if (sc->sc_enabled == 0) { 1167 1.105 jdc if ((error = scsipi_adapter_addref(adapt)) == 0) 1168 1.105 jdc sc->sc_enabled = 1; 1169 1.105 jdc else 1170 1.105 jdc aprint_error_dev(sc->sc_dev, "device enable failed\n"); 1171 1.105 jdc } 1172 1.21 thorpej return (error); 1173 1.21 thorpej } 1174 1.21 thorpej 1175 1.21 thorpej /* 1176 1.21 thorpej * Disable the network interface. 1177 1.21 thorpej */ 1178 1.21 thorpej void 1179 1.75 dsl se_disable(struct se_softc *sc) 1180 1.21 thorpej { 1181 1.34 bouyer struct scsipi_periph *periph = sc->sc_periph; 1182 1.34 bouyer struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; 1183 1.21 thorpej 1184 1.21 thorpej if (sc->sc_enabled != 0) { 1185 1.34 bouyer scsipi_adapter_delref(adapt); 1186 1.21 thorpej sc->sc_enabled = 0; 1187 1.21 thorpej } 1188 1.21 thorpej } 1189 1.21 thorpej 1190 1.1 thorpej #define SEUNIT(z) (minor(z)) 1191 1.1 thorpej /* 1192 1.1 thorpej * open the device. 1193 1.1 thorpej */ 1194 1.1 thorpej int 1195 1.76 dsl seopen(dev_t dev, int flag, int fmt, struct lwp *l) 1196 1.1 thorpej { 1197 1.21 thorpej int unit, error; 1198 1.1 thorpej struct se_softc *sc; 1199 1.34 bouyer struct scsipi_periph *periph; 1200 1.34 bouyer struct scsipi_adapter *adapt; 1201 1.1 thorpej 1202 1.1 thorpej unit = SEUNIT(dev); 1203 1.72 tsutsui sc = device_lookup_private(&se_cd, unit); 1204 1.10 enami if (sc == NULL) 1205 1.10 enami return (ENXIO); 1206 1.5 matthias 1207 1.34 bouyer periph = sc->sc_periph; 1208 1.34 bouyer adapt = periph->periph_channel->chan_adapter; 1209 1.1 thorpej 1210 1.34 bouyer if ((error = scsipi_adapter_addref(adapt)) != 0) 1211 1.21 thorpej return (error); 1212 1.21 thorpej 1213 1.34 bouyer SC_DEBUG(periph, SCSIPI_DB1, 1214 1.74 cegger ("scopen: dev=0x%"PRIx64" (unit %d (of %d))\n", dev, unit, 1215 1.10 enami se_cd.cd_ndevs)); 1216 1.1 thorpej 1217 1.34 bouyer periph->periph_flags |= PERIPH_OPEN; 1218 1.1 thorpej 1219 1.34 bouyer SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n")); 1220 1.10 enami return (0); 1221 1.1 thorpej } 1222 1.1 thorpej 1223 1.1 thorpej /* 1224 1.1 thorpej * close the device.. only called if we are the LAST 1225 1.112 msaitoh * occurrence of an open device 1226 1.1 thorpej */ 1227 1.1 thorpej int 1228 1.76 dsl seclose(dev_t dev, int flag, int fmt, struct lwp *l) 1229 1.1 thorpej { 1230 1.72 tsutsui struct se_softc *sc = device_lookup_private(&se_cd, SEUNIT(dev)); 1231 1.34 bouyer struct scsipi_periph *periph = sc->sc_periph; 1232 1.34 bouyer struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; 1233 1.1 thorpej 1234 1.34 bouyer SC_DEBUG(sc->sc_periph, SCSIPI_DB1, ("closing\n")); 1235 1.22 thorpej 1236 1.34 bouyer scsipi_wait_drain(periph); 1237 1.22 thorpej 1238 1.34 bouyer scsipi_adapter_delref(adapt); 1239 1.34 bouyer periph->periph_flags &= ~PERIPH_OPEN; 1240 1.1 thorpej 1241 1.10 enami return (0); 1242 1.1 thorpej } 1243 1.1 thorpej 1244 1.1 thorpej /* 1245 1.1 thorpej * Perform special action on behalf of the user 1246 1.1 thorpej * Only does generic scsi ioctls. 1247 1.1 thorpej */ 1248 1.1 thorpej int 1249 1.75 dsl seioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1250 1.1 thorpej { 1251 1.72 tsutsui struct se_softc *sc = device_lookup_private(&se_cd, SEUNIT(dev)); 1252 1.1 thorpej 1253 1.59 christos return (scsipi_do_ioctl(sc->sc_periph, dev, cmd, addr, flag, l)); 1254 1.1 thorpej } 1255