BSD 4_3_Reno release
[unix-history] / usr / src / sys / vaxuba / np.c
CommitLineData
0399a117 1/*
e9280e61
KS
2 * Copyright (c) 1986 MICOM-Interlan, Inc., Boxborough Mass
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
0399a117 5 *
1c15e888 6 * @(#)np.c 7.7 (Berkeley) 6/21/90
ef9a9a2c
MK
7 *
8 * From:
9 * np.c version 1.5
10 *
11 * This version retrieved: 8/18/86 @ 18:58:54
12 * This delta created: 8/18/86 @ 18:19:24
13 *
14 * static char *SCCSID = "@(#)np.c 1.5";
15 *
0399a117
KS
16 */
17
18 /******************************************
19 * *
20 * NPDRIVER *
21 * *
22 ******************************************/
23
24/*
25 * The NP Driver is used to route requests, independent of protocol type,
26 * to the NP series Intelligent Board. The facilities it provides are
27 * used for board maintainance by the superuser and by protocol pseudo-drivers,
28 * such as WN, for sending requests to a board. The board maintainance and
29 * control functions are accessed via npioctl() by the NP support utilities.
30 */
31
ef9a9a2c
MK
32/*
33 * Modification History:
34 * 4/9/86 DDW Removed pseudo-driver initialization flag resets from NpReset
35 * 5/28/86 CJM Changed iodone() to wakeup() in NpProcQueue().
36 *
37 */
0399a117
KS
38
39/*
40 * Include Files
41 */
42
43#include "np.h"
44#if NNP > 0
1c15e888
C
45#include "param.h"
46#include "buf.h"
47#include "ubavar.h"
48#include "signal.h"
49#include "systm.h"
50#include "user.h"
51#include "proc.h"
52#include "uio.h"
53#include "errno.h"
ef9a9a2c 54
0399a117
KS
55#include "../vaxuba/npreg.h"
56
ef9a9a2c
MK
57#define b_uio b_forw
58#define b_rp av_back
0399a117
KS
59/*
60 * Global variables for pseudo-drivers.
61 */
62
ef9a9a2c
MK
63int WnInitFlag = 0;
64int IsInitFlag = 0;
65int (*IxAttach)();
66int (*IxReset)();
0399a117
KS
67
68/*
69 * Debugging level.
70 */
71
72int NpDebug = 0;
73
74/* Driver Wide State used by the ICP */
75
76int NpState = NPCLEAR;
77
78
79/*
80 * Master structure, one per board, contains request queue header,
81 * shared memory address, and memory mapping information.
82 */
83
84struct npmaster npmasters[NNP];
85
86/* Structure of the shared memory area */
87
88static struct npspace npspaces[NNP];
89
90/* Panic Message data structures */
91
92static int panicmap; /* Mapping information */
93static char NpPbuf[PANLEN] = 0; /* Panic message buffer */
94static caddr_t pstring; /* Panic string address on board, absolute */
95static unsign16 panaddr[2]; /* Panic string address on board (seg/offset) */
96
97/* Driver Wide Connection Table */
98
99static struct npconn npcnxtab[NNP][NNPCNN];
100
101/* Head of the request queue, one per board */
102
103static struct npreq reqhdr[NNP];
104
ef9a9a2c
MK
105/* Require for diagnostic packages */
106
107typedef struct npreq *reqptr;
108reqptr np_mapreq[NNP];
109
0399a117
KS
110/* The request structures, one pool per board */
111
112static struct npreq npreqs[NNP][NUMCQE];
113
114
115/*
116 * Data structures needed for BSD 4.2 Device Drivers
117 */
118
119int npprobe(), npattach(), npintr();
120struct uba_device *npdinfo[NNP];
121
122/* UNIBUS address of Network Processors */
123
124u_short npstd[] = { 0166000, 0166020, 0 };
125
126/* Interrupt vectors used by the Network Processors */
127
128static unsign16 npvectors[NNP];
129
130struct uba_driver npdriver =
131 { npprobe, 0, npattach, 0, npstd, "np", npdinfo };
132struct buf np_tab[NNP];
ef9a9a2c 133static unsigned long np_icount[NNP];
0399a117
KS
134
135
136/*
137 * External function and data structure declarations.
138 */
139
140struct npreq * NpGetReq();
141struct npmaster *NpBoardChange();
142int NpTimer();
143struct CQE * NpRemCQE();
0399a117
KS
144
145extern struct user u;
146\f
147/*
148 * Np_init() is responsible for hardware initializiation and the software
149 * initialization of the connection table and driver software data structures.
150 */
151
152npinit(unit)
153int unit;
154{
155 register int j;
156
157
158 /* Software Initialization */
159
160 npmasters[unit].flags = NPCLEAR;
161
162 NpSWinit(unit);
163
164 /* Hardware Initialization */
165
166 NpHWinit(unit);
167
168 /* Connection Table Initialization */
169
170 for(j=0;j<NNPCNN;j++) {
171 npcnxtab[unit][j].protocol = NPCLCONN;
172 npcnxtab[unit][j].unit = &npmasters[unit];
173 }
174}
175\f
176/*
177 * Np_open establishes a connection to the NP Driver using the minor
178 * device number as an identifier. A default protocol, NPMAINT, is assigned
179 * with the specified unit. Protocol and unit may be changed using the
180 * NpProtChange and NpBoardChange functions.
181 * Since the maintainance protocol does not need a working I-Board, entries
182 * are always made in the Connection Table, npcnxtab, if the board exists.
183 */
184
185/*ARGSUSED*/
186npopen(dev,flag)
187dev_t dev;
188int flag;
189{
190 int unit;
191 unsign16 conn;
192 struct npmaster *mp;
193 int error;
194
195 if(NpDebug & DEBENTRY)
196 printf("npopen\n");
197
198 /* Clear error */
199
200 error = 0;
201
202 /* Make sure it's the superuser */
203
204 if(u.u_uid)
205 return(EPERM);
206
207 /* Get the connection identifier */
208
209 if(((conn = NPCONN(dev)) >= NNPCNN) ||
210 ((unit = NPUNIT(dev)) >= NNP))
211 return(ENODEV);
212
213
214 if(NpDebug & DEBOPEN)
215 printf("conn = %x unit = %d\n",conn,unit);
216
217 /* Get the board for the specified unit */
218
219 mp = NpBoardChange(NPMAINT,unit);
220
221 if(mp != (struct npmaster *) 0) {
222 npcnxtab[unit][conn].unit = mp;
223 npcnxtab[unit][conn].protocol = NPMAINT;
224 }
225 else error = ENXIO;
226
227 if(NpDebug & DEBENTRY)
228 printf("npopen...\n");
229
230 return(error);
231}
232\f
233/*
234 * Np_close is responsible updating the connection table for
235 * that connection by marking it closed.
236 */
237
238npclose(dev)
239dev_t dev;
240{
241
242 if(NpDebug & DEBENTRY)
243 printf("npclose\n");
244
245 /* Get the connection identifier */
246
247 npcnxtab[NPUNIT(dev)][NPCONN(dev)].protocol = NPCLCONN;
248
249 if(NpDebug & DEBENTRY)
250 printf("npclose...\n");
251
252 return(0);
253
254}
255\f
256/*
257 * Npioctl is the main conduit of commands between the I-Board and the
258 * NP support utilities. Relevant information for the request is found in the
259 * cmd and addr parameters. Cmd specifies the function to perform, addr is
260 * command specific. Npioctl returns 0 if successful, or an error number
261 * (which winds up in errno).
262 */
263
264/*ARGSUSED*/
265npioctl(dev,cmd,addr,flag)
266dev_t dev;
267int cmd;
268caddr_t *addr;
269int flag;
270{
271 unsign16 protocol;
272 unsign16 conn;
273 unsign16 unit;
274 int error;
275
276 register struct npmaster *mp;
277 register struct npreq *rp;
278 unsigned usrarg;
279
280 if(NpDebug & DEBENTRY)
281 printf("npioctl\n");
282
283 /* Clear error */
284
285 error = 0;
286
287 /* Strip off IOC_VOID bit */
288
289 cmd &= CMDMASK;
290
291 /* Get connection identifier */
292
293 conn = NPCONN(dev);
294 unit = NPUNIT(dev);
295
296 /* Master pointer for this unit */
297
298 mp = npcnxtab[unit][conn].unit;
299
300 protocol = npcnxtab[unit][conn].protocol;
301
302 /* Get a request structure from the pool and initialize it */
303
304 while((rp = NpGetReq(mp->reqtab)) == NULL) {
305 mp->reqtab->flags |= WANTREQ;
306 sleep((caddr_t)(mp->reqtab),PZERO -1);
307 }
308
309 if(NpDebug & DEBREQ)
310 printf("NP Reqp is %x\n",rp);
311
312 /* Initializations of request structure */
313
314 rp->intr = (int (*)())0; /* Do not call interrupt routine */
315 rp->bufoffset = 0; /* Offset into data buffer */
0399a117
KS
316 rp->procp = u.u_procp; /* Process structure for this user */
317
318 /* Copy in user's argument to ioctl() call */
319
320 if(error = copyin(*addr,&usrarg,sizeof(usrarg)))
321 return(error);
322
323
324 if(NpDebug & DEBIOCTL)
325 printf("arg = %x\n",usrarg);
326
327 /* Execute the specified command */
328
329 switch(cmd) {
330
331 case NPSETPROT:
332 if((error = NpProtChange(usrarg,mp->unit)) == 0)
333 npcnxtab[unit][conn].protocol = usrarg;
334 break;
335 case NPSETBOARD:
336 if(mp = NpBoardChange(protocol,usrarg))
337 npcnxtab[unit][conn].unit = mp;
338 else {
339 mp = npcnxtab[unit][conn].unit;
340 error = ENXIO;
341 }
342 break;
343 case NPRESET:
344 error = NpReset(mp,rp);
345 break;
346 case NPSETNPDEB:
347 NpDebug = usrarg;
348 break;
349 case NPINIT:
350 error = NpSWinit(mp->unit);
351 break;
352 case NPSTART:
353
354#ifdef OLDROM
355 /*
356 * Kludge to work around I-Board boot from Host. Read two bytes
357 * from the board into the Device Configuration Word
358 * in Shared Memory.
359 */
360
361 NPIO(mp,(paddr_t)0x500,(paddr_t)(&mp->shmemp->statblock.sb_dcw),2,B_READ);
362
363 mp->shmemp->statblock.sb_drw = 0;
364#endif
365
366 /* Set the Address at which to begin On-Board execution */
367
368 error = NpSetXeqAddr(mp,(caddr_t)usrarg);
369 break;
370 case NPSTATS:
371 error = NpStats();
372 break;
373 case NPGPANIC:
374 error = copyout((caddr_t)NpPbuf,*addr,PANLEN);
375
376 /* Clear panic request flag and leave */
377
378 mp->flags &= ~PANICREQ;
379 break;
380 case NPPOLL:
381 error = NpPoll(mp,*addr);
382 break;
383 case NPKILL:
384 error = NpKill(mp,rp);
385 break;
386 case NPSETADDR:
387 error = NpSetMemAddr(mp,*addr);
388 break;
389 case NPRCSR0:
390 usrarg = RCSR0(mp->iobase);
391 error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
392 break;
393 case NPRCSR1:
394 usrarg = RCSR1(mp->iobase);
395 error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
396 break;
397 case NPRCSR2:
398 usrarg = RCSR2(mp->iobase);
399 error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
400 break;
401 case NPRCSR3:
402 usrarg = RCSR3(mp->iobase);
403 error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
404 break;
405 case NPWCSR0:
406 WCSR0(mp->iobase,usrarg);
407 break;
408 case NPWCSR1:
409 WCSR1(mp->iobase,usrarg);
410 break;
411 case NPWCSR2:
412 WCSR2(mp->iobase,usrarg);
413 break;
414 case NPWCSR3:
415 WCSR3(mp->iobase,usrarg);
416 break;
417 case NPNETBOOT:
418 error = NpSetIntLevel(mp,mp->vector);
419 if(error) break;
420 error = NpSetXeqAddr(mp,(caddr_t)INETBOOT);
421 break;
ef9a9a2c
MK
422 case NPSETLAST:
423 if (usrarg)
424 mp->flags &= ~LSTCMD;
425 else
426 mp->flags |= LSTCMD;
427 break;
428 case NPCLRICNT:
429 np_icount[unit] = NPCLEAR;
430 break;
431 case NPGETICNT:
432 usrarg = np_icount[unit];
433 error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
434 break;
435 case NPGETIVEC:
436 usrarg = mp->vector;
437 error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
438 break;
439 case NPMAPMEM:
440 error = NpMem(mp, rp, *addr);
441 break;
0399a117
KS
442 default:
443 printf("Bad Maintenance command: %d!\n",cmd);
444 error = EIO;
445 break;
0399a117 446 }
ef9a9a2c 447 if((cmd != NPRESET) && (cmd != NPINIT) && (cmd != NPMAPMEM))
0399a117
KS
448 NpFreeReq(mp->reqtab,rp);
449
450 if(NpDebug & DEBENTRY)
451 printf("npioctl...\n");
452
453 return(error);
454}
455
456/*
457 * np_start - start io activity
458 */
459npstart(mp)
460register struct npmaster *mp;
461{
462
ef9a9a2c 463 register struct uio *uio;
0399a117
KS
464 register struct buf *bp;
465 register struct npreq *rp;
466
467 int error; /* Return from NPIO call */
468
469 if(NpDebug & DEBENTRY)
470 printf("npstart\n");
471
472 if((bp = np_tab[mp->unit].b_actf) == (struct buf *)0) {
473 np_tab[mp->unit].b_active = 0;
474 return;
475 }
ef9a9a2c
MK
476 if((rp = (struct npreq *)(bp->b_rp)) == (struct npreq *)0) {
477 bp->b_flags = B_ERROR;
478 iodone(bp);
479 return;
480 }
481 if ((uio = (struct uio *)bp->b_uio) == (struct uio *)0) {
0399a117
KS
482 bp->b_flags = B_ERROR;
483 iodone(bp);
484 return;
485 }
486 np_tab[mp->unit].b_active = 1;
487
488 if(NpDebug & DEBIO)
ef9a9a2c
MK
489 printf("NP IO src %x dst = %x cnt = %x\n", bp->b_un.b_addr,
490 uio->uio_offset, bp->b_bcount);
0399a117
KS
491
492 /* Send the request to the board via the CSR0 command interface */
493
494 if(bp->b_flags & B_READ)
ef9a9a2c
MK
495 error = NPIO(mp, (paddr_t)uio->uio_offset, (paddr_t)rp->bufaddr,
496 bp->b_bcount, (bp->b_flags & B_READ));
0399a117 497 else
ef9a9a2c
MK
498 error = NPIO(mp, (paddr_t)rp->bufaddr, (paddr_t)uio->uio_offset,
499 bp->b_bcount, (bp->b_flags & B_READ));
0399a117
KS
500
501
502 /* Check return from I/O */
503
504 if(error) {
505 bp->b_flags |= B_ERROR;
506 np_tab[mp->unit].b_actf = bp->av_forw;
0399a117
KS
507 if(NpDebug & DEBIO)
508 printf("NPIO return error: b_flags is %x \n",bp->b_flags);
509 iodone(bp);
510 }
511
512 if(NpDebug & DEBENTRY)
513 printf("npstart...\n");
514
515}
516/*
ef9a9a2c 517 * npstrategy - the strategy routine
0399a117
KS
518 */
519
520npstrategy(bp)
521register struct buf *bp;
522{
523
524 register struct buf *ip; /* quick pointer */
525 register struct npmaster *mp; /* master structure for this device */
526 register struct npreq *rp; /* reqest struct pointer */
527 int s; /* priority to return to */
528
529 if(NpDebug & DEBENTRY)
530 printf("npstrategy\n");
531 if(NpDebug & DEBIO)
532 printf("flag = %x count = %x paddr = %x %x blkno = %x %x\n",
ef9a9a2c
MK
533 bp->b_flags, bp->b_bcount, bp->b_un.b_addr, bp->b_un.b_addr,
534 bp->b_blkno,bp->b_blkno);
0399a117
KS
535
536 /* get master structure */
537
538 mp = npcnxtab[NPUNIT(bp->b_dev)][NPCONN(bp->b_dev)].unit;
539
540 /* make sure the boards ok */
541
542 if (mp->flags & BADBOARD) {
543 bp->b_flags |= B_ERROR;
544
545 if(NpDebug & DEBMEM)
546 printf("Bad Board %x bp %x\n",mp->flags,bp->b_flags);
547
548 np_tab[mp->unit].b_actf = bp->av_forw;
549 iodone(bp);
550 return;
551 }
552
553 /* Initializations of request structure */
554
555 while((rp = NpGetReq(mp->reqtab)) == NULL) {
556 mp->reqtab->flags |= WANTREQ;
557 sleep((caddr_t)(mp->reqtab),PZERO -1);
558 }
559
560 rp->bufoffset = 0; /* This is the start of the buffer */
561 ip = &np_tab[mp->unit];
ef9a9a2c 562 bp->b_rp = (struct buf *)rp;
0399a117
KS
563
564 rp->flags |= KERNREQ; /* Mark it as kernel so not to map */
565
566 rp->mapbase = ubasetup(mp->devp->ui_ubanum,bp,0);
567 rp->bufaddr = (caddr_t)((int)(rp->mapbase) & UBADDRMASK);
568
569 s = spl5();
570 if(ip->b_actf ==(struct buf *)0)
571 ip->b_actf = bp;
572 else {
573 if(ip->b_actf->av_forw)
574 printf("Panic NP100 bad buffer chain\n");
575 ip->b_actf->av_forw = bp;
576 }
577 ip->b_actl = bp;
578
579 NpAddReq(mp->reqtab,rp); /* Queue onto active list */
580
581 if(ip->b_active == 0) {
582
583 if(NpDebug & DEBIO)
584 printf("calling npstart %x\n",mp);
585
586 npstart(mp);
587 }
588 splx(s);
589
590 if(NpDebug & DEBIO)
591 printf("back from npstart\n");
592
593 /* Await completion of I/O */
594
595 iowait(bp);
596
597 if(NpDebug & DEBIO)
598 printf("after iowait in npstrategy\n");
599
600 /* Remove request from queue */
601
602 NpRemReq(rp);
603
604 /* Release mapping registers */
605
606 ubarelse(mp->devp->ui_ubanum,&rp->mapbase);
607
608 /* Free up request structure */
609
610 NpFreeReq(mp->reqtab,rp);
611
612 if(NpDebug & DEBENTRY)
613 printf("Leaving npstrategy flags is %x\n",bp->b_flags);
614}
615
616unsigned
617nptrim(bp)
618register struct buf *bp;
619{
620
621 if(bp->b_bcount > NPMAXXFR)
622 bp->b_bcount = NPMAXXFR;
623}
624
625/*
626 * Npread dumps data from the board to the user's buffer
627 */
628npread(dev,uio)
629dev_t dev;
630struct uio *uio;
631{
ef9a9a2c
MK
632 struct buf *bp;
633 bp = &npcnxtab[NPUNIT(dev)][NPCONN(dev)].np_rbuf;
0399a117
KS
634
635 if(NpDebug & DEBENTRY)
636 printf("in npread\n");
637
ef9a9a2c
MK
638 bp->b_uio = (struct buf *)uio;
639 return(physio(npstrategy,bp,dev,B_READ ,nptrim,uio));
0399a117
KS
640}
641
642/*
643 * Npwrite loads the np100 board from the user's buffer
644 */
645
646npwrite(dev,uio)
647dev_t dev;
648struct uio *uio;
649{
650 struct buf *bp;
651 bp = &npcnxtab[NPUNIT(dev)][NPCONN(dev)].np_wbuf;
652
653 if(NpDebug & DEBENTRY)
654 printf("in npwrite \n");
655
ef9a9a2c 656 bp->b_uio = (struct buf *)uio;
0399a117
KS
657 return(physio(npstrategy,bp,dev,B_WRITE ,nptrim,uio));
658}
0399a117 659
ef9a9a2c 660/*
0399a117
KS
661 * npreset - called as result of a UNIBUS reset.
662 */
663
664npreset(uban)
665int uban;
666{
667
668 register struct npmaster *mp;
669 register struct npreq *rp;
670 register struct uba_device *ui;
671 int i;
672
ef9a9a2c
MK
673 if(NpDebug & DEBENTRY)
674 printf("npreset(ubareset)\n");
0399a117
KS
675 for(i = 0; i < NNP; i++) {
676
677 if(((ui = npdinfo[i]) == (struct uba_device *)NULL) ||
678 (ui->ui_ubanum != uban))
679 continue;
680
681 mp = &npmasters[i];
ef9a9a2c
MK
682
683 /* Get a Request structure */
684
685 while((rp = NpGetReq(mp->reqtab)) == NULL) {
686 mp->reqtab->flags |= WANTREQ;
687 sleep((caddr_t)(mp->reqtab),PZERO -1);
688 }
689
690 NpReset(mp,rp);
0399a117 691 }
ef9a9a2c
MK
692 if(NpDebug & DEBENTRY)
693 printf("npreset(ubareset)...\n");
0399a117
KS
694}
695
ef9a9a2c 696
0399a117
KS
697/*
698 * Nppoll looks for work by polling each board. He goes to sleep if there are
699 * no outstanding requests for him but reminds the board that he's there when
700 * needed.
701 */
702
703NpPoll(mp,addr)
704struct npmaster *mp;
705caddr_t addr;
706{
707 int error;
708
709 struct {
710 unsign16 request;
711 unsign16 unit;
712 }icpreq;
713
714 if(NpDebug & DEBMAINT)
715 printf("NpPoll: flags is %x.\n",mp->flags);
716
717 while(TRUE) {
718
719 for(mp = npmasters; mp; mp = mp->next) {
720
721 if(mp->flags & BOARDREQ) {
722
723 /* Get request type from master structure */
724
725 if(mp->flags & BRDRESET) {
726 icpreq.request = ICPPOLL;
727 mp->reqtab->reqcnt--;
728
729 if(NpDebug & DEBMAINT)
730 printf("Waking NpResetter!\n");
731
732 wakeup((caddr_t)(&mp->reqtab));
733 }
734 else if(mp->flags & PANICREQ)
735 icpreq.request = ICPPANIC;
736 else if(mp->flags & DUMPREQ)
737 icpreq.request = ICPDUMP;
738 else if(mp->flags & LOADREQ)
739 icpreq.request = ICPLOAD;
740 else {
741 mp->flags &= ~BOARDREQ;
742 continue;
743 }
744
745 if(NpDebug & DEBMAINT)
746 printf("ProcICP servicing %d \n",icpreq.request );
747
748 /* Request and unit number to be sent */
749
750 icpreq.unit = mp->unit;
751
752 /* Copy service request to calling process */
753
754 error = copyout(&icpreq,addr,sizeof(icpreq));
755
756 /* Mark Poller as being unavailable */
757
758 NpState &= ~ICPAVAIL;
759
760 return(error);
761 }
762 }
763
764 /* Mark Poller as being available */
765
766 NpState |= ICPAVAIL;
767
c376c8e7
MK
768 if (error = tsleep((caddr_t)&NpState, (PZERO + 1) | PCATCH,
769 devio, 0))
770 return (error);
0399a117
KS
771
772 if(NpDebug & DEBMAINT)
773 printf("wakeup in NpPoll\n");
774
775 }
776}
777\f
778/*
779 * Software initialization of Driver data structures for the specified unit.
780 */
781
782NpSWinit(unit)
783int unit;
784{
785
786 register int j;
787 register struct npmaster *mp;
788 register struct npspace *npsp;
789 register struct CmdQue *cqp;
790 int offset;
791
792 if(NpDebug & DEBINIT)
793 printf("SW reset on unit %d.\n",unit);
794
ef9a9a2c
MK
795 np_icount[unit] = NPCLEAR;
796 np_mapreq[unit] = (struct npreq *) NPCLEAR;
797
0399a117
KS
798 /* Initialize master structure pointer for this unit */
799
800 mp = &npmasters[unit];
801
802 /* Initialize unit buffer headers */
803
804 np_tab[unit].b_active = 0;
805 np_tab[unit].b_actf = 0;
806
807 /* UBA device structure for this unit */
808
809 mp->devp = npdinfo[unit];
810
811 /* Interrupt vector for this unit */
812
813 mp->vector = npvectors[unit];
814
815 if(unit == (NNP -1))
816 mp->next = (struct npmaster *)NULL;
817 else mp->next = &npmasters[unit + 1];
818
819 /*
820 * Guarantee alignment of shared memory area on a
821 * 16 byte boundary as required by I-Board
822 */
823
824 mp->shmemp = &npspaces[unit];
825 mp->shmemp = (struct npspace *)ROUND16((int)(mp->shmemp));
826
827 /* Base address of this controller */
828
829 mp->iobase = (struct NPREG *)(mp->devp->ui_addr);
830
831 if(NpDebug & DEBMEM) {
832 printf("Npspaces starts at %x.\n",npspaces);
833 printf("Shared memory starts at %x.\n",mp->shmemp);
834 printf("End of shared memory is %x.\n",&npspaces[unit + 1]);
835 printf("Iobase is %x.\n",mp->iobase);
836 printf("Npmasters start at %x\n",npmasters);
837 printf("Reqhdr start at %x\n",reqhdr);
838 printf("Npreqs start at %x\n",npreqs);
839 }
840
841 /* Initialize the request header */
842
843 mp->reqtab = &reqhdr[unit];
844
845 /* Unit initialization */
846
847 mp->unit = unit;
848
849 /* Initialize Status Block */
850
851 npsp = mp->shmemp;
852 offset = (int) (mp->shmemp);
853
854 npsp->statblock.sb_drw = 0;
855 npsp->statblock.sb_hcw = HOSTCONF;
856 npsp->statblock.sb_dcw = 0;
857 npsp->statblock.sb_dpm = 0;
858
859 npsp->statblock.sb_dcq = (unsign16)((int)(&npsp->devcq))-offset;
860
861 npsp->statblock.sb_hcq = (unsign16)((int)(&npsp->hostcq))-offset;
862
863 /* Initialize Device Command Queue */
864
865 cqp = (struct CmdQue *) &npsp->devcq;
866
867 if(NpDebug & DEBCQ)
868 printf("Device CQ at %x\n",cqp);
869
870 cqp->scanflag = NPCLEAR;
871 cqp->chngflag = NPCLEAR;
872
873 cqp->cq_add = (unsign16)(int)(&cqp->cq_cqe[0]) - offset;
874 cqp->cq_rem = cqp->cq_add;
875
876 cqp->cq_wrap = (unsign16)(int)(&cqp->cq_cqe[NUMCQE]) - offset;
877
878 for(j = 0; j < NUMCQE; j++)
879 cqp->cq_cqe[j] = (unsign16)NULL;
880
881 /* Initialize Host Command Queue */
882
883 cqp = (struct CmdQue *) &npsp->hostcq;
884
885 if(NpDebug & DEBCQ)
886 printf("HOST CQ at %x\n",cqp);
887
888 cqp->scanflag = NPCLEAR;
889 cqp->chngflag = NPCLEAR;
890
891 cqp->cq_add = (unsign16)(int)(&cqp->cq_cqe[0]) - offset;
892 cqp->cq_rem = cqp->cq_add;
893
894 cqp->cq_wrap = (unsign16)(int)(&cqp->cq_cqe[NUMCQE]) - offset;
895
896 for(j = 0; j < NUMCQE; j++)
897 cqp->cq_cqe[j] = (unsign16)NULL;
898
899 /*
900 * Initialize the reqid of the elements to the address
901 * of the corresponding Npreq structure. These don't change.
902 */
903
904 for(j = 0; j < NUMCQE; j++)
905 npsp->elements[j].cqe_reqid = &npreqs[unit][j];
906
907 /*
908 * Initialize the Request Header (reqhdr), free list of
909 * npreqs, and pointers to CQEs.
910 */
911
912 reqhdr[unit].forw = reqhdr[unit].back = &reqhdr[unit];
913 reqhdr[unit].free = &npreqs[unit][0];
914
915 for(j = 0; j < NUMCQE; j++) {
0399a117
KS
916 npreqs[unit][j].free = &npreqs[unit][j + 1];
917 npreqs[unit][j].element = &npsp->elements[j];
918 npreqs[unit][j].forw = npreqs[unit][j].back = (struct npreq *)NULL;
ef9a9a2c 919 npreqs[unit][j].flags = NPCLEAR;
0399a117
KS
920 }
921 npreqs[unit][--j].free = &reqhdr[unit];
922
923 /*
924 * Set up the UNIBUS I/O Map Registers for the
925 * Shared memory area.
926 */
927
928 mp->iomapbase = uballoc(mp->devp->ui_ubanum,(caddr_t)(mp->shmemp),sizeof(struct npspace),0);
929
930
931 if(NpDebug & DEBENTRY)
932 printf("SW_Init...\n");
ef9a9a2c 933 return(0);
0399a117
KS
934}
935\f
936/*
937 * NpHWinit() issues a hardware reset to the specified board and waits
938 * for on-board diagnostics to complete. It returns 0 if the board is
939 * present and passed diagnostics, an error value otherwise.
940 */
941
942NpHWinit(unit)
943int unit;
944{
945 register struct npmaster *mp;
946 struct NPREG *REG;
947 unsign16 status;
948 int dflag;
949
950 if(unit >= NNP)
951 return(ENXIO);
952
953 mp = &npmasters[unit];
954
955 if(NpDebug & DEBENTRY)
956 printf("NpHWinit\n");
957
958 /* See if the board is out there */
959
960 REG = (struct NPREG *)mp->iobase;
961
962 if(NpDebug & DEBINIT)
963 printf("REG in HWinit is %x.\n",mp->iobase);
964
965 if(!(mp->flags & BRDRESET))
966
967 if(badaddr(REG,2)) {
968 mp->flags |= BADBOARD;
969 printf("\nNP100 unit %d not found!\n",unit);
970 return(ENXIO);
971 }
972
973
0399a117
KS
974 if(NpDebug & DEBENTRY)
975 printf("Resetting the NP100 Board at %x\n",mp->iobase);
976
977 /* Reset the Board */
978
979 RESET(mp);
980
981 dflag = NPCLEAR;
982
983 timeout(NpTimer,&dflag,DIAGTIME);
984
985 /* Wait for Enable and Read Data Ready to go high */
986
987 while(! ((RCSR1(mp->iobase) & NPENB) && (RCSR1(mp->iobase) & NPRDR))) {
988 if(dflag)
989 break;
990
991 }
992
993 untimeout(NpTimer,&dflag);
994
995 if(NpDebug & DEBINIT)
996 printf("np reset %d \n",dflag);
997
998 if(dflag) {
999 mp->flags |= BADBOARD;
1000 printf("NP100 Unit %d timed out!\n",unit);
1001 return(EIO);
1002 }
1003
1004 status = RCSR0(mp->iobase);
1005
1006 /* Check for Hardware OK */
1007
1008 if(!(RCSR1(mp->iobase) & NPHOK)) {
1009 mp->flags |= BADBOARD;
0399a117
KS
1010 printf("NP100 Unit %d Failed diagnostics!\n",unit);
1011 printf("Status from CSR0: %x.\n",status);
1012 return(EIO);
1013 }
1014
1015 if(NpDebug & DEBENTRY)
1016 printf("HWinit...\n");
1017
1018 return(0);
1019}
1020\f
1021/*
1022 * NP Driver Interrupt Handler
1023 */
1024
1025npintr(unit)
1026int unit;
1027{
1028 register struct npmaster *mp;
1029 register struct buf *bp;
1030
1031 if(NpDebug & DEBENTRY)
1032 printf("npintr on unit %d!\n",unit);
1033
1034 mp = &npmasters[unit];
ef9a9a2c 1035 np_icount[unit]++;
0399a117
KS
1036
1037 if(NpDebug & DEBINTR)
ef9a9a2c
MK
1038 printf("npintr mp->flags = %x interupt count = %x\n",
1039 mp->flags, np_icount[unit]);
0399a117
KS
1040
1041 /* Wake up anyone sleeping on a CSR0 Command */
1042
1043 if(mp->flags & CSRPEND) {
1044
1045 mp->flags &= ~CSRPEND;
1046 if(np_tab[mp->unit].b_active) {
1047 np_tab[mp->unit].b_active = 0;
1048 bp = np_tab[mp->unit].b_actf;
1049 np_tab[mp->unit].b_actf = bp->av_forw;
1050
1051 if(NpDebug & DEBINTR)
1052 printf("bp = %x resid = %d forw = %x\n",bp,
1053 bp->b_resid,bp->av_forw);
1054
1055 bp->b_resid = 0;
1056 iodone(bp);
1057 }
1058 if(mp->flags & PANIC3) {
1059 mp->flags &= ~PANIC3;
1060 mp->flags = AVAILABLE;
1061 ubarelse(mp->devp->ui_ubanum,&panicmap);
1062 }
1063 if(mp->flags & PANIC2) {
1064 mp->flags &= ~PANIC2;
1065 printf("Panic Message: %s",NpPbuf);
1066 mp->flags |= PANIC3;
1067 NpPbuf[0] = 0;
1068 NPIO(mp,(paddr_t)((int) panicmap & UBADDRMASK),(paddr_t)pstring,sizeof(NpPbuf),B_WRITE);
1069 }
1070 if(mp->flags & PANIC1) {
1071 mp->flags &= ~PANIC1;
1072 mp->flags |= PANIC2;
1073 ubarelse(mp->devp->ui_ubanum,&panicmap);
1074 panicmap = uballoc(mp->devp->ui_ubanum,(caddr_t)NpPbuf,sizeof(NpPbuf),0);
1075 pstring = (caddr_t)((panaddr[1] << 4) + panaddr[0]);
1076 NPIO(mp,(paddr_t)pstring,(paddr_t)((int) panicmap & UBADDRMASK),sizeof(NpPbuf),B_READ);
1077 }
1078
1079 wakeup((caddr_t)mp);
1080 goto out;
1081 }
1082
1083 /* Mark unit as being available if Device Protocol Mask set */
1084
1085 if(!(mp->flags & AVAILABLE)) {
1086
8468e120 1087 if((mp->shmemp->statblock.sb_dpm) && (!(mp->flags & BRDRESET)))
0399a117
KS
1088
1089 mp->flags = AVAILABLE;
0399a117
KS
1090 }
1091
1092 /* Honor service requests from the device */
1093
1094 switch(mp->shmemp->statblock.sb_drw) {
1095
1096 case NOREQ:
1097 break;
1098
1099 case NPPANIC:
1100
1101 printf("\nPanic from NP100 unit %d!\n",mp->unit);
1102 mp->flags &= ~AVAILABLE;
1103 mp->flags |= PANIC1;
1104
1105 /* Clear device request word */
1106
1107 mp->shmemp->statblock.sb_drw = 0;
1108
1109 panicmap = uballoc(mp->devp->ui_ubanum,(caddr_t)panaddr,sizeof(panaddr),0);
1110 NPIO(mp,(paddr_t)NPPSADDR,(paddr_t)((int)panicmap & UBADDRMASK),sizeof(panaddr),B_READ);
1111 goto out;
1112 break;
1113
1114 case NPDUMP:
1115 mp->flags |= (DUMPREQ | BOARDREQ);
1116
1117 /* Clear device request word */
1118
1119 mp->shmemp->statblock.sb_drw = 0;
1120
1121 if(NpState & ICPAVAIL)
1122 wakeup((caddr_t)&NpState);
1123 break;
1124
1125 case NPLOAD:
1126 mp->flags |= (LOADREQ | BOARDREQ);
1127
1128 /* Clear device request word */
1129
1130 mp->shmemp->statblock.sb_drw = 0;
1131
1132 if(NpState & ICPAVAIL)
1133 wakeup((caddr_t)&NpState);
1134 break;
1135
1136 default:
1137 printf("Bad Req: %x.\n",mp->shmemp->statblock.sb_drw);
1138 goto out;
1139
1140 }
1141
1142 /* Process the Host Command Queue for this device */
1143
1144 NpProcQueue(mp);
1145
1146out:
1147 CLEARINT(mp); /* Clear the interrupt */
1148
1149 if(NpDebug & DEBENTRY)
1150 printf("npintr...\n");
1151
1152 return(1); /* Interrupt serviced */
1153
1154}
1155\f
1156/*
1157 * This routine, called from the interrupt handler, is used to process the
1158 * Host Command Queue for the specified device.
1159 */
1160
1161NpProcQueue(mp)
1162struct npmaster *mp;
1163{
1164 register struct CmdQue *cqp;
1165 register struct CQE *ep;
1166 register struct npreq *rp;
1167 register int base;
1d5affa5 1168 int s;
0399a117
KS
1169
1170 if(NpDebug & DEBENTRY)
1171 printf("NpProcQueue\n");
1172
1173 cqp = &mp->shmemp->hostcq; /* Command Queue pointer */
1174
1d5affa5
MK
1175 s = spl5();
1176 if(mp->flags & SCANNING) {
1177 splx(s);
0399a117 1178 return;
1d5affa5
MK
1179 }
1180 mp->flags |= SCANNING;
1181 splx(s);
0399a117 1182
1d5affa5 1183 cqp->scanflag | = ON;
0399a117
KS
1184
1185 base = (int)mp->shmemp; /* Shared memory base address */
1186
1d5affa5 1187 while(1) {
0399a117 1188
1d5affa5
MK
1189 cqp->scanflag |= ON;
1190 cqp->chngflag &= ~ON;
0399a117
KS
1191 while(ep = NpRemCQE(cqp,base)) {
1192
1193 rp = ep->cqe_reqid;
1194
1195 if(NpDebug & DEBCQE)
1196 printf("cqe_sts is %x ep = %x\n",ep->cqe_sts,ep);
1197
1198 switch (ep->cqe_sts) {
1199
1200 case NPDONE:
1201 rp->flags |= REQDONE; /* Normal completion */
1202 break;
1203 case NPIFC: /* IFC Request */
1204 rp->flags |= IOIFC;
1205 break;
1206 case NPPERR: /* Protocol Error */
1207 rp->flags |= (NPPERR | REQDONE);
1208 break;
1209 case NPMERR: /* Memory allocation */
1210 rp->flags |= (NPMERR | REQDONE);
1211 break;
1212 default: /* Error on Board */
1213 rp->flags |= (IOERR | REQDONE);
1214 break;
1215
1216 }
1217
1218 if(NpDebug & DEBCQE) {
1219 printf("flag is %x reqid = %x\n",rp->flags,ep->cqe_reqid);
1220 printf("wakeup in procqueue\n");
1221 }
1222
1223 if(rp->intr) {
1224
1225 if(NpDebug & DEBINTR)
1226 printf("calling usr intr at %x\n",
1227 rp->intr);
1228
1229 /* Call interrupt routine */
1230
1231 (*rp->intr)(mp,rp);
0399a117
KS
1232 }
1233 else {
1234
1235 if(NpDebug & DEBINTR)
1236 printf("waking up %x\n",rp);
1237
ef9a9a2c 1238 /* if(rp->flags & NPUIO)
0399a117
KS
1239 iodone(&rp->buf);
1240 else wakeup((caddr_t) (rp)); /* Awaken */
1241
ef9a9a2c 1242 wakeup((caddr_t)(rp)); /* Awaken */
0399a117
KS
1243 if(NpDebug & DEBINTR)
1244 printf("AWAKE\n");
1245 }
0399a117
KS
1246 }
1247
1d5affa5 1248 cqp->scanflag &= ~ON;
0399a117 1249 if(!(cqp->chngflag & ON))
1d5affa5 1250 break;
0399a117
KS
1251
1252 }
1253
1d5affa5 1254 mp->flags &= ~SCANNING;
0399a117
KS
1255 if(NpDebug & DEBENTRY)
1256 printf("NpProcQueue...\n");
1257}
1258
1259/*
1260 * NpIFC - processes an IFC (Internal Fuction Call) request
1261 * NOTE: this function must be called from the user context
1262 * on all virtual pageing systems
1263 *
1264 */
1265NpIFC(mp,rp)
1266register struct npmaster *mp;
1267register struct npreq *rp;
1268{
1269 register struct CQE *ep;
1270
1271 if(NpDebug & DEBENTRY)
1272 printf("NpIFC\n");
1273
1274 ep = rp->element;
1275 rp->flags &= ~IOIFC;
1276 switch(ep->cqe_func) {
1277
1278 case NPUNLOCK: /* Unlock process, free up mapping registers */
1279
1280 if(NpDebug & DEBIFC)
1281 printf("NPUNLOCK\n");
1282
1283 if(rp->mapbase)
1284 NpUnMapMem(mp,rp);
1285 break;
1286
1287 case NPLOCK: /* Lock process, get mapping registers */
1288
1289 if(NpDebug & DEBIFC)
1290 printf("NPLOCK\n");
1291 NpMapMem(mp,rp,rp->virtmem,rp->bytecnt);
1292 ep->cqe_dma[0] = LOWORD(rp->bufaddr);
1293 ep->cqe_dma[1] = HIWORD(rp->bufaddr);
1294 break;
1295
1296 case NPREMAP:
1297
1298 if(NpDebug & DEBIFC)
1299 printf("NPREMAP\n");
1300
1301 /* Remap user buffer and update buffer offset */
1302#ifdef USG
1303 np_remapmem(rp,rp->virtmem);
1304 ep->cqe_dma[0] = LOWORD(rp->bufaddr);
1305 ep->cqe_dma[1] = HIWORD(rp->bufaddr);
1306 break;
1307#endif
1308
1309 default:
1310 if(NpDebug & DEBIFC)
1311 printf("Bad case %x in IFC\n", ep->cqe_func);
1312
1313 rp->flags |= (REQDONE | IOERR);
1314 break;
1315 }
1316}
1317\f
1318/*
1319 * The following contains various routines for allocating and deallocating
1320 * structures used by the NP Driver. Routines are also here for addding
1321 * and removing Command Queue Elements from a Command Queue.
1322 */
1323
1324/*
1325 * Get a free NP Request structure from the list pointed to by head. Returns
1326 * a pointer to a npreq or NULL if none left.
1327 */
1328
1329struct npreq *
1330NpGetReq(head)
1331struct npreq *head;
1332{
1333
1334 register struct npreq *p;
1335
1336 p = head->free;
1337 head->free = p->free;
ef9a9a2c
MK
1338 if (p->flags & REQALOC)
1339 printf("GetReq: Req %x already allocated\n", p);
1340 p->flags &= WANTREQ;
1341 if (p != head)
1342 p->flags |= REQALOC;
0399a117
KS
1343 return(p==head ? (struct npreq *)NULL : p);
1344}
1345
1346/*
1347 * Return a NP Request structure to the free list pointed to by head.
1348 */
1349
1350NpFreeReq(head,nprp)
1351register struct npreq *head, *nprp;
1352{
ef9a9a2c 1353 int s;
0399a117
KS
1354
1355 if(NpDebug & DEBREQ)
1356 printf("NpFreeReq, head is %x rp is %x\n",head,nprp);
1357
ef9a9a2c
MK
1358 if (nprp == NULL) {
1359 printf("FREEREQ: attempt to free null pointer\n");
1360 return;
1361 }
1362 if (!(nprp->flags & REQALOC)) {
1363 printf("FREEREQ: attempt to free unallocated request %x\n",
1364 nprp);
1365 return;
1366 }
1367 if (nprp->flags & REQUSE)
1368 printf("FREEREQ: freeing unremoved request %x\n", nprp);
1369
1370 s = spl5();
0399a117
KS
1371 nprp->forw = nprp->back = (struct npreq *)NULL;
1372 nprp->free = head->free;
1373 head->free = nprp;
ef9a9a2c
MK
1374 nprp->flags &= ~REQALOC;
1375 splx(s);
0399a117
KS
1376
1377 /* Wake up any processes waiting for a request structure */
1378
1379 if(head->flags & WANTREQ) {
1380 head->flags &= ~WANTREQ;
1381 wakeup((caddr_t)head);
1382 }
1383
1384 if(NpDebug & DEBENTRY)
1385 printf("NpFreeReq...\n");
1386}
1387
1388/*
1389 * Add a Command Queue Element onto the specified Command Queue and
1390 * update its Add offset.
1391 */
1392
1393NpAddCQE(ep,cqp,mp)
1394struct CQE *ep;
1395struct CmdQue *cqp;
1396struct npmaster *mp;
1397{
1398
1399 register unsign16 *temp;
1400 register unsign16 cqe_offset;
1401 register int base;
1402
1403 base = (int)mp->shmemp; /* Shared memory base address */
1404
1405 temp = (unsign16 *)(base + cqp->cq_add); /* Offset to add element */
1406
1407 cqe_offset = (unsign16)((int)ep - base);
1408
1409 if(*temp) { /* Should never happen */
1410
1411 printf("No more room on Command Queue!\n");
0399a117
KS
1412 return;
1413 }
1414 else *temp = cqe_offset; /* Enter this request's offset */
1415
0399a117
KS
1416 /* Update cqe_add where next request is to be added */
1417
1418 cqp->cq_add += sizeof(unsign16);
1419
1420 if(cqp->cq_add == cqp->cq_wrap) /* Wrap if necessary */
1421 cqp->cq_add = (unsign16)((int)cqp->cq_cqe - base);
1422
1d5affa5
MK
1423 cqp->chngflag |= ON; /* Set change flag unconditionally */
1424
0399a117
KS
1425 /* Interrupt the Board if his scan flag isn't on */
1426
1427 if(!(cqp->scanflag & ON))
1428
1429 INTNI(mp); /* Interrupt the Board */
1430
1431}
1432
1433/*
1434 * The NpRemCQE routine is used to remove the next CQE from the Command Queue
1435 * specified by cqp. The common offset of shared memory used by the device
1436 * is specified by base. NpRemCQE returns a pointer to the next CQE or
1437 * NULL if there are none left. This routine will also update the cqe_rem
1438 * offset which specifies where the next element to be removed from the
1439 * queue is located.
1440 */
1441
1442struct CQE *
1443NpRemCQE(cqp,base)
1444struct CmdQue *cqp;
1445int base;
1446{
1447
1448 register unsign16 *temp;
1449 register unsign16 cqe_offset;
1450
1451 cqp->chngflag &= ~ON; /* Turn off unconditionally */
1452
1453 /* Get address of element to remove */
1454
1455 temp = (unsign16 *)(base +cqp->cq_rem);
1456
1457 if(*temp == NULL) /* If none left, go home */
1458 return((struct CQE *) NULL);
1459
1460 else cqe_offset = *temp; /* Offset of CQE to remove */
1461
1462 /* Update the Command Queue's cqe_rem offset */
1463
1464 *temp = NULL; /* Clear out this entry */
1465
1466 cqp->cq_rem += sizeof(unsign16); /* Bump offset */
1467
1468 if(cqp->cq_rem == cqp->cq_wrap) /* Wrap if necessary */
1469 cqp->cq_rem = (unsign16)((int)cqp->cq_cqe - base);
1470
1471 temp = (unsign16 *)(base + cqe_offset); /* CQE address */
1472 return((struct CQE *)temp); /* is returned */
1473}
1474
1475/*
1476 * NpAddReq will add the specified npreq structure to the queue controlled
1477 * by head.
1478 */
1479
1480NpAddReq(head,rp)
1481register struct npreq *head, *rp;
1482{
ef9a9a2c 1483 int s;
0399a117 1484
ef9a9a2c 1485 if (NpDebug & (DEBENTRY|DEBREQ))
0399a117
KS
1486 printf("NpAddReq: %x\n",rp);
1487
ef9a9a2c
MK
1488 if (rp->flags & REQUSE)
1489 printf("ADDREQ: Request %x allready in use\n", rp);
1490
1491 s = spl7();
0399a117
KS
1492 rp->forw = head->forw;
1493 rp->forw->back = rp;
1494 rp->back = head;
1495 head->forw = rp;
ef9a9a2c
MK
1496 rp->flags |= REQUSE;
1497 splx(s);
0399a117
KS
1498
1499 if(NpDebug & DEBENTRY)
1500 printf("NpAddReq...\n");
1501}
1502
1503/*
1504 * NpRemReq is used to remove a npreq structure from the queue specified by
1505 * head.
1506 */
1507
1508NpRemReq(rp)
1509register struct npreq *rp;
1510{
ef9a9a2c 1511 int s;
0399a117 1512
ef9a9a2c 1513 if (NpDebug & (DEBENTRY|DEBREQ))
0399a117
KS
1514 printf("NpRemReq: %x\n",rp);
1515
ef9a9a2c
MK
1516 if (rp == NULL) {
1517 printf("REMREQ: null pointer removal requested\n");
1518 return;
1519 }
1520 if (!(rp->flags & REQUSE)) {
1521 printf("REMREQ: trying to rem unused req %x\n", rp);
1522 return;
1523 }
1524 if (!(rp->flags & REQALOC)) {
1525 printf("REMREQ: trying to rem unallocated req %x\n", rp);
1526 return;
1527 }
1528
1529 s = spl7();
0399a117
KS
1530 rp->back->forw = rp->forw;
1531 rp->forw->back = rp->back;
ef9a9a2c
MK
1532 rp->flags &= ~REQUSE;
1533 splx(s);
0399a117
KS
1534
1535 if(NpDebug & DEBENTRY)
1536 printf("NpRemReq...\n");
1537}
1538
1539\f
1540/*
1541 * The following routines are used to communicate with the
1542 * NI Hardware via the CSR0 commands. These commands are issued during
1543 * the hardware initializtion process and may also be used subsequently
1544 * by privileged processes who wish to communicate in this way. The
1545 * convention for passing data as a Command Block is discussed in detail
1546 * in the NI1510 UNIBUS Compatible Ethernet Communications Processor
1547 * Hardware Specification.
1548 */
1549
1550NpSendCSR0(iobase,src,bcount)
1551struct NPREG *iobase;
1552register unsign16 *src;
1553int bcount;
1554{
1555 register int wcount;
1556 int i;
1557 int csrflag;
1558 unsign16 tmp;
1559
1560 if(NpDebug & DEBENTRY)
1561 printf("NpSendCSR0\n");
1562
1563 /* Jolt the board into CSR0 command mode if necessary */
1564
1565 if(!(RCSR1(iobase) & NPENB)){
1566 tmp = NPCLEAR; /* MC68000 clr reads before writing */
1567 WCSR0(iobase,tmp);
1568 }
1569
1570 wcount = (bcount +1) >> 1; /* Convert byte count to word count */
1571
1572 /* Clear timer flag before beginning the timer */
1573
1574 csrflag = NPCLEAR;
1575 timeout(NpTimer,&csrflag,DIAGTIME);
1576
1577 for(i = 0; (i < wcount) & (csrflag == NPCLEAR); i++) {
1578 while(! ((RCSR1(iobase) & NPENB) && (RCSR1(iobase) & NPRDY)))
1579 if(csrflag) break;
1580 WCSR0(iobase,*src);
1581 src++; /* Better do this WCSR is a macro */
1582 }
1583
1584 /* Clear the timer entry */
1585
1586 untimeout(NpTimer,&csrflag);
1587
1588 /* Error if timer went off */
1589
1590 if(csrflag)
1591 return(EIO);
1592
1593 if(NpDebug & DEBENTRY)
1594 printf("NpSendCSR0...\n");
1595 return(0);
1596}
1597
1598/*
1599 * NpSetIntLev sets the UNIBUS interrupt vector to be used by the NP board when
1600 * interupting the host. The board is specified by mp.
1601 */
1602
1603NpSetIntLevel(mp,level)
1604struct npmaster *mp;
1605int level;
1606{
1607
1608 struct {
1609 unsign16 cmd_word;
1610 unsign16 int_level;
1611 }cmd_block;
1612
1613 cmd_block.cmd_word = NPCBI | CBICNT;
1614 cmd_block.int_level = level;
1615
1616 return(NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block)));
1617}
1618
1619/*
1620 * NpSetMemAddr is used to declare the shared memory area address to be used
1621 * for communication between the driver and the device. This address is used
1622 * to access data structures by acting as a base from which defined offsets
1623 * locate data. The board is specified by mp.
1624 */
1625
1626NpSetMemAddr(mp,addr)
1627struct npmaster *mp;
1628caddr_t addr;
1629{
1630
1631 caddr_t shmaddr;
1632 int error;
1633
1634 struct {
1635 unsign16 cmd_word;
1636 unsign16 hi_addr;
1637 unsign16 lo_addr;
1638 } cmd_block;
1639
1640 if(NpDebug & DEBENTRY)
1641 printf("NpSetMemAddr\n");
1642
1643 shmaddr = addr;
1644
1645 if(NpDebug & DEBMEM)
1646 printf("NpSetMemAddr, addr is %x shmaddr is %x.\n",addr,shmaddr);
1647
1648 cmd_block.cmd_word = NPCMD | CMDCNT;
1649 cmd_block.hi_addr = HIWORD(shmaddr);
1650 cmd_block.lo_addr = LOWORD(shmaddr);
1651
1652 error = NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block));
1653
1654 if(NpDebug & DEBENTRY)
1655 printf("NpSetMemAddr...\n");
1656
1657 return(error);
1658}
1659
1660
1661/*
1662 * NpSetXeqAddr specifies the address at which the board should begin
1663 * execution of its on-board software. It also indicates the shared memory
1664 * address to be used. The board is specified by mp.
1665 */
1666
1667NpSetXeqAddr(mp,addr)
1668struct npmaster *mp;
1669caddr_t addr;
1670{
1671 caddr_t shmaddr;
1672 int error;
1673
1674 struct {
1675 unsign16 cmd_word;
1676 unsign16 hi_addr;
1677 unsign16 lo_addr;
1678 unsign16 mhi_addr;
1679 unsign16 mlo_addr;
1680 } cmd_block;
1681
1682 if(NpDebug & DEBENTRY)
1683 printf("NpSetXeqAddr\n");
1684
1685 shmaddr = (caddr_t)((int)mp->iomapbase & UBADDRMASK);
1686
1687 cmd_block.cmd_word = NPBGN | NPCMD | NPLST | (BGNCNT + CMDCNT);
1688 cmd_block.hi_addr = HIWORD(addr);
1689 cmd_block.lo_addr = LOWORD(addr);
1690 cmd_block.mhi_addr = HIWORD(shmaddr);
1691 cmd_block.mlo_addr = LOWORD(shmaddr);
1692
1693 if(NpDebug & DEBINIT) {
1694 printf("NpSetXeqAdddr: hi: %x lo: %x\n",HIWORD(addr), LOWORD(addr));
1695 printf("NpSetXeqAdddr: mhi: %x mlo: %x\n",HIWORD(shmaddr),LOWORD(shmaddr));
1696 }
1697
1698 error = NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block));
1699
1700 if(NpDebug & DEBENTRY)
1701 printf("NpSetXeqAddr...\n");
1702
1703 return(error);
1704}
1705
1706/*
1707 * NPIO issues a CSR0 load or dump request to the I-Board after packaging a
1708 * CSR0 Command Block.
1709 */
1710
1711NPIO(mp,src,dest,count,dir)
1712struct npmaster *mp;
1713paddr_t dest;
1714paddr_t src;
1715unsign16 count;
1716int dir; /* Direction READ/WRITE */
1717{
1718
1719 int error;
1720
1721 struct {
1722 unsign16 cmd_word; /* Command Word */
1723 unsign16 shi_addr; /* High word of Source Address */
1724 unsign16 slo_addr; /* Low word of Source Address */
1725 unsign16 dhi_addr; /* High word of Destination Address */
1726 unsign16 dlo_addr; /* Low word of Destination Address */
1727 unsign16 count; /* Byte count */
1728 unsign16 intlevel; /* Interrupt level to host */
1729 } cmd_block;
1730
1731 if(NpDebug & DEBENTRY)
1732 printf("NPIO\n");
1733 if(NpDebug & DEBMAINT) {
1734 printf("I/O src addr = %x, dest addr = %x \n",src,dest);
1735 printf("I/O count = %d \n",count);
1736 }
1737
ef9a9a2c 1738 cmd_block.cmd_word = NPCBI | (CBICNT + IOCNT);
0399a117
KS
1739 cmd_block.intlevel = mp->vector;
1740 cmd_block.shi_addr = HIWORD(src);
1741 cmd_block.slo_addr = LOWORD(src);
1742 cmd_block.dhi_addr = HIWORD(dest);
1743 cmd_block.dlo_addr = LOWORD(dest);
1744 cmd_block.count = count;
ef9a9a2c
MK
1745 if ((mp->flags & LSTCMD) == 0)
1746 cmd_block.cmd_word |= NPLST;
0399a117
KS
1747 if(dir == B_READ)
1748 cmd_block.cmd_word |= NPDMP;
1749 else
1750 cmd_block.cmd_word |= NPLD;
1751
1752
1753 if(NpDebug & DEBIO) {
1754 printf("cmd: %x int: %o shi: %x slo: %x dhi: %x dlo: %x cnt: %x\n",
1755 cmd_block.cmd_word,cmd_block.intlevel,cmd_block.shi_addr,cmd_block.slo_addr,
1756 cmd_block.dhi_addr,cmd_block.dlo_addr,cmd_block.count);
1757 }
1758
1759 mp->flags |= CSRPEND; /* CSR0 command pending */
1760
1761 error = NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block));
1762 if(NpDebug & DEBENTRY)
1763 printf("NPIO...\n");
1764
1765 return(error);
1766}
1767
1768
1769/*
1770 * NpKill will terminate all outstanding requests for the specified board.
1771 */
1772
1773NpKill(mp,curr_rp)
1774struct npmaster *mp;
1775struct npreq *curr_rp;
1776{
1777 struct npreq *rp;
1778 int s;
1779
1780 if(NpDebug & DEBENTRY)
1781 printf("NpKill\n");
1782
1783 mp->reqtab->reqcnt = 0; /* Init request count */
1784
1d5affa5 1785 s = spl5(); /* Disable interrupts */
0399a117
KS
1786
1787 /* Mark each active request as having an error and wake him up */
1788
1789 for(rp = mp->reqtab->forw;rp != mp->reqtab;rp = rp->forw) {
1790
1791 if(rp == curr_rp) continue;
1792
1793 rp->flags |= (IOABORT | REQDONE);
1794 mp->reqtab->reqcnt++;
ef9a9a2c 1795 /* if(rp->flags & NPUIO)
0399a117 1796 iodone(&rp->buf);
ef9a9a2c
MK
1797 else */
1798 wakeup((caddr_t)rp);
0399a117
KS
1799 }
1800
1801 if(NpDebug & DEBMAINT)
1802 printf("NpKill, req count is %d\n",mp->reqtab->reqcnt);
1803
1804 splx(s);
1805
1806 if(NpDebug & DEBENTRY)
1807 printf("NpKill...\n");
1808
1809 return(0);
1810
1811}
1812
1813/* Hardware and Software Initializations for the specified unit */
1814
1815NpReset(mp,rp)
1816register struct npmaster *mp;
1817struct npreq *rp;
1818{
1819 int error;
1820
1821 if(NpDebug & DEBENTRY)
1822 printf("NpReset!\n");
1823
1824 /* Mark board as being reset and make unavailable */
1825
1826 mp->flags = BRDRESET;
1827
1828 /* Abort outstanding requests for this board */
1829
1830 mp->reqtab->reqcnt = 0; /* Init request count */
1831
1832 /* Wakeup Poller if available and wait until he's gone */
1833
1834 if(NpState & ICPAVAIL) {
1835
1836 mp->flags |= BOARDREQ;
1837 mp->reqtab->reqcnt++;
1838
1839 if(NpDebug & DEBMAINT)
1840 printf("Waking ICP in reset!\n");
1841
1842 wakeup((caddr_t)&NpState);
1843
1844 while(mp->reqtab->reqcnt)
c376c8e7
MK
1845 if (error = tsleep((caddr_t)(&mp->reqtab),
1846 (PZERO + 1) | PCATCH, devio, 0))
1847 return (error);
0399a117
KS
1848
1849 if(NpDebug & DEBMAINT)
1850 printf("Reset:awoken by ICP senior!\n");
1851
1852 }
1853
1854 /* Abort outstanding requests and wait till they're gone */
1855
1856 NpKill(mp,rp);
1857
1858 while(mp->reqtab->reqcnt) {
1859
1860 if(NpDebug & DEBMAINT) {
1861 printf("Sleeping in NpReset on reqtab!\n");
1862 printf("Reqcnt is %d.\n",mp->reqtab->reqcnt);
1863 }
1864
c376c8e7
MK
1865 if (error = tsleep((caddr_t)(&mp->reqtab),
1866 (PZERO + 1) | PCATCH, devio, 0))
1867 return (error);
0399a117
KS
1868 }
1869
1870 /* Free up I/O Map registers if any allocated */
1871
1872 if(mp->iomapbase) {
1873
1874 if(NpDebug & DEBMEM)
1875 printf("freeing shared memory map.\n");
1876
1877 ubarelse(mp->devp->ui_ubanum,&mp->iomapbase);
1878 mp->iomapbase = 0;
1879 }
1880
1881 /* Initialize S/W data structures in NP Driver */
1882
1883 NpSWinit(mp->unit); /* Software initialization */
1884
1885 /* Hardware initialization of the board */
1886
1887 error = NpHWinit(mp->unit); /* Hardware initialization */
1888
1889 mp->flags &= ~BRDRESET; /* Initialization complete */
1890
1891 /* Initialize Pseudo-Drivers */
1892
0399a117
KS
1893 if (IxReset)
1894 (*IxReset)(mp->unit, mp->devp->ui_ubanum, rp);
1895
1896 /* Clear Poller's State Flag */
1897
1898 NpState = NPCLEAR;
1899
1900 if(NpDebug & DEBENTRY)
1901 printf("NpReset...\n");
1902
1903 return(error);
1904}
1905
1906/*
1907 * General purpose timeout function which sets the flag passed to it
1908 * as argument.
1909 */
1910
1911NpTimer(flagp)
1912int *flagp;
1913{
1914 *flagp = NPSET;
1915}
1916
1917NpStats()
1918{
1919 if(NpDebug & DEBENTRY)
1920 printf("npstats\n");
1921 return(0);
1922}
1923
1924/*
1925 * NpCloseConn is called to issue a close connection command to the I-Board.
1926 */
1927
1928NpCloseConn(mp,protocol)
1929struct npmaster *mp;
1930unsign16 protocol;
1931{
1932
1933 register struct npreq *rp;
1934 register struct CQE *ep;
1935 int pri;
1936
1937 if(NpDebug & DEBENTRY)
1938 printf("NpCloseConn\n");
1939
1940 /*
1941 * Don't issue the Close Connection command if the Board
1942 * isn't up.
1943 */
1944
1945 if(!((mp->shmemp->statblock.sb_dpm) & PROTOMASK(protocol))) {
1946 return;
1947 }
1948
1949 /* Get a Request structure */
1950
1951 while((rp = NpGetReq(mp->reqtab)) == NULL) {
1952 mp->reqtab->flags |= WANTREQ;
1953 sleep((caddr_t)(mp->reqtab),PZERO -1);
1954 }
1955
1956 rp->intr = (int (*)())0; /* Do not call interrupt routine */
0399a117
KS
1957 rp->mapbase = 0; /* Clear mapping information */
1958
1959 ep = rp->element; /* Handy pointer */
1960
1961 /* Fill in CQE */
1962
1963 ep->cqe_wind = 0; /* Entire buffer mapped */
1964 ep->cqe_nbuf = 1; /* Must be 1, no buffer chaining */
1965 ep->cqe_char = 0; /* Set to 0 for now */
1966
1967 ep->cqe_func = NPSTOP; /* OS_STP to I-Board */
1968
1969 ep->cqe_prot = protocol; /* Protocol of this connection */
1970 ep->cqe_lenrpb = 0; /* Parameter block length */
1971
1972 ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR; /* Clear status flags */
1973
1974 ep->cqe_famid = (unsign32)u.u_procp->p_pid; /* Process ID */
1975
1976 NpAddReq(mp->reqtab,rp); /* Queue onto active list */
1977
1d5affa5 1978 pri = spl5(); /* Mask our interrupts */
0399a117
KS
1979
1980 NpAddCQE(ep,&mp->shmemp->devcq,mp); /* Add CQE to device's queue */
1981
1982 /* Wait for command to complete */
1983
1984 while(!(rp->flags & REQDONE))
1985 sleep((caddr_t)rp,PZERO - 1);
1986
1987 splx(pri);
1988
1989 NpRemReq(rp); /* Remove request from active list */
1990
1991 NpFreeReq(mp->reqtab,rp); /* Deallocate request structure */
1992
1993 if(NpDebug & DEBENTRY)
1994 printf("NpCloseConn...\n");
1995
1996}
1997
1998/*
1999 * This function allows the protocol to be changed for a given connection.
2000 * It returns 0 for success, error code otherwise.
2001 */
2002
2003NpProtChange(protocol,unit)
2004register unsign16 protocol;
2005register int unit;
2006{
2007
2008 register struct npmaster *mp;
2009
2010 /* Privileged users only for Maintenance Protocol */
2011
2012 if((protocol == NPMAINT) && (u.u_uid != 0))
2013 return(EPERM);
2014
2015 if(NpDebug & DEBMAINT)
2016 printf("NpProtChange = %x\n",protocol);
2017
2018 if(protocol != NPMAINT) {
2019
2020 /* Make sure the I-Board supports the protocol */
2021
2022 mp = &npmasters[unit];
2023
2024 if(!((mp->shmemp->statblock.sb_dpm) & PROTOMASK(protocol)))
2025 return(ENXIO);
2026 }
2027
2028 return(0);
2029}
2030
2031/*
2032 * This function allows for the changing of the unit for a given connection.
2033 */
2034
2035struct npmaster *
2036NpBoardChange(protocol,unit)
2037register unsign16 protocol;
2038register int unit; /* Unit number */
2039{
2040 register struct npmaster *mp;
2041
2042
2043 if(unit > NNP)
2044 return((struct npmaster *)0);
2045
2046 if(protocol != NPMAINT) {
2047
2048 /*
2049 * Loop through the master structures finding a board which
2050 * supports the requested protocol.
2051 */
2052
2053 for(mp = npmasters; mp ; mp = mp->next) {
2054
2055 if(mp->flags & BADBOARD)
2056 continue;
2057
2058 if(((mp->shmemp->statblock.sb_dpm) & PROTOMASK(protocol)))
2059 return(mp);
2060 }
2061 return((struct npmaster *)0);
2062 }
2063 return(&npmasters[unit]);
2064}
2065
2066/*
2067 * NpMapMem - maps the user's memory updating the fields in the npreq
2068 * structure and returning the mapped address in rp->buffaddr.
2069 */
2070NpMapMem(mp,rp,addr,count)
2071register struct npmaster *mp;
2072register struct npreq *rp;
2073caddr_t addr;
2074int count;
2075{
2076
2077 if(NpDebug & DEBENTRY)
2078 printf("NpMapMem\n");
2079 if(NpDebug & DEBIO)
2080 printf("mp %x rp %x addr %x count %x\n",mp,rp,addr,count);
2081
2082 rp->virtmem = addr;
2083 rp->bytecnt = count;
2084
2085 rp->buf.b_un.b_addr = addr;
2086 rp->buf.b_flags = B_PHYS | B_BUSY;
2087 rp->buf.b_bcount = count;
2088 rp->buf.b_proc = rp->procp;
2089
2090 rp->procp->p_flag |= SPHYSIO;
ef9a9a2c
MK
2091 if(NpDebug & DEBENTRY)
2092 printf("vslock\n");
0399a117 2093 vslock(addr,count);
ef9a9a2c
MK
2094 if(NpDebug & DEBENTRY)
2095 printf("vslock...\n");
0399a117
KS
2096
2097 rp->mapbase = ubasetup(mp->devp->ui_ubanum,&rp->buf,0);
2098
2099 rp->bufaddr = (caddr_t)(rp->mapbase & UBADDRMASK);
2100
2101 if(NpDebug & DEBENTRY)
2102 printf("NpMapMem...\n");
2103}
2104
2105/*
2106 * Unmap the user's memory and free up mapping registers
2107 */
2108
2109NpUnMapMem(mp,rp)
2110struct npmaster *mp;
2111struct npreq *rp;
2112{
2113 if(NpDebug & DEBENTRY)
2114 printf("NpUnMapMem\n");
2115
2116 ubarelse(mp->devp->ui_ubanum,&rp->mapbase);
2117 rp->mapbase = 0;
2118 vsunlock(rp->virtmem,rp->bytecnt,B_READ);
2119 rp->procp->p_flag &= ~SPHYSIO;
2120
2121 if(NpDebug & DEBENTRY)
2122 printf("NpUnMapMem...\n");
2123}
2124
2125npprobe(reg, ui)
2126caddr_t reg;
2127struct uba_device *ui;
2128{
2129register int br,cvec;
2130u_short csraddr;
2131int i;
2132
2133#ifdef lint
2134 br = 0; cvec = br; br = cvec;
2135#endif
2136
2137 if(NpDebug & DEBINIT)
2138 printf("In npprobe, regaddr is %x!\n",reg);
2139
2140 cvec = (uba_hd[numuba].uh_lastiv -= 4);
2141
ef9a9a2c 2142#ifdef OLDBSD
0399a117
KS
2143 /* Find unit number from npstd[] by matching the csr address */
2144
2145 csraddr = (u_short)((int)reg & 0x0FFFF);
2146
2147 for(i = 0; i < NNP; i++) {
2148
2149 if(csraddr == npstd[i]) {
2150 npvectors[i] = cvec;
2151 break;
2152 }
2153 }
2154 if(i == NNP)
2155 printf("Couldn't find device in npstd[]!\n");
ef9a9a2c 2156
0399a117
KS
2157#else
2158 npvectors[ui->ui_unit] = cvec;
2159#endif
2160 br = 0x15;
2161
2162 if(NpDebug & DEBINIT)
2163 printf("npprobe...\n");
2164
2165 return(sizeof(struct NPREG)); /* CSR Registers */
2166
2167}
2168
2169npattach(ui)
2170register struct uba_device *ui;
2171{
2172
2173 if(NpDebug & DEBINIT)
2174 printf("In npattach, ui is %x.\n",ui);
2175
2176 npinit(ui->ui_unit);
0399a117
KS
2177 if (IxAttach)
2178 (*IxAttach)(ui);
2179
2180 if(NpDebug & DEBINIT)
2181 printf("npattach...\n");
2182}
2183
ef9a9a2c
MK
2184
2185NpMem(mp, rp, uaddr)
2186struct npmaster *mp;
2187struct npreq *rp;
2188unsigned long uaddr;
2189{
2190 struct np_mem mem;
2191 register int error = 0;
2192
2193 if(NpDebug & DEBENTRY)
2194 printf("npmem\n");
2195
2196 if (error = copyin(uaddr, &mem, sizeof(mem)))
2197 return (error);
2198
2199 if (mem.mem_type == NP_SET) {
2200 if (np_mapreq[mp->unit] != (struct npreq *)NPCLEAR)
2201 error = EBUSY;
2202 else {
2203 error = NpMapMem(mp, rp, mem.mem_addr, mem.mem_count);
2204 if (error != 0) {
2205 np_mapreq[mp->unit] = rp;
2206 mem.mem_addr = rp->bufaddr;
2207 }
2208 }
2209 } else if (mem.mem_type == NP_USET) {
2210 error = NpUnMapMem(mp, np_mapreq[mp->unit]);
2211 NpFreeReq(mp->reqtab, rp);
2212 NpFreeReq(mp->reqtab, np_mapreq[mp->unit]);
2213 np_mapreq[mp->unit] = (struct npreq *)NPCLEAR;
2214 } else
2215 error = EIO;
2216
2217 if (error != 0)
2218 error = copyout(&mem, uaddr, sizeof(mem));
2219
2220 if(NpDebug & DEBENTRY)
2221 printf("npmem...\n");
2222 return (error);
2223}
0399a117 2224#endif