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