xref: /original-bsd/sys/vax/datakit/dk.c (revision 2bd07fe6)
1 /*
2  * Datakit driver
3  *	SCCSID[] = "@(#)dk.c	2.1 DKHOST 84/07/03"
4  */
5 
6 #include "datakit.h"
7 #if NDATAKIT>0
8 
9 #include "param.h"
10 #include "../machine/pte.h"
11 #include "signal.h"
12 #include "errno.h"
13 #include "conf.h"
14 #include "user.h"
15 #include "ioctl.h"
16 #include "tty.h"
17 #include "inode.h"
18 #include "file.h"
19 #include "systm.h"
20 #include "proc.h"
21 #include "mbuf.h"
22 #include "buf.h"
23 #include "uio.h"
24 #include "kernel.h"
25 #include "dkit.h"
26 #include "dkcmc.h"
27 #include "dk.h"
28 #include "dkdev.h"
29 #include "syslog.h"
30 
31 extern int dkdebug ;
32 
33 #define DKBUFUSE	5	/* max buffers /channel */
34 
35 
36 int	dk_nchan	= NDATAKIT;
37 struct	dkdev		dkdev[NDATAKIT];
38 struct	dksetupreq	*dkreq[NDATAKIT];
39 
40 
41 
42 
43 #ifdef	MONITOR
44 int dummy ;
45 int *DKP2 = &dummy ;
46 #define	M_ON(a)		*DKP2 |= (a)
47 #define	M_OFF(a)	*DKP2 &= ~(a)
48 
49 #define	Mread	0400
50 #define Mrslp	01000
51 #define	Mrcpy	02000
52 #define	Mwrite	04000
53 #define	Mwcpy	010000
54 
55 #else
56 #define	M_ON(a)
57 #define	M_OFF(a)
58 #endif
59 
60 
61 
62 /*ARGSUSED*/
63 dkioctl(dev, cmd, data, flag)
64 register caddr_t data;
65 {
66 	register struct	dkdev	*tp;
67 	register chanstat ;
68 	int	chan, sp_chan;
69 	int	s;
70 	register short	*pp ;
71 	struct dkdev *tsp;
72 	extern dkidone() ;
73 	struct diocdial dialreq;
74 	extern int commchan;
75 
76 	chan = dev = minor(dev);
77 	tp = &dkdev[chan];
78 	pp = (short *) data;
79 	switch(cmd) {
80 	case DIOCEXCL:
81 		tp->d_state |= DKXCLUDE ;
82 		break ;
83 	case DIOCNXCL:
84 		tp->d_state &= ~DKXCLUDE ;
85 		break ;
86 	case DIOCSETK:
87 		dkdebug = pp[0] ;
88 		break;
89 	case DIOCQQABO:
90 		pp[0] = tp->d_rresid;
91 		pp[1] = tp->d_rdone;
92 		pp[2] = tp->d_rctl;
93 		break ;
94 	case DIOCRMODE:
95 		if (pp[0] & DKR_TIME)
96 			tp->d_rmode = (DKR_TIME | DKR_BLOCK);
97 		else tp->d_rmode = pp[0] ;
98 		break ;
99 	case DIOCXCTL:
100 		tp->d_xctl = pp[0] ;
101 		break ;
102 	case DIOCFLUSH:
103 		dk_cmd(chan, DKC_XINIT|DKC_FLUSH);
104 		break;
105 	case KIOCINIT:
106 		dk_cmd(chan, DKC_XINIT);
107 		break;
108 	case DIOCXWIN:
109 		return dk_winsize(chan, (struct diocxwin *)data);
110 	case DIOCRESET:
111 		if (chan != 1 && chan != pp[0]) return EACCES;
112 		if (pp[0] > 1 && pp[0] < commchan) return EINVAL;
113 		if (pp[0] < 0 || pp[0] >= dk_nchan) return EINVAL;
114 		if (pp[0] == 0) return -dk_close(0);
115 		else dk_reset(pp[0]);
116 		break;
117 	case DIOCCTYPE:
118 		if (tp->d_ctype == NULL) {
119 			struct mbuf *m;
120 
121 			MGET(m, M_WAIT, DKMT_CTYPE);
122 			if (m == NULL)
123 				return ENOBUFS;
124 			tp->d_ctype = mtod(m, struct diocctype *);
125 		}
126 		return bcopy(data, (caddr_t) tp->d_ctype, sizeof (struct diocctype));
127 	case DIOCINFO:
128 		((struct diocinfo *)data)->dioc_nchan = dk_nchan;
129 		((struct diocinfo *)data)->dioc_channum = chan;
130 		((struct diocinfo *)data)->dioc_commchan = commchan;
131 		break;
132 	case DIOCSTAT:
133 		if (*((int *)data) < 0 || *((int *)data) >= dk_nchan)
134 			return EINVAL;
135 		*((int *)data) = dk_status(*((int *)data));
136 		break;
137 	case FIONBIO:
138 		if (*(int *)data)
139 			tp->dc_state |= DK_NDELAY;
140 		else
141 			tp->dc_state &= ~DK_NDELAY;
142 		break;
143 	case FIOASYNC:
144 		if (*(int *)data)
145 			tp->dc_state |= DK_ASYNC;
146 		else
147 			tp->dc_state &= ~DK_ASYNC;
148 		break;
149 	case TIOCGPGRP:
150 		*(int *)data = tp->d_pgrp;
151 		break;
152 	case TIOCSPGRP:
153 		tp->d_pgrp = *(int *)data;
154 		break;
155 
156 	/* splice chan to file descriptor */
157 	case DKIOCSPL:
158 		u.u_error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param,
159 		    3*sizeof (short));
160 		if (u.u_error) return u.u_error;
161 		if ((sp_chan = dkgetdev(tp->d_param[0])) <= 0)
162 			return u.u_error ;
163 		if (sp_chan == chan)
164 			return EINVAL ;
165 		tsp = &dkdev[sp_chan] ;
166 		tp->dc_state |= DKSETUP ;
167 		tsp->dc_state |= DKSETUP ;
168 		if (dk_splice(chan, sp_chan, dkidone, (caddr_t) tp,
169 			(caddr_t) tsp)) {
170 			tp->dc_state &= ~DKSETUP ;
171 			tsp->dc_state &= ~DKSETUP ;
172 			return EIO ;
173 		}
174 		s = spl5() ;
175 		while (tp->dc_state & DKSETUP)
176 			sleep((caddr_t) tp, TTOPRI);
177 		while (tsp->dc_state & DKSETUP)
178 			sleep((caddr_t) tsp, TTOPRI);
179 		splx(s) ;
180 		if ((dk_status(chan) & DK_RESET) || (dk_status(sp_chan) & DK_RESET))
181 			return EIO ;
182 		if (tp->d_error || tsp->d_error)
183 			return EIO ;
184 		u.u_error = copyout((caddr_t) tp->d_param, *(caddr_t *)data,
185 		    3*sizeof (short));
186 		if (u.u_error) return u.u_error;
187 		break ;
188 
189 	case DIOCSWAIT:
190 		(void) dksplwait(chan) ;
191 		break ;
192 
193 	default:
194 		if ((cmd & DKIOCMASK) != DKIOCVAL) {
195 			return ENOTTY ;
196 		}
197 		if (cmd == DKIODIAL) {
198 			u.u_error = copyin(*(caddr_t *)data, (caddr_t) &dialreq,
199 			    sizeof (struct diocdial));
200 			if (u.u_error) return u.u_error;
201 			if (u.u_error = dkiodial(chan, dialreq.dialstring))
202 				return u.u_error;
203 			tp->dc_state |= DKSETUP ;
204 			chanstat = dk_setup(minor(dev), (int) DKIOCREQ, 0,
205 			0, 0, (int) u.u_uid, dkidone, (caddr_t)tp) ;
206 		}
207 		else {
208 			u.u_error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param,
209 			    3*sizeof (short));
210 			if (u.u_error) return u.u_error;
211 			tp->dc_state |= DKSETUP ;
212 			chanstat = dk_setup(minor(dev), cmd, 0, 0, 0,
213 				(int) u.u_uid, dkidone, (caddr_t)tp) ;
214 		}
215 		if (chanstat) {
216 			tp->dc_state &= ~DKSETUP ;
217 			return (chanstat < 0 ? ECONNREFUSED : chanstat);
218 		}
219 		s = spl5() ;
220 		while (tp->dc_state & DKSETUP)
221 			sleep((caddr_t)(tp), TTOPRI) ;
222 		splx(s) ;
223 		u.u_error = copyout((caddr_t) tp->d_param, *(caddr_t *)data,
224 		    3*sizeof (short));
225 		if (u.u_error) return u.u_error;
226 		if (dk_status(minor(dev)) & DK_RESET)
227 			return ENETRESET ;
228 		if (tp->d_error)
229 			return EIO ;
230 		break ;
231 	}
232 	return 0;
233 }
234 
235 #define DS_SIZE 64
236 static
237 dkiodial(chan, user_ds)
238 register char *user_ds;
239 {
240 	register caddr_t ds;
241 	register n;
242 	register struct mbuf *mb;
243 	int u_count;
244 
245 	mb = m_get(M_WAIT, DKMT_DATA);
246 	if (mb == NULL) return ENOBUFS;
247 	ds = mtod(mb, caddr_t);
248 	for (u_count = 0; u_count < MLEN - 6; u_count++) {
249 		*ds = *user_ds;
250 		if (*ds == '\n' || *ds == '\0') break;
251 		ds++;
252 		user_ds++;
253 	}
254 	*ds = '\n';
255 	u_count++;
256 
257 	/* add uid in char decimal */
258 
259 	ds++;
260 	u_count++;
261 	for (n = u.u_uid; n /= 10; ds++) u_count++;
262 	for (n = u.u_uid;; ds--) {
263 		*ds = n % 10 + '0';
264 		if ((n /= 10) == 0) break;
265 	}
266 
267 	mb->m_len = u_count;
268 	if (dk_xmit(chan, mb, 1, 0, (int (*)()) 0, (caddr_t) 0) == 0) {
269 		return(EIO);
270 	}
271 	else return(0);
272 }
273 /*
274  * End action for ioctl completion
275  */
276 /*ARGSUSED*/
277 dkidone(tp, chan, err, p0, p1, p2)
278 register struct dkdev *tp ;
279 short chan, p0, p1, p2 ;
280 {
281 	tp->d_error = err ;
282 	tp->d_param[0] = p0 ;
283 	tp->d_param[1] = p1 ;
284 	tp->d_param[2] = p2 ;
285 	tp->dc_state &= ~DKSETUP ;
286 	wakeup((caddr_t)tp) ;
287 }
288 
289 
290 
291 
292 /*ARGSUSED*/
293 dkopen(dev, flag)
294 {
295 	register struct	dkdev	*tp;
296 	register chan;
297 	register struct nameidata *ndp = &u.u_nd;
298 	struct	inode *ip;
299 	struct	file *fp;
300 	int	 m;
301 
302 #ifdef lint
303 	(void) dk_xint(0, 0);
304 #endif
305 	dev = minor(dev);
306 	if (dev == 1) {
307 		return 0;	/* Maintenance channel */
308 	}
309 
310 	chan = dev;
311 	if (chan >= dk_nchan) {
312 /* debug */	log(LOG_ERR, "dkopen bad: chan>=NDKCHANS : %d\n",chan);
313 		return ENXIO;
314 	}
315 
316 	tp = &dkdev[chan];
317 	if ((tp->d_state & DKOPEN) == 0)
318 		tp->dc_state = 0 ;
319 	if (tp->d_state&DKXCLUDE && u.u_ruid!=0) {
320 		return EBUSY;
321 	}
322 
323 	if ((m = dk_open(chan, (int (*)()) NULL)) < 0)
324 		return -m;
325 
326 
327 	/*
328 	 * Channel 0 is reserved for maintenance.
329 	 * An open on channel 0 is interpreted as a request
330 	 * for an unused channel.
331 	 */
332 	if (chan==0) {
333 		char dname[30];
334 
335 		chan = m ;
336 		tp = &dkdev[chan] ;
337 		tp->dc_state = 0 ;
338 		/*
339 		 * throw away inode for dk0. (/dev/dk/dial)
340 		 * Build standard name of new one, and ask namei for it.
341 		 */
342 		fp = u.u_ofile[u.u_r.r_val1];
343 
344 		dksnamer(dname, chan);
345 		/* log(LOG_ERR, "dname=%s chan=%d\n", dname, chan); */
346 		u.u_error = 0;
347 		ndp->ni_nameiop = FOLLOW | LOOKUP;
348 		ndp->ni_segflg = UIO_SYSSPACE;
349 		ndp->ni_dirp = dname;
350 		ip = namei(ndp);
351 
352 		if (ip == NULL) {
353 			(void) dk_close(chan) ;
354 			return ENOENT ;
355 		}
356 
357 		/* Give back old one */
358 		ilock((struct inode *) fp->f_data);
359 		iput((struct inode *) fp->f_data);
360 
361 		fp->f_data = (caddr_t) ip;
362 		iunlock(ip);
363 	}
364 	if ((tp->d_state & DKOPEN) == 0) {
365 		tp->d_state |= DKOPEN ;
366 		tp->dc_state = 0;
367 		tp->d_rmode = 0 ;
368 		tp->d_xctl = 0 ;
369 		tp->d_pgrp = 0;
370 	}
371 	tp->d_prot |= DpURP;
372 	return 0;
373 }
374 
375 /* Policy decision here -- standard name of dk file known to this routine */
376 dksnamer(s, n) register char *s;
377 {
378 	register char *p = "/dev/dk/dk";
379 
380 	while (*s++ = *p++)
381 		;
382 	s--;
383 	*s++ = '0' + (n/100); n %= 100;
384 	*s++ = '0' + (n/10); n %= 10;
385 	*s++ = '0' + n;
386 	*s = '\0';
387 }
388 
389 /*
390  * Close a channel:
391  */
392 
393 /*ARGSUSED*/
394 dkclose(dev, flag)
395 dev_t dev;
396 int flag;
397 {
398 	register struct	dkdev	*tp;
399 	extern wakeup() ;
400 	extern brelse() ;
401 	short	s, chan ;
402 	int i, cl = 0;
403 
404 	chan = minor(dev);
405 	tp = &dkdev[chan];
406 	if (chan == 1) {
407 		return 0;	/* Maintenance channel */
408 	}
409 	s = spl5() ;
410 	if (u.u_signal[SIGKILL] != SIG_IGN) {	  /* detect close from exit() */
411 		while (tp->d_bufct) {
412 			tp->d_state |= DKWAIT ;
413 			sleep((caddr_t)(&tp->d_state), TTOPRI) ;
414 		}
415 	}
416 	else if (tp->d_bufct)
417 		/* Hmm -- buffers queued.  Let's wait 15 seconds max */
418 		for (i = 0; tp->d_bufct && i < 15; i++) {
419 			tp->d_state |= DKWAIT ;
420 			timeout(wakeup, (caddr_t) &tp->d_state, hz);
421 			sleep((caddr_t)(&tp->d_state), TTOPRI) ;
422 		}
423 	splx(s) ;
424 	tp->dc_state = 0;
425 	tp->d_rmode = 0;
426 	tp->d_prot &= ~DpURP;
427 	if(!tp->d_prot){
428 		cl = dk_close(chan);
429 		(void) dk_takedown(chan);
430 		tp->d_state = 0;
431 	}
432 	return -cl;
433 }
434 
435 dkread(dev, uio)
436 dev_t dev ;
437 struct uio *uio;
438 {
439 register struct dkdev *tp ;
440 int err;
441 
442 	M_ON(Mread) ;
443 	tp = &dkdev[minor(dev)] ;
444 	err = dkuread(minor(dev), uio) ;
445 	tp->d_rresid = uio->uio_resid ;
446 	M_OFF(Mread) ;
447 	return err;
448 }
449 
450 
451 dkwrite(dev, uio)
452 struct uio *uio;
453 dev_t dev ;
454 {
455 	int err;
456 
457 	M_ON(Mwrite) ;
458 	err = dkuwrite(minor(dev), uio) ;
459 	M_OFF(Mwrite) ;
460 	return err;
461 }
462 
463 #endif
464