xref: /netbsd-src/sys/dev/scsipi/if_dse.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1 /*	$NetBSD: if_dse.c,v 1.3 2022/12/22 23:06:11 nat Exp $ */
2 
3 /*
4  * Driver for DaynaPORT SCSI/Link SCSI-Ethernet
5  *
6  * Written by Hiroshi Noguchi <ngc@ff.iij4u.or.jp>
7  *
8  * Modified by Matt Sandstrom <mattias@beauty.se> for NetBSD 1.5.3
9  *
10  * This driver is written based on "if_se.c".
11  */
12 
13 /*
14  * Copyright (c) 1997 Ian W. Dall <ian.dall@dsto.defence.gov.au>
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. All advertising materials mentioning features or use of this software
26  *    must display the following acknowledgement:
27  *	This product includes software developed by Ian W. Dall.
28  * 4. The name of the author may not be used to endorse or promote products
29  *    derived from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
35  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41  */
42 
43 
44 
45 #include "opt_inet.h"
46 #include "opt_net_mpsafe.h"
47 #include "opt_atalk.h"
48 
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/callout.h>
53 #include <sys/syslog.h>
54 #include <sys/kernel.h>
55 #include <sys/file.h>
56 #include <sys/stat.h>
57 #include <sys/ioctl.h>
58 #include <sys/buf.h>
59 #include <sys/uio.h>
60 #include <sys/malloc.h>
61 #include <sys/errno.h>
62 #include <sys/device.h>
63 #include <sys/disklabel.h>
64 #include <sys/disk.h>
65 #include <sys/proc.h>
66 #include <sys/conf.h>
67 
68 #include <sys/workqueue.h>
69 
70 #include <dev/scsipi/scsipi_all.h>
71 #include <dev/scsipi/scsiconf.h>
72 
73 #include <sys/mbuf.h>
74 
75 #include <sys/socket.h>
76 #include <net/if.h>
77 #include <net/if_dl.h>
78 #include <net/if_ether.h>
79 #include <net/if_media.h>
80 
81 #ifdef INET
82 #include <netinet/in.h>
83 #include <netinet/if_inarp.h>
84 #endif
85 
86 #ifdef NETATALK
87 #include <netatalk/at.h>
88 #endif
89 
90 #include <net/bpf.h>
91 
92 
93 /*
94  * debug flag
95  */
96 #if 0
97 #define	DSE_DEBUG
98 #endif
99 
100 
101 #define DSE_TIMEOUT	100000
102 #define	DSE_OUTSTANDING	4
103 #define	DSE_RETRIES	4
104 #define DSE_MINSIZE	60
105 
106 #define	DSE_HEADER_TX	4
107 #define	DSE_TAIL_TX	4
108 #define DSE_EXTRAS_TX	(DSE_HEADER_TX + DSE_TAIL_TX)
109 
110 #define	DSE_HEADER_RX	6
111 #define	DSE_TAIL_RX	0
112 #define	DSE_EXTRAS_RX	(DSE_HEADER_RX + DSE_TAIL_RX)
113 
114 #define	MAX_BYTES_RX	(ETHERMTU + sizeof(struct ether_header) + ETHER_CRC_LEN)
115 
116 /* 10 full length packets appears to be the max ever returned. 16k is OK */
117 #define RBUF_LEN	(16 * 1024)
118 
119 /*
120  * Tuning parameters:
121  *   We will attempt to adapt to polling fast enough to get RDATA_GOAL packets
122  *   per read
123  */
124 #define RDATA_MAX	10	/* maximum of returned packets (guessed) */
125 #define RDATA_GOAL 	8
126 
127 /*
128  * maximum of available multicast address entries (guessed)
129  */
130 #define	DSE_MCAST_MAX	10
131 
132 
133 /* dse_poll and dse_poll0 are the normal polling rate and the minimum
134  * polling rate respectively. dse_poll0 should be chosen so that at
135  * maximum ethernet speed, we will read nearly RDATA_MAX packets. dse_poll
136  * should be chosen for reasonable maximum latency.
137  * In practice, if we are being saturated with min length packets, we
138  * can't poll fast enough. Polling with zero delay actually
139  * worsens performance. dse_poll0 is enforced to be always at least 1
140  */
141 #if MAC68K_DEBUG
142 #define DSE_POLL		50	/* default in milliseconds */
143 #define DSE_POLL0 		30	/* default in milliseconds */
144 #else
145 #define DSE_POLL		80	/* default in milliseconds */
146 #define DSE_POLL0 		40	/* default in milliseconds */
147 #endif
148 int dse_poll = 0;		/* Delay in ticks set at attach time */
149 int dse_poll0 = 0;
150 int dse_max_received = 0;	/* Instrumentation */
151 
152 
153 
154 
155 /*==========================================
156   data type defs
157 ==========================================*/
158 typedef struct scsipi_inquiry_data dayna_ether_inquiry_data;
159 
160 typedef struct {
161 	uint8_t	opcode[2];
162 	uint8_t	byte3;
163 	uint8_t	length[2];
164 	uint8_t	byte6;
165 } scsi_dayna_ether_generic;
166 
167 #define	DAYNA_CMD_SEND		0x0A		/* same as generic "Write" */
168 #define	DAYNA_CMD_RECV		0x08		/* same as generic "Read" */
169 
170 #define	DAYNA_CMD_GET_ADDR	0x09		/* ???: read MAC address ? */
171 #define	REQ_LEN_GET_ADDR	0x12
172 
173 #define	DAYNA_CMD_SET_MULTI	0x0D		/* set multicast address */
174 
175 #define	DAYNA_CMD_VENDOR1	0x0E		/* ???: initialize signal ? */
176 
177 #define IS_SEND(generic)	((generic)->opcode == DAYNA_CMD_SEND)
178 #define IS_RECV(generic)	((generic)->opcode == DAYNA_CMD_RECV)
179 
180 struct dse_softc {
181 	device_t sc_dev;
182 	struct	ethercom sc_ethercom;	/* Ethernet common part */
183 	struct scsipi_periph *sc_periph;/* contains our targ, lun, etc. */
184 
185 	struct callout sc_recv_ch;
186 	struct kmutex sc_iflock;
187 	struct if_percpuq *sc_ipq;
188 	struct workqueue *sc_recv_wq, *sc_send_wq;
189 	struct work sc_recv_work, sc_send_work;
190 	int sc_recv_work_pending, sc_send_work_pending;
191 
192 	char *sc_tbuf;
193 	char *sc_rbuf;
194 	int sc_debug;
195 	int sc_flags;
196 	int sc_last_timeout;
197 	int sc_enabled;
198 	int sc_attach_state;
199 };
200 
201 /* bit defs of "sc_flags" */
202 #define DSE_NEED_RECV	0x1
203 
204 static int	dsematch(device_t, cfdata_t, void *);
205 static void	dseattach(device_t, device_t, void *);
206 static int	dsedetach(device_t, int);
207 
208 static void	dse_ifstart(struct ifnet *);
209 static void	dse_send_worker(struct work *wk, void *cookie);
210 
211 static void	dsedone(struct scsipi_xfer *, int);
212 static int	dse_ioctl(struct ifnet *, u_long, void *);
213 static void	dsewatchdog(struct ifnet *);
214 
215 static void	dse_recv_callout(void *);
216 static void	dse_recv_worker(struct work *wk, void *cookie);
217 static void	dse_recv(struct dse_softc *);
218 static struct mbuf*	dse_get(struct dse_softc *, uint8_t *, int);
219 static int	dse_read(struct dse_softc *, uint8_t *, int);
220 
221 static int	dse_init_adaptor(struct dse_softc *);
222 static int	dse_get_addr(struct dse_softc *, uint8_t *);
223 static int	dse_set_multi(struct dse_softc *);
224 
225 static int	dse_reset(struct dse_softc *);
226 
227 #if 0	/* 07/16/2000 comment-out */
228 static int	dse_set_mode(struct dse_softc *, int, int);
229 #endif
230 static int	dse_init(struct dse_softc *);
231 static void	dse_stop(struct dse_softc *);
232 
233 #if 0
234 static __inline uint16_t	ether_cmp(void *, void *);
235 #endif
236 
237 static inline int dse_scsipi_cmd(struct scsipi_periph *periph,
238 			struct scsipi_generic *scsipi_cmd,
239 			int cmdlen, u_char *data_addr, int datalen,
240 			int retries, int timeout, struct buf *bp,
241 			int flags);
242 
243 int	dse_enable(struct dse_softc *);
244 void	dse_disable(struct dse_softc *);
245 
246 
247 CFATTACH_DECL_NEW(dse, sizeof(struct dse_softc),
248     dsematch, dseattach, dsedetach, NULL);
249 
250 extern struct cfdriver dse_cd;
251 
252 dev_type_open(dseopen);
253 dev_type_close(dseclose);
254 dev_type_ioctl(dseioctl);
255 
256 const struct cdevsw dse_cdevsw = {
257 	.d_open = dseopen,
258 	.d_close = dseclose,
259 	.d_read = noread,
260 	.d_write = nowrite,
261 	.d_ioctl = dseioctl,
262 	.d_stop = nostop,
263 	.d_tty = notty,
264 	.d_poll = nopoll,
265 	.d_mmap = nommap,
266 	.d_kqfilter = nokqfilter,
267 	.d_discard = nodiscard,
268 	.d_flag = D_OTHER | D_MPSAFE
269 };
270 
271 const struct scsipi_periphsw dse_switch = {
272 
273 	NULL,			/* Use default error handler */
274 	NULL,		/* have no queue */
275 	NULL,			/* have no async handler */
276 	dsedone,		/* deal with stats at interrupt time */
277 };
278 
279 struct scsipi_inquiry_pattern dse_patterns[] = {
280 	{	T_PROCESSOR,	T_FIXED,
281 		"Dayna",		"SCSI/Link",		"" },
282 };
283 
284 
285 
286 /*====================================================
287   definitions for SCSI commands
288 ====================================================*/
289 
290 /*
291  * command templates
292  */
293 /* unknown commands */
294 /* Vendor #1 */
295 static const scsi_dayna_ether_generic	sonic_ether_vendor1 = {
296 	{ DAYNA_CMD_VENDOR1, 0x00 },
297 	0x00,
298 	{ 0x00, 0x00 },
299 	0x80
300 };
301 
302 
303 
304 #if 0
305 /*
306  * Compare two Ether/802 addredses for equality, inlined and
307  * unrolled for speed.
308  * Note: use this like memcmp()
309  */
310 static __inline uint16_t
311 ether_cmp(void *one, void *two)
312 {
313 	uint16_t*	a;
314 	uint16_t*	b;
315 	uint16_t diff;
316 
317 	a = (uint16_t *) one;
318 	b = (uint16_t *) two;
319 
320 	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
321 
322 	return (diff);
323 }
324 
325 #define ETHER_CMP	ether_cmp
326 #endif
327 
328 /*
329  * check to match with SCSI inquiry information
330  */
331 static int
332 dsematch(device_t parent, cfdata_t match, void *aux)
333 {
334 	struct scsipibus_attach_args *sa = aux;
335 	int priority;
336 
337 	(void)scsipi_inqmatch(&sa->sa_inqbuf,
338 	    dse_patterns, sizeof(dse_patterns) / sizeof(dse_patterns[0]),
339 	    sizeof(dse_patterns[0]), &priority);
340 	return priority;
341 }
342 
343 
344 /*
345  * The routine called by the low level scsi routine when it discovers
346  * a device suitable for this driver.
347  */
348 static void
349 dseattach(device_t parent, device_t self, void *aux)
350 {
351 	struct dse_softc *sc = device_private(self);
352 	struct scsipibus_attach_args *sa = aux;
353 	struct scsipi_periph *periph = sa->sa_periph;
354 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
355 	uint8_t myaddr[ETHER_ADDR_LEN];
356 	char wqname[MAXCOMLEN];
357 	int rv;
358 
359 	sc->sc_dev = self;
360 
361 	aprint_normal("\n");
362 	SC_DEBUG(periph, SCSIPI_DB2, ("dseattach: "));
363 
364 	sc->sc_attach_state = 0;
365 	callout_init(&sc->sc_recv_ch, CALLOUT_MPSAFE);
366 	callout_setfunc(&sc->sc_recv_ch, dse_recv_callout, (void *)sc);
367 	mutex_init(&sc->sc_iflock, MUTEX_DEFAULT, IPL_SOFTNET);
368 
369 	/*
370 	 * Store information needed to contact our base driver
371 	 */
372 	sc->sc_periph = periph;
373 	periph->periph_dev = sc->sc_dev;
374 	periph->periph_switch = &dse_switch;
375 #if 0
376 	sc_periph->sc_link_dbflags = SCSIPI_DB1;
377 #endif
378 
379 	dse_poll = mstohz(DSE_POLL);
380 	dse_poll = dse_poll? dse_poll: 1;
381 	dse_poll0 = mstohz(DSE_POLL0);
382 	dse_poll0 = dse_poll0? dse_poll0: 1;
383 
384 	/*
385 	 * Initialize and attach send and receive buffers
386 	 */
387 	sc->sc_tbuf = malloc(ETHERMTU + sizeof(struct ether_header) +
388 	    DSE_EXTRAS_TX + 16, M_DEVBUF, M_WAITOK);
389 
390 	sc->sc_rbuf = malloc(RBUF_LEN + 16, M_DEVBUF, M_WAITOK);
391 
392 	/* initialize adaptor and obtain MAC address */
393 	dse_init_adaptor(sc);
394 	sc->sc_attach_state = 1;
395 
396 	/* Initialize ifnet structure. */
397 	strcpy(ifp->if_xname, device_xname(sc->sc_dev));
398 	ifp->if_softc = sc;
399 	ifp->if_start = dse_ifstart;
400 	ifp->if_ioctl = dse_ioctl;
401 	ifp->if_watchdog = dsewatchdog;
402 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
403 	ifp->if_extflags = IFEF_MPSAFE;
404 
405 	dse_get_addr(sc, myaddr);
406 
407 	/* Attach the interface. */
408 	if_initialize(ifp);
409 
410 	snprintf(wqname, sizeof(wqname), "%sRx", device_xname(sc->sc_dev));
411 	rv = workqueue_create(&sc->sc_recv_wq, wqname, dse_recv_worker, sc,
412 	    PRI_SOFTNET, IPL_NET, WQ_MPSAFE);
413 	if (rv != 0) {
414 		aprint_error_dev(sc->sc_dev,
415 		    "unable to create recv Rx workqueue\n");
416 		dsedetach(sc->sc_dev, 0);
417 		return; /* Error */
418 	}
419 	sc->sc_recv_work_pending = false;
420 	sc->sc_attach_state = 2;
421 
422 	snprintf(wqname, sizeof(wqname), "%sTx", device_xname(sc->sc_dev));
423 	rv = workqueue_create(&sc->sc_send_wq, wqname, dse_send_worker, ifp,
424 	    PRI_SOFTNET, IPL_NET, WQ_MPSAFE);
425 	if (rv != 0) {
426 		aprint_error_dev(sc->sc_dev,
427 		    "unable to create send Tx workqueue\n");
428 		dsedetach(sc->sc_dev, 0);
429 		return; /* Error */
430 	}
431 	sc->sc_send_work_pending = false;
432 	sc->sc_ipq = if_percpuq_create(&sc->sc_ethercom.ec_if);
433 	ether_ifattach(ifp, myaddr);
434 	if_register(ifp);
435 	sc->sc_attach_state = 4;
436 
437 	bpf_attach(ifp, DLT_EN10MB, sizeof(struct ether_header));
438 }
439 
440 static int
441 dsedetach(device_t self, int flags)
442 {
443 	struct dse_softc *sc = device_private(self);
444 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
445 
446 	switch(sc->sc_attach_state) {
447 	case 4:
448 		dse_stop(sc);
449 		mutex_enter(&sc->sc_iflock);
450 		ifp->if_flags &= ~IFF_RUNNING;
451 		dse_disable(sc);
452 		ether_ifdetach(ifp);
453 		if_detach(ifp);
454 		mutex_exit(&sc->sc_iflock);
455 		if_percpuq_destroy(sc->sc_ipq);
456 		/*FALLTHROUGH*/
457 	case 3:
458 		workqueue_destroy(sc->sc_send_wq);
459 		/*FALLTHROUGH*/
460 	case 2:
461 		workqueue_destroy(sc->sc_recv_wq);
462 		/*FALLTHROUGH*/
463 	case 1:
464 		free(sc->sc_rbuf, M_DEVBUF);
465 		free(sc->sc_tbuf, M_DEVBUF);
466 		callout_destroy(&sc->sc_recv_ch);
467 		mutex_destroy(&sc->sc_iflock);
468 		break;
469 	default:
470 		aprint_error_dev(sc->sc_dev, "detach failed (state %d)\n",
471 		    sc->sc_attach_state);
472 		return 1;
473 		break;
474 	}
475 
476 	return 0;
477 }
478 
479 
480 /*
481  * submit SCSI command
482  */
483 static __inline int
484 dse_scsipi_cmd(struct scsipi_periph *periph, struct scsipi_generic *cmd,
485     int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
486     struct buf *bp, int flags)
487 {
488 	int error = 0;
489 
490 	error = scsipi_command(periph, cmd, cmdlen, data_addr,
491    		 datalen, retries, timeout, bp, flags);
492 
493 	return error;
494 }
495 
496 
497 /*
498  * Start routine for calling from network sub system
499  */
500 static void
501 dse_ifstart(struct ifnet *ifp)
502 {
503 	struct dse_softc *sc = ifp->if_softc;
504 
505 	mutex_enter(&sc->sc_iflock);
506 	if (!sc->sc_send_work_pending)  {
507 		sc->sc_send_work_pending = true;
508 		workqueue_enqueue(sc->sc_send_wq, &sc->sc_send_work, NULL);
509 	}
510 	mutex_exit(&sc->sc_iflock);
511 	if (sc->sc_flags & DSE_NEED_RECV) {
512 		sc->sc_flags &= ~DSE_NEED_RECV;
513 	}
514 }
515 
516 /*
517  * Invoke the transmit workqueue and transmission on the interface.
518  */
519 static void
520 dse_send_worker(struct work *wk, void *cookie)
521 {
522 	struct ifnet *ifp = cookie;
523 	struct dse_softc *sc = ifp->if_softc;
524 	scsi_dayna_ether_generic cmd_send;
525 	struct mbuf *m, *m0;
526 	int len, error;
527 	u_char *cp;
528 
529 	mutex_enter(&sc->sc_iflock);
530 	sc->sc_send_work_pending = false;
531 	mutex_exit(&sc->sc_iflock);
532 
533 	KASSERT(if_is_mpsafe(ifp));
534 
535 	/* Don't transmit if interface is busy or not running */
536 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
537 		return;
538 
539 	while (1) {
540 		IFQ_DEQUEUE(&ifp->if_snd, m0);
541 		if (m0 == NULL)
542 			break;
543 		/* If BPF is listening on this interface, let it see the
544 		 * packet before we commit it to the wire.
545 		 */
546 		bpf_mtap(ifp, m0, BPF_D_OUT);
547 
548 		/* We need to use m->m_pkthdr.len, so require the header */
549 		if ((m0->m_flags & M_PKTHDR) == 0)
550 			panic("ctscstart: no header mbuf");
551 		len = m0->m_pkthdr.len;
552 
553 		/* Mark the interface busy. */
554 		ifp->if_flags |= IFF_OACTIVE;
555 
556 		/* Chain; copy into linear buffer allocated at attach time. */
557 		cp = sc->sc_tbuf;
558 		for (m = m0; m != NULL; ) {
559 			memcpy(cp, mtod(m, u_char *), m->m_len);
560 			cp += m->m_len;
561 			m = m0 = m_free(m);
562 		}
563 		if (len < DSE_MINSIZE) {
564 #ifdef DSE_DEBUG
565 			if (sc->sc_debug)
566 				aprint_error_dev(sc->sc_dev,
567 				    "packet size %d (%zu) < %d\n", len,
568 				    cp - (u_char *)sc->sc_tbuf, DSE_MINSIZE);
569 #endif
570 			memset(cp, 0, DSE_MINSIZE - len);
571 			len = DSE_MINSIZE;
572 		}
573 
574 		/* Fill out SCSI command. */
575 		memset(&cmd_send, 0, sizeof(cmd_send));
576 		cmd_send.opcode[0] = DAYNA_CMD_SEND;
577 		_lto2b(len, &(cmd_send.length[0]));
578 		cmd_send.byte6 = 0x00;
579 
580 		/* Send command to device. */
581 		error = dse_scsipi_cmd(sc->sc_periph,
582 		    (void *)&cmd_send, sizeof(cmd_send),
583 		    sc->sc_tbuf, len, DSE_RETRIES,
584 		    DSE_TIMEOUT, NULL, XS_CTL_NOSLEEP | XS_CTL_POLL |
585 		    XS_CTL_DATA_OUT);
586 		if (error) {
587 			aprint_error_dev(sc->sc_dev,
588 			    "not queued, error %d\n", error);
589 			if_statinc(ifp, if_oerrors);
590 			ifp->if_flags &= ~IFF_OACTIVE;
591 		} else
592 			if_statinc(ifp, if_opackets);
593 	}
594 }
595 
596 
597 /*
598  * Called from the scsibus layer via our scsi device switch.
599  */
600 static void
601 dsedone(struct scsipi_xfer *xs, int error)
602 {
603 	struct dse_softc *sc = device_private(xs->xs_periph->periph_dev);
604 	struct scsipi_generic *cmd = xs->cmd;
605 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
606 
607 	if (IS_SEND(cmd)) {
608 		ifp->if_flags &= ~IFF_OACTIVE;
609 	} else if (IS_RECV(cmd)) {
610 		/* RECV complete */
611 		/* pass data up. reschedule a recv */
612 		/* scsipi_free_xs will call start. Harmless. */
613 
614 		if (error) {
615 			/* Reschedule after a delay */
616 			callout_schedule(&sc->sc_recv_ch, dse_poll);
617 		} else {
618 			int n, ntimeo;
619 			n = dse_read(sc, xs->data, xs->datalen - xs->resid);
620 			if (n > dse_max_received)
621 				dse_max_received = n;
622 			if (n == 0)
623 				ntimeo = dse_poll;
624 			else if (n >= RDATA_MAX)
625 				ntimeo = dse_poll0;
626 			else {
627 				ntimeo = sc->sc_last_timeout;
628 				ntimeo = (ntimeo * RDATA_GOAL)/n;
629 				ntimeo = (ntimeo < dse_poll0?
630 					  dse_poll0: ntimeo);
631 				ntimeo = (ntimeo > dse_poll?
632 					  dse_poll: ntimeo);
633 			}
634 			sc->sc_last_timeout = ntimeo;
635 			callout_schedule(&sc->sc_recv_ch, ntimeo);
636 		}
637 	}
638 }
639 
640 
641 /*
642  * Setup a receive command by queuing the work.
643  * Usually called from a callout, but also from se_init().
644  */
645 static void
646 dse_recv_callout(void *v)
647 {
648 	/* do a recv command */
649 	struct dse_softc *sc = (struct dse_softc *) v;
650 
651 	if (sc->sc_enabled == 0)
652 		return;
653 
654 	mutex_enter(&sc->sc_iflock);
655 	if (sc->sc_recv_work_pending == true) {
656 		callout_schedule(&sc->sc_recv_ch, dse_poll);
657 		mutex_exit(&sc->sc_iflock);
658 		return;
659 	}
660 
661 	sc->sc_recv_work_pending = true;
662 	workqueue_enqueue(sc->sc_recv_wq, &sc->sc_recv_work, NULL);
663 	mutex_exit(&sc->sc_iflock);
664 }
665 
666 /*
667  * Invoke the receive workqueue
668  */
669 static void
670 dse_recv_worker(struct work *wk, void *cookie)
671 {
672 	struct dse_softc *sc = (struct dse_softc *) cookie;
673 
674 	dse_recv(sc);
675 	mutex_enter(&sc->sc_iflock);
676 	sc->sc_recv_work_pending = false;
677 	mutex_exit(&sc->sc_iflock);
678 
679 }
680 
681 /*
682  * Do the actual work of receiving data.
683  */
684 static void
685 dse_recv(struct dse_softc *sc)
686 {
687 	scsi_dayna_ether_generic cmd_recv;
688 	int error, len;
689 
690 	/* do a recv command */
691 	/* fill out command buffer */
692 	memset(&cmd_recv, 0, sizeof(cmd_recv));
693 	cmd_recv.opcode[0] = DAYNA_CMD_RECV;
694 	len = MAX_BYTES_RX + DSE_EXTRAS_RX;
695 	_lto2b(len, &(cmd_recv.length[0]));
696 	cmd_recv.byte6 = 0xC0;
697 
698 	error = dse_scsipi_cmd(sc->sc_periph,
699 	    (void *)&cmd_recv, sizeof(cmd_recv),
700 	    sc->sc_rbuf, RBUF_LEN, DSE_RETRIES, DSE_TIMEOUT, NULL,
701 	    XS_CTL_NOSLEEP | XS_CTL_POLL | XS_CTL_DATA_IN);
702 	if (error)
703 		callout_schedule(&sc->sc_recv_ch, dse_poll);
704 }
705 
706 
707 /*
708  * We copy the data into mbufs.  When full cluster sized units are present
709  * we copy into clusters.
710  */
711 static struct mbuf *
712 dse_get(struct dse_softc *sc, uint8_t *data, int totlen)
713 {
714 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
715 	struct mbuf *m, *m0, *newm;
716 	int len;
717 
718 	MGETHDR(m0, M_DONTWAIT, MT_DATA);
719 	if (m0 == NULL)
720 		return NULL;
721 
722 	m_set_rcvif(m0, ifp);
723 	m0->m_pkthdr.len = totlen;
724 	len	= MHLEN;
725 	m = m0;
726 
727 	while (totlen > 0) {
728 		if (totlen >= MINCLSIZE) {
729 			MCLGET(m, M_DONTWAIT);
730 			if((m->m_flags & M_EXT) == 0)
731 				goto bad;
732 
733 			len = MCLBYTES;
734 		}
735 
736 		if (m == m0) {
737 			char *newdata = (char *)
738 			    ALIGN(m->m_data + sizeof(struct ether_header)) -
739 			    sizeof(struct ether_header);
740 			len -= newdata - m->m_data;
741 			m->m_data = newdata;
742 		}
743 
744 		m->m_len = len = uimin(totlen, len);
745 		memcpy(mtod(m, void *), data, len);
746 		data += len;
747 
748 		totlen -= len;
749 		if (totlen > 0) {
750 			MGET(newm, M_DONTWAIT, MT_DATA);
751 			if (newm == NULL)
752 				goto bad;
753 
754 			len = MLEN;
755 			m = m->m_next = newm;
756 		}
757 	}
758 
759 	return m0;
760 
761 bad:
762 	m_freem(m0);
763 	return NULL ;
764 }
765 
766 
767 #ifdef MAC68K_DEBUG
768 static int
769 peek_packet(uint8_t*  buf)
770 {
771 	struct ether_header *eh;
772 	uint16_t type;
773 	int len;
774 
775 	eh = (struct ether_header*)buf;
776 	type = _2btol((uint8_t*)&(eh->ether_type));
777 
778 	len = sizeof(struct ether_header);
779 
780 	if (type <= ETHERMTU) {
781 		/* for 802.3 */
782 		len += type;
783 	} else{
784 		/* for Ethernet II (DIX) */
785 		switch (type) {
786 		  case ETHERTYPE_ARP:
787 			len += 28;
788 			break;
789 		  case ETHERTYPE_IP:
790 			len += _2btol(buf + sizeof(struct ether_header) + 2);
791 			break;
792 		  default:
793 			len = 0;
794 			goto l_end;
795 			break;
796 		}
797 	}
798 	if (len < DSE_MINSIZE) {
799 		len = DSE_MINSIZE;
800 	}
801 	len += ETHER_CRC_LEN;
802 
803   l_end:;
804 	return len;
805 }
806 #endif
807 
808 
809 /*
810  * Pass packets to higher levels.
811  */
812 static int
813 dse_read(struct dse_softc *sc, uint8_t *data, int datalen)
814 {
815 	struct mbuf *m;
816 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
817 	int	len;
818 	int	n;
819 #ifdef MAC68K_DEBUG
820 	int	peek_flag = 1;
821 #endif
822 
823 	mutex_enter(&sc->sc_iflock);
824 	n = 0;
825 	while (datalen >= DSE_HEADER_RX) {
826 		/*
827 		 * fetch bytes of stream.
828 		 * here length = (ether frame length) + (FCS's 4 bytes)
829 		 */
830 		/* fetch frame length */
831 		len = _2btol(data);
832 
833 		/* skip header part */
834 		data	+= DSE_HEADER_RX;
835 		datalen -= DSE_HEADER_RX;
836 
837 #if 0	/* 03/10/2001  only for debug */
838 		{
839 			printf("DATALEN %d len %d\n", datalen, len);
840 			int	j;
841 			printf("\ndump[%d]: ",n);
842 			for ( j = 0 ; j < datalen ; j++ ) {
843 				printf("%02X ",data[j-DSE_HEADER_RX]);
844 			}
845 		}
846 #endif
847 #ifdef MAC68K_DEBUG
848 		if (peek_flag) {
849 			peek_flag = 0;
850 			len = peek_packet(data);
851 		}
852 #endif
853 		if (len == 0)
854 			break;
855 
856 #ifdef DSE_DEBUG
857 		aprint_error_dev(sc->sc_dev, "dse_read: datalen = %d, packetlen"
858 		    " = %d, proto = 0x%04x\n", datalen, len,
859 		    ntohs(((struct ether_header *)data)->ether_type));
860 #endif
861 		if ((len < (DSE_MINSIZE + ETHER_CRC_LEN)) ||
862 		     (MAX_BYTES_RX < len)) {
863 #ifdef DSE_DEBUG
864 			aprint_error_dev(sc->sc_dev, "invalid packet size "
865 			    "%d; dropping\n", len);
866 #endif
867 			if_statinc(ifp, if_ierrors);
868 			break;
869 		}
870 
871 		/* Don't need crc. Must keep ether header for BPF */
872 		m = dse_get(sc, data, len - ETHER_CRC_LEN);
873 		if (m == NULL) {
874 #ifdef DSE_DEBUG
875 			if (sc->sc_debug)
876 				aprint_error_dev(sc->sc_dev, "dse_read: "
877 				    "dse_get returned null\n");
878 #endif
879 			if_statinc(ifp, if_ierrors);
880 			goto next_packet;
881 		}
882 		if_statinc(ifp, if_ipackets);
883 
884 		/*
885 		 * Check if there's a BPF listener on this interface.
886 		 * If so, hand off the raw packet to BPF.
887 		 */
888 		if (ifp->if_bpf)
889 			bpf_mtap(ifp, m, BPF_D_OUT);
890 
891 		/* Pass the packet up. */
892 		if_percpuq_enqueue(sc->sc_ipq, m);
893 
894   next_packet:
895 		data	+= len;
896 		datalen	-= len;
897 		n++;
898 	}
899 	mutex_exit(&sc->sc_iflock);
900 
901 	return n;
902 }
903 
904 
905 static void
906 dsewatchdog(struct ifnet *ifp)
907 {
908 	struct dse_softc *sc = ifp->if_softc;
909 
910 	log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
911 	if_statinc(ifp, if_oerrors);
912 
913 	dse_reset(sc);
914 }
915 
916 
917 static int
918 dse_reset(struct dse_softc *sc)
919 {
920 	int error;
921 #if 0
922 	/* Maybe we don't *really* want to reset the entire bus
923 	 * because the ctron isn't working. We would like to send a
924 	 * "BUS DEVICE RESET" message, but don't think the ctron
925 	 * understands it.
926 	 */
927 	error = dse_scsipi_cmd(sc->sc_periph, 0, 0, 0, 0, DSE_RETRIES, 2000,
928 	    NULL, XS_CTL_RESET);
929 #endif
930 	error = dse_init(sc);
931 	return error;
932 }
933 
934 
935 static int
936 dse_init_adaptor(struct dse_softc *sc)
937 {
938 	scsi_dayna_ether_generic cmd_vend1;
939 	u_char tmpbuf[sizeof(cmd_vend1)];
940 	int error;
941 
942 #if 0	/* 07/21/2001 for test */
943 	/* Maybe we don't *really* want to reset the entire bus
944 	 * because the ctron isn't working. We would like to send a
945 	 * "BUS DEVICE RESET" message, but don't think the ctron
946 	 * understands it.
947 	 */
948 	error = dse_scsipi_cmd(sc->sc_periph, 0, 0, 0, 0, DSE_RETRIES,
949 	    2000, NULL, XS_CTL_RESET);
950 #endif
951 
952 	cmd_vend1 = sonic_ether_vendor1;
953 
954 	error = dse_scsipi_cmd(sc->sc_periph,
955 	    (struct scsipi_generic *)&cmd_vend1, sizeof(cmd_vend1),
956 		&(tmpbuf[0]), sizeof(tmpbuf),
957 	    DSE_RETRIES, DSE_TIMEOUT, NULL, XS_CTL_POLL | XS_CTL_DATA_IN);
958 
959 	if (error)
960 		goto l_end;
961 
962 	/* wait 500 msec */
963 	kpause("dsesleep", false, hz / 2, NULL);
964 
965 l_end:
966 	return error;
967 }
968 
969 
970 static int
971 dse_get_addr(struct dse_softc *sc, uint8_t *myaddr)
972 {
973 	scsi_dayna_ether_generic cmd_get_addr;
974 	u_char tmpbuf[REQ_LEN_GET_ADDR];
975 	int error;
976 
977 	memset(&cmd_get_addr, 0, sizeof(cmd_get_addr));
978 	cmd_get_addr.opcode[0] = DAYNA_CMD_GET_ADDR;
979 	_lto2b(REQ_LEN_GET_ADDR, cmd_get_addr.length);
980 
981 	error = dse_scsipi_cmd(sc->sc_periph,
982 	    (struct scsipi_generic *)&cmd_get_addr, sizeof(cmd_get_addr),
983 	    tmpbuf, sizeof(tmpbuf),
984 	    DSE_RETRIES, DSE_TIMEOUT, NULL, XS_CTL_POLL | XS_CTL_DATA_IN);
985 
986 	if (error == 0) {
987 		memcpy(myaddr, &(tmpbuf[0]), ETHER_ADDR_LEN);
988 
989 		aprint_error_dev(sc->sc_dev, "ethernet address %s\n",
990 			   ether_sprintf(myaddr));
991 	}
992 
993 	return error;
994 }
995 
996 
997 #if 0	/* 07/16/2000 comment-out */
998 static int
999 dse_set_mode(struct dse_softc *sc, int len, int mode)
1000 
1001 	return 0;
1002 }
1003 #endif
1004 
1005 
1006 static int
1007 dse_init(struct dse_softc *sc)
1008 {
1009 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1010 	int error = 0;
1011 
1012 	if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == IFF_UP) {
1013 		ifp->if_flags |= IFF_RUNNING;
1014 		mutex_enter(&sc->sc_iflock);
1015 		if (!sc->sc_recv_work_pending)  {
1016 			sc->sc_recv_work_pending = true;
1017 			workqueue_enqueue(sc->sc_recv_wq, &sc->sc_recv_work,
1018 			    NULL);
1019 		}
1020 		mutex_exit(&sc->sc_iflock);
1021 		ifp->if_flags &= ~IFF_OACTIVE;
1022 		mutex_enter(&sc->sc_iflock);
1023 		if (!sc->sc_send_work_pending)  {
1024 			sc->sc_send_work_pending = true;
1025 			workqueue_enqueue(sc->sc_send_wq, &sc->sc_send_work,
1026 			    NULL);
1027 		}
1028 		mutex_exit(&sc->sc_iflock);
1029 	}
1030 	return error;
1031 }
1032 
1033 
1034 static uint8_t	BROADCAST_ADDR[ETHER_ADDR_LEN] =
1035 			{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
1036 
1037 
1038 static int
1039 dse_set_multi(struct dse_softc *sc)
1040 {
1041 	scsi_dayna_ether_generic cmd_set_multi;
1042 	struct ether_multistep step;
1043 	struct ether_multi *enm;
1044 	u_char *cp, *mybuf;
1045 	int error, len;
1046 
1047 	error = 0;
1048 
1049 #ifdef DSE_DEBUG
1050 	aprint_error_dev(sc->sc_dev, "dse_set_multi\n");
1051 #endif
1052 
1053 	mybuf = malloc(ETHER_ADDR_LEN * DSE_MCAST_MAX, M_DEVBUF, M_NOWAIT);
1054 	if (mybuf == NULL) {
1055 		error = EIO;
1056 		goto l_end;
1057 	}
1058 
1059 	/*
1060 	 * copy all entries to transfer buffer
1061 	 */
1062 	cp = mybuf;
1063 	len = 0;
1064 	ETHER_FIRST_MULTI(step, &(sc->sc_ethercom), enm);
1065 	while ((len < (DSE_MCAST_MAX - 1)) && (enm != NULL)) {
1066 		/* ### refer low side entry */
1067 		memcpy(cp, enm->enm_addrlo, ETHER_ADDR_LEN);
1068 
1069 		cp += ETHER_ADDR_LEN;
1070 		len++;
1071 		ETHER_NEXT_MULTI(step, enm);
1072 	}
1073 
1074 	/* add broadcast address as default */
1075 	memcpy(cp, BROADCAST_ADDR, ETHER_ADDR_LEN);
1076 	len++;
1077 
1078 	len *= ETHER_ADDR_LEN;
1079 
1080 	memset(&cmd_set_multi, 0, sizeof(cmd_set_multi));
1081 	cmd_set_multi.opcode[0] = DAYNA_CMD_SET_MULTI;
1082 	_lto2b(len, cmd_set_multi.length);
1083 
1084 	error = dse_scsipi_cmd(sc->sc_periph,
1085 	    (struct scsipi_generic*)&cmd_set_multi, sizeof(cmd_set_multi),
1086 	    mybuf, len, DSE_RETRIES, DSE_TIMEOUT, NULL, XS_CTL_POLL | XS_CTL_DATA_OUT);
1087 
1088 	free(mybuf, M_DEVBUF);
1089 
1090 l_end:
1091 	return error;
1092 }
1093 
1094 
1095 static void
1096 dse_stop(struct dse_softc *sc)
1097 {
1098 	/* Don't schedule any reads */
1099 	callout_stop(&sc->sc_recv_ch);
1100 
1101 	/* Wait for the workqueues to finish */
1102 	mutex_enter(&sc->sc_iflock);
1103 	workqueue_wait(sc->sc_recv_wq, &sc->sc_recv_work);
1104 	workqueue_wait(sc->sc_send_wq, &sc->sc_send_work);
1105 	mutex_exit(&sc->sc_iflock);
1106 
1107 	/* Abort any scsi cmds in progress */
1108 	mutex_enter(chan_mtx(sc->sc_periph->periph_channel));
1109 	scsipi_kill_pending(sc->sc_periph);
1110 	mutex_exit(chan_mtx(sc->sc_periph->periph_channel));
1111 }
1112 
1113 
1114 /*
1115  * Process an ioctl request.
1116  */
1117 static int
1118 dse_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1119 {
1120 	struct dse_softc *sc;
1121 	struct ifaddr *ifa;
1122 	struct ifreq *ifr;
1123 	struct sockaddr *sa;
1124 	int error;
1125 
1126 	error = 0;
1127 	sc = ifp->if_softc;
1128 	ifa = (struct ifaddr *)data;
1129 	ifr = (struct ifreq *)data;
1130 
1131 	switch (cmd) {
1132 	case SIOCINITIFADDR:
1133 		mutex_enter(&sc->sc_iflock);
1134 		if ((error = dse_enable(sc)) != 0)
1135 			break;
1136 		ifp->if_flags |= IFF_UP;
1137 		mutex_exit(&sc->sc_iflock);
1138 
1139 #if 0
1140 		if ((error = dse_set_media(sc, CMEDIA_AUTOSENSE)) != 0)
1141 			break;
1142 #endif
1143 
1144 		switch (ifa->ifa_addr->sa_family) {
1145 #ifdef INET
1146 		case AF_INET:
1147 			if ((error = dse_init(sc)) != 0)
1148 				break;
1149 			arp_ifinit(ifp, ifa);
1150 			break;
1151 #endif
1152 #ifdef NETATALK
1153 		case AF_APPLETALK:
1154 			if ((error = dse_init(sc)) != 0)
1155 				break;
1156 			break;
1157 #endif
1158 		default:
1159 			error = dse_init(sc);
1160 			break;
1161 		}
1162 		break;
1163 
1164 
1165 	case SIOCSIFADDR:
1166 		mutex_enter(&sc->sc_iflock);
1167 		error = dse_enable(sc);
1168 		mutex_exit(&sc->sc_iflock);
1169 		if (error != 0)
1170 			break;
1171 		ifp->if_flags |= IFF_UP;
1172 
1173 		switch (ifa->ifa_addr->sa_family) {
1174 #ifdef INET
1175 		case AF_INET:
1176 			if ((error = dse_init(sc)) != 0)
1177 				break;
1178 			arp_ifinit(ifp, ifa);
1179 			break;
1180 #endif
1181 #ifdef NETATALK
1182 		case AF_APPLETALK:
1183 			if ((error = dse_init(sc)) != 0)
1184 				break;
1185 			break;
1186 #endif
1187 		default:
1188 			error = dse_init(sc);
1189 			break;
1190 		}
1191 		break;
1192 
1193 	case SIOCSIFFLAGS:
1194 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1195 			break;
1196 		/* XXX re-use ether_ioctl() */
1197 		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
1198 		case IFF_RUNNING:
1199 			/*
1200 			 * If interface is marked down and it is running, then
1201 			 * stop it.
1202 			 */
1203 			dse_stop(sc);
1204 			mutex_enter(&sc->sc_iflock);
1205 			ifp->if_flags &= ~IFF_RUNNING;
1206 			dse_disable(sc);
1207 			mutex_exit(&sc->sc_iflock);
1208 			break;
1209 		case IFF_UP:
1210 			/*
1211 			 * If interface is marked up and it is stopped, then
1212 			 * start it.
1213 			 */
1214 			mutex_enter(&sc->sc_iflock);
1215 			error = dse_enable(sc);
1216 			mutex_exit(&sc->sc_iflock);
1217 			if (error)
1218 				break;
1219 			error = dse_init(sc);
1220 			break;
1221 		default:
1222 			/*
1223 			 * Reset the interface to pick up changes in any other
1224 			 * flags that affect hardware registers.
1225 			 */
1226 			mutex_enter(&sc->sc_iflock);
1227 			if (sc->sc_enabled)
1228 				error = dse_init(sc);
1229 			mutex_exit(&sc->sc_iflock);
1230 			break;
1231 		}
1232 #ifdef DSE_DEBUG
1233 		if (ifp->if_flags & IFF_DEBUG)
1234 			sc->sc_debug = 1;
1235 		else
1236 			sc->sc_debug = 0;
1237 #endif
1238 		break;
1239 
1240 	case SIOCADDMULTI:
1241 		if (sc->sc_enabled == 0) {
1242 			error = EIO;
1243 			break;
1244 		}
1245 		mutex_enter(&sc->sc_iflock);
1246 		sa = sockaddr_dup(ifreq_getaddr(cmd, ifr), M_WAITOK);
1247 		mutex_exit(&sc->sc_iflock);
1248 		if (ether_addmulti(sa, &sc->sc_ethercom) == ENETRESET) {
1249 			error = dse_set_multi(sc);
1250 #ifdef DSE_DEBUG
1251 			aprint_error_dev(sc->sc_dev, "add multi: %s\n",
1252 				   ether_sprintf(ifr->ifr_addr.sa_data));
1253 #endif
1254 		} else
1255 			error = 0;
1256 
1257 		mutex_enter(&sc->sc_iflock);
1258 		sockaddr_free(sa);
1259 		mutex_exit(&sc->sc_iflock);
1260 
1261 		break;
1262 
1263 	case SIOCDELMULTI:
1264 		if (sc->sc_enabled == 0) {
1265 			error = EIO;
1266 			break;
1267 		}
1268 		mutex_enter(&sc->sc_iflock);
1269 		sa = sockaddr_dup(ifreq_getaddr(cmd, ifr), M_WAITOK);
1270 		mutex_exit(&sc->sc_iflock);
1271 		if (ether_delmulti(sa, &sc->sc_ethercom) == ENETRESET) {
1272 			error = dse_set_multi(sc);
1273 #ifdef DSE_DEBUG
1274 			aprint_error_dev(sc->sc_dev, "delete multi: %s\n",
1275 			    ether_sprintf(ifr->ifr_addr.sa_data));
1276 #endif
1277 		} else
1278 			error = 0;
1279 
1280 		mutex_enter(&sc->sc_iflock);
1281 		sockaddr_free(sa);
1282 		mutex_exit(&sc->sc_iflock);
1283 
1284 		break;
1285 
1286 	default:
1287 		error = ether_ioctl(ifp, cmd, data);
1288 		break;
1289 	}
1290 
1291 
1292 	return error;
1293 }
1294 
1295 
1296 /*
1297  * Enable the network interface.
1298  */
1299 int
1300 dse_enable(struct dse_softc *sc)
1301 {
1302 	struct scsipi_periph *periph = sc->sc_periph;
1303 	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
1304 	int error = 0;
1305 
1306 	if (sc->sc_enabled == 0) {
1307 		if ((error = scsipi_adapter_addref(adapt)) == 0)
1308 			sc->sc_enabled = 1;
1309 		else
1310 			aprint_error_dev(sc->sc_dev, "device enable failed\n");
1311 	}
1312 
1313 	return error;
1314 }
1315 
1316 
1317 /*
1318  * Disable the network interface.
1319  */
1320 void
1321 dse_disable(struct dse_softc *sc)
1322 {
1323 	struct scsipi_periph *periph = sc->sc_periph;
1324 	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
1325 	if (sc->sc_enabled != 0) {
1326 		scsipi_adapter_delref(adapt);
1327 		sc->sc_enabled = 0;
1328 	}
1329 }
1330 
1331 
1332 #define	DSEUNIT(z)	(minor(z))
1333 
1334 /*
1335  * open the device.
1336  */
1337 int
1338 dseopen(dev_t dev, int flag, int fmt, struct lwp *l)
1339 {
1340 	int unit, error;
1341 	struct dse_softc *sc;
1342 	struct scsipi_periph *periph;
1343 	struct scsipi_adapter *adapt;
1344 
1345 	unit = DSEUNIT(dev);
1346 	sc = device_lookup_private(&dse_cd, unit);
1347 	if (sc == NULL)
1348 		return ENXIO;
1349 
1350 	periph = sc->sc_periph;
1351 	adapt = periph->periph_channel->chan_adapter;
1352 
1353 	if ((error = scsipi_adapter_addref(adapt)) != 0)
1354 		return error;
1355 
1356 	SC_DEBUG(periph, SCSIPI_DB1,
1357 	    ("scopen: dev=0x%"PRIx64" (unit %d (of %d))\n", dev, unit,
1358 	    dse_cd.cd_ndevs));
1359 
1360 	periph->periph_flags |= PERIPH_OPEN;
1361 
1362 	SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n"));
1363 
1364 	return 0;
1365 }
1366 
1367 
1368 /*
1369  * close the device.. only called if we are the LAST
1370  * occurence of an open device
1371  */
1372 int
1373 dseclose(dev_t dev, int flag, int fmt, struct lwp *l)
1374 {
1375 	struct dse_softc *sc = device_lookup_private(&dse_cd, DSEUNIT(dev));
1376 	struct scsipi_periph *periph = sc->sc_periph;
1377 	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
1378 
1379 	SC_DEBUG(sc->sc_periph, SCSIPI_DB1, ("closing\n"));
1380 
1381 	scsipi_wait_drain(periph);
1382 
1383 	scsipi_adapter_delref(adapt);
1384 	periph->periph_flags &= ~PERIPH_OPEN;
1385 
1386 	return 0;
1387 }
1388 
1389 
1390 /*
1391  * Perform special action on behalf of the user
1392  * Only does generic scsi ioctls.
1393  */
1394 int
1395 dseioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1396 {
1397 	struct dse_softc *sc = device_lookup_private(&dse_cd, DSEUNIT(dev));
1398 
1399 	return (scsipi_do_ioctl(sc->sc_periph, dev, cmd, addr, flag, l));
1400 }
1401 
1402