1*6964Ssam /* uda.c 4.5 82/05/27 */ 24743Swnj 34743Swnj #include "ra.h" 44743Swnj #if NUDA > 0 54743Swnj /* 64743Swnj * UDA50/RAxx disk device driver 74743Swnj * 84743Swnj * Restrictions: 94743Swnj * Unit numbers must be less than 8. 104743Swnj * 114743Swnj * TO DO: 124743Swnj * write dump code 134743Swnj * test on 750 144743Swnj */ 154743Swnj 164743Swnj #include "../h/param.h" 174743Swnj #include "../h/systm.h" 184743Swnj #include "../h/buf.h" 194743Swnj #include "../h/conf.h" 204743Swnj #include "../h/dir.h" 214743Swnj #include "../h/user.h" 224743Swnj #include "../h/pte.h" 234743Swnj #include "../h/map.h" 244743Swnj #include "../h/vm.h" 254743Swnj #include "../h/ubareg.h" 264743Swnj #include "../h/ubavar.h" 274743Swnj #include "../h/dk.h" 284743Swnj #include "../h/cpu.h" 294743Swnj #include "../h/cmap.h" 304743Swnj 314743Swnj int udadebug; 324743Swnj #define printd if(udadebug&1)printf 334743Swnj 34*6964Ssam int udaerror = 0; /* set to cause hex dump of error log packets */ 35*6964Ssam 364743Swnj /* 374743Swnj * Parameters for the communications area 384743Swnj */ 394743Swnj 40*6964Ssam #define NRSPL2 3 /* log2 number of response packets */ 41*6964Ssam #define NCMDL2 3 /* log2 number of command packets */ 424743Swnj #define NRSP (1<<NRSPL2) 434743Swnj #define NCMD (1<<NCMDL2) 444743Swnj 454743Swnj #include "../h/udareg.h" 464743Swnj #include "../h/mscp.h" 474743Swnj 484743Swnj struct uda_softc { 494743Swnj short sc_state; /* state of controller */ 504743Swnj short sc_mapped; /* Unibus map allocated for uda struct? */ 514743Swnj int sc_ubainfo; /* Unibus mapping info */ 524743Swnj struct uda *sc_uda; /* Unibus address of uda struct */ 534743Swnj int sc_ivec; /* interrupt vector address */ 544743Swnj short sc_credits; /* transfer credits */ 554743Swnj short sc_lastcmd; /* pointer into command ring */ 564743Swnj short sc_lastrsp; /* pointer into response ring */ 574743Swnj } uda_softc[NUDA]; 584743Swnj 594743Swnj /* 604743Swnj * Controller states 614743Swnj */ 624743Swnj #define S_IDLE 0 /* hasn't been initialized */ 634743Swnj #define S_STEP1 1 /* doing step 1 init */ 644743Swnj #define S_STEP2 2 /* doing step 2 init */ 654743Swnj #define S_STEP3 3 /* doing step 3 init */ 664743Swnj #define S_SCHAR 4 /* doing "set controller characteristics" */ 674743Swnj #define S_RUN 5 /* running */ 684743Swnj 694743Swnj struct uda { 704743Swnj struct udaca uda_ca; /* communications area */ 714743Swnj struct mscp uda_rsp[NRSP]; /* response packets */ 724743Swnj struct mscp uda_cmd[NCMD]; /* command packets */ 734743Swnj } uda[NUDA]; 744743Swnj 754743Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 764743Swnj struct size { 774743Swnj daddr_t nblocks; 784743Swnj daddr_t blkoff; 794743Swnj } ra_sizes[8] ={ 804743Swnj 15884, 0, /* A=blk 0 thru 15883 */ 814743Swnj 33440, 15884, /* B=blk 15884 thru 49323 */ 824743Swnj -1, 0, /* C=blk 0 thru end */ 83*6964Ssam 15884, 340670, /* D=blk 340670 thru 356553 */ 84*6964Ssam 55936, 356554, /* E=blk 356554 thru 412489 */ 85*6964Ssam -1, 412490, /* F=blk 412490 thru end */ 864743Swnj 82080, 49324, /* G=blk 49324 thru 131403 */ 874743Swnj -1, 131404, /* H=blk 131404 thru end */ 884743Swnj }; 894743Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 904743Swnj 914743Swnj daddr_t radsize[NRA]; /* disk size, from ONLINE end packet */ 924743Swnj 934743Swnj int udprobe(), udslave(), udattach(), udintr(); 944743Swnj struct mscp *udgetcp(); 954743Swnj struct uba_ctlr *udminfo[NUDA]; 964743Swnj struct uba_device *uddinfo[NRA]; 974743Swnj struct uba_device *udip[NUDA][8]; /* 8 == max number of drives */ 984743Swnj 99*6964Ssam u_short udstd[] = { 0772150, 0 }; 1004743Swnj struct uba_driver udadriver = 1014743Swnj { udprobe, udslave, udattach, 0, udstd, "ra", uddinfo, "uda", udminfo, 0 }; 1024743Swnj struct buf rudbuf[NRA]; 1034743Swnj struct buf udutab[NRA]; 1044743Swnj struct buf udwtab[NUDA]; /* I/O wait queue, per controller */ 1054743Swnj 1064743Swnj #define b_qsize b_resid /* queue size per drive, in udutab */ 1074743Swnj #define b_ubinfo b_resid /* Unibus mapping info, per buffer */ 1084743Swnj 1094743Swnj udprobe(reg, ctlr) 1104743Swnj caddr_t reg; 1114743Swnj int ctlr; 1124743Swnj { 1134743Swnj register int br, cvec; 1144743Swnj register struct uda_softc *sc = &uda_softc[ctlr]; 1154743Swnj 1164743Swnj #ifdef lint 1176187Ssam br = 0; cvec = br; br = cvec; reg = reg; 1186187Ssam udread(0); udwrite(0); udreset(0); udintr(0); 1194743Swnj #endif 1204743Swnj /* SHOULD CHECK THAT IT REALLY IS A UDA */ 1214743Swnj br = 0x15; 1224743Swnj cvec = sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); 1234743Swnj return(1); 1244743Swnj } 1254743Swnj 1264743Swnj udslave(ui, reg) 1274743Swnj struct uba_device *ui; 1284743Swnj caddr_t reg; 1294743Swnj { 1304743Swnj /* 1314743Swnj * TOO HARD TO FIND OUT IF DISK IS THERE UNTIL 1324743Swnj * INITIALIZED. WE'LL FIND OUT WHEN WE FIRST 1334743Swnj * TRY TO ACCESS IT. 1344743Swnj */ 1356187Ssam #ifdef lint 1366187Ssam ui = ui; reg = reg; 1376187Ssam #endif 1384743Swnj return(1); 1394743Swnj } 1404743Swnj 1414743Swnj udattach(ui) 1424743Swnj register struct uba_device *ui; 1434743Swnj { 1444743Swnj 1454743Swnj if (ui->ui_dk > 0) 1464743Swnj dk_mspw[ui->ui_dk] = 1.0 / (60 * 31 * 256); /* approx */ 1474743Swnj ui->ui_flags = 0; 1484743Swnj udip[ui->ui_ctlr][ui->ui_slave] = ui; 1494743Swnj radsize[ui->ui_unit] = (daddr_t)0xffffff; /* max possible size */ 1504743Swnj } 1514743Swnj 1524743Swnj /* 1534743Swnj * Open a UDA. Initialize the device and 1544743Swnj * set the unit online. 1554743Swnj */ 1564743Swnj udopen(dev, flag) 1574743Swnj dev_t dev; 1584743Swnj int flag; 1594743Swnj { 1604743Swnj register int unit; 1614743Swnj register struct uba_device *ui; 1624743Swnj register struct uda_softc *sc; 1635434Sroot int s; 1644743Swnj 1656187Ssam #ifdef lint 1666187Ssam flag = flag; 1676187Ssam #endif 1684743Swnj unit = minor(dev) >> 3; 1694743Swnj if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0) { 1704743Swnj u.u_error = ENXIO; 1714743Swnj return; 1724743Swnj } 1734743Swnj sc = &uda_softc[ui->ui_ctlr]; 1745434Sroot s = spl5(); 1754743Swnj if (sc->sc_state != S_RUN) { 1764743Swnj if (sc->sc_state == S_IDLE) 1774743Swnj udinit(ui->ui_ctlr); 1786187Ssam /* wait for initialization to complete */ 1796187Ssam sleep((caddr_t)ui->ui_mi, 0); 1804743Swnj if (sc->sc_state != S_RUN) { 1814743Swnj u.u_error = EIO; 1824743Swnj return; 1834743Swnj } 1844743Swnj } 1855434Sroot splx(s); 1864743Swnj /* SHOULD PROBABLY FORCE AN ONLINE ATTEMPT 1874743Swnj TO SEE IF DISK IS REALLY THERE */ 1884743Swnj } 1894743Swnj 1904743Swnj /* 1914743Swnj * Initialize a UDA. Set up UBA mapping registers, 1924743Swnj * initialize data structures, and start hardware 1934743Swnj * initialization sequence. 1944743Swnj */ 1954743Swnj udinit(d) 1964743Swnj int d; 1974743Swnj { 1984743Swnj register struct uda_softc *sc; 1994743Swnj register struct uda *ud; 2004743Swnj struct udadevice *udaddr; 2014743Swnj struct uba_ctlr *um; 2024743Swnj 2034743Swnj sc = &uda_softc[d]; 2044743Swnj um = udminfo[d]; 2054743Swnj um->um_tab.b_active++; 2064743Swnj ud = &uda[d]; 2074743Swnj udaddr = (struct udadevice *)um->um_addr; 2084743Swnj if (sc->sc_mapped == 0) { 2094743Swnj /* 2104743Swnj * Map the communications area and command 2114743Swnj * and response packets into Unibus address 2124743Swnj * space. 2134743Swnj */ 2144743Swnj sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)ud, 2154743Swnj sizeof (struct uda), 0); 2164743Swnj sc->sc_uda = (struct uda *)(sc->sc_ubainfo & 0x3ffff); 2174743Swnj sc->sc_mapped = 1; 2184743Swnj } 2194743Swnj 2204743Swnj /* 2214743Swnj * Start the hardware initialization sequence. 2224743Swnj */ 2234743Swnj udaddr->udaip = 0; /* start initialization */ 2244743Swnj while ((udaddr->udasa & UDA_STEP1) == 0) 2254743Swnj ; 2264743Swnj udaddr->udasa = UDA_ERR|(NCMDL2<<11)|(NRSPL2<<8)|UDA_IE|(sc->sc_ivec/4); 2274743Swnj /* 2284743Swnj * Initialization continues in interrupt routine. 2294743Swnj */ 2304743Swnj sc->sc_state = S_STEP1; 2314743Swnj sc->sc_credits = 0; 2324743Swnj } 2334743Swnj 2344743Swnj udstrategy(bp) 2354743Swnj register struct buf *bp; 2364743Swnj { 2374743Swnj register struct uba_device *ui; 2384743Swnj register struct uba_ctlr *um; 2394743Swnj register struct buf *dp; 2404743Swnj register int unit; 2414743Swnj int xunit = minor(bp->b_dev) & 07; 2424743Swnj daddr_t sz, maxsz; 2435434Sroot int s; 2444743Swnj 2454743Swnj sz = (bp->b_bcount+511) >> 9; 2464743Swnj unit = dkunit(bp); 2474743Swnj if (unit >= NRA) 2484743Swnj goto bad; 2494743Swnj ui = uddinfo[unit]; 2504743Swnj um = ui->ui_mi; 2514743Swnj if (ui == 0 || ui->ui_alive == 0) 2524743Swnj goto bad; 2534743Swnj if ((maxsz = ra_sizes[xunit].nblocks) < 0) 2544743Swnj maxsz = radsize[unit] - ra_sizes[xunit].blkoff; 2554743Swnj if (bp->b_blkno < 0 || bp->b_blkno+sz > maxsz || 2564743Swnj ra_sizes[xunit].blkoff >= radsize[unit]) 2574743Swnj goto bad; 2585434Sroot s = spl5(); 2594743Swnj /* 2604743Swnj * Link the buffer onto the drive queue 2614743Swnj */ 2624743Swnj dp = &udutab[ui->ui_unit]; 2634743Swnj if (dp->b_actf == 0) 2644743Swnj dp->b_actf = bp; 2654743Swnj else 2664743Swnj dp->b_actl->av_forw = bp; 2674743Swnj dp->b_actl = bp; 2684743Swnj bp->av_forw = 0; 2694743Swnj /* 2704743Swnj * Link the drive onto the controller queue 2714743Swnj */ 2724743Swnj if (dp->b_active == 0) { 2734743Swnj dp->b_forw = NULL; 2744743Swnj if (um->um_tab.b_actf == NULL) 2754743Swnj um->um_tab.b_actf = dp; 2764743Swnj else 2774743Swnj um->um_tab.b_actl->b_forw = dp; 2784743Swnj um->um_tab.b_actl = dp; 2794743Swnj dp->b_active = 1; 2804743Swnj } 2814743Swnj if (um->um_tab.b_active == 0) { 2824743Swnj #if defined(VAX750) 2834743Swnj if (cpu == VAX_750) { 2844743Swnj if (um->um_ubinfo != 0) 2854743Swnj printf("uda: ubinfo %x\n",um->um_ubinfo); 2864743Swnj else 2874743Swnj um->um_ubinfo = 2886187Ssam uballoc(um->um_ubanum, (caddr_t)0, 0, 2896187Ssam UBA_NEEDBDP); 2904743Swnj } 2914743Swnj #endif 2924743Swnj (void) udstart(um); 2934743Swnj } 2945434Sroot splx(s); 2954743Swnj return; 2964743Swnj 2974743Swnj bad: 2984743Swnj bp->b_flags |= B_ERROR; 2994743Swnj iodone(bp); 3004743Swnj return; 3014743Swnj } 3024743Swnj 3034743Swnj udstart(um) 3044743Swnj register struct uba_ctlr *um; 3054743Swnj { 3064743Swnj register struct buf *bp, *dp; 3074743Swnj register struct mscp *mp; 3084743Swnj register struct uda_softc *sc; 3094743Swnj register struct uba_device *ui; 3104743Swnj struct udadevice *udaddr; 3114743Swnj int i; 3124743Swnj 3134743Swnj sc = &uda_softc[um->um_ctlr]; 3144743Swnj 3154743Swnj loop: 3164743Swnj if ((dp = um->um_tab.b_actf) == NULL) { 3174743Swnj /* 3184743Swnj * Release uneeded UBA resources and return 3194743Swnj */ 3204743Swnj um->um_tab.b_active = 0; 3214743Swnj #if defined(VAX750) 3224743Swnj if (cpu == VAX_750) { 3234743Swnj if (um->um_ubinfo == 0) 3244743Swnj printf("uda: um_ubinfo == 0\n"); 3254743Swnj else 3264743Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 3274743Swnj } 3284743Swnj #endif 3296187Ssam return (0); 3304743Swnj } 3314743Swnj if ((bp = dp->b_actf) == NULL) { 3324743Swnj /* 3334743Swnj * No more requests for this drive, remove 3344743Swnj * from controller queue and look at next drive. 3354743Swnj * We know we're at the head of the controller queue. 3364743Swnj */ 3374743Swnj dp->b_active = 0; 3384743Swnj um->um_tab.b_actf = dp->b_forw; 3394743Swnj goto loop; 3404743Swnj } 3414743Swnj um->um_tab.b_active++; 3424743Swnj udaddr = (struct udadevice *)um->um_addr; 3434743Swnj if ((udaddr->udasa&UDA_ERR) || sc->sc_state != S_RUN) { 3444743Swnj harderr(bp, "ra"); 3454743Swnj printf("udasa %o, state %d\n", udaddr->udasa&0xffff, sc->sc_state); 3464743Swnj udinit(um->um_ctlr); 3474743Swnj /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE UDRESET */ 3486187Ssam return (0); 3494743Swnj } 3504743Swnj ui = uddinfo[dkunit(bp)]; 3514743Swnj /* 3524743Swnj * If no credits, can't issue any commands 3534743Swnj * until some outstanding commands complete. 3544743Swnj */ 3554743Swnj if (sc->sc_credits < 2) 3566187Ssam return (0); 3574743Swnj if ((mp = udgetcp(um)) == NULL) 3586187Ssam return (0); 3594743Swnj sc->sc_credits--; /* committed to issuing a command */ 3604743Swnj if (ui->ui_flags == 0) { /* not online */ 3614743Swnj mp->mscp_opcode = M_OP_ONLIN; 3624743Swnj mp->mscp_unit = ui->ui_slave; 3634743Swnj dp->b_active = 2; 3644743Swnj um->um_tab.b_actf = dp->b_forw; /* remove from controller q */ 3654743Swnj printd("uda: bring unit %d online\n", ui->ui_slave); 3664743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 3674743Swnj i = udaddr->udaip; 3684743Swnj goto loop; 3694743Swnj } 3704743Swnj switch (cpu) { 3714743Swnj case VAX_780: 3724743Swnj i = UBA_NEEDBDP|UBA_CANTWAIT; 3734743Swnj break; 3744743Swnj 3754743Swnj case VAX_750: 3764743Swnj i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT; 3774743Swnj break; 3784743Swnj 3796949Ssam case VAX_730: 3804743Swnj i = UBA_CANTWAIT; 3814743Swnj break; 3824743Swnj } 3834743Swnj if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) { 3844743Swnj mp->mscp_opcode = M_OP_GTUNT; 3854743Swnj mp->mscp_unit = ui->ui_slave; 3864743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 3874743Swnj i = udaddr->udaip; /* initiate polling */ 3884743Swnj return(1); /* wait for interrupt */ 3894743Swnj } 3904743Swnj mp->mscp_cmdref = (long)bp; /* pointer to get back */ 3914743Swnj mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE; 3924743Swnj mp->mscp_unit = ui->ui_slave; 3934743Swnj mp->mscp_lbn = bp->b_blkno + ra_sizes[minor(bp->b_dev)&7].blkoff; 3944743Swnj mp->mscp_bytecnt = bp->b_bcount; 3954743Swnj mp->mscp_buffer = (i & 0x3ffff) | (((i>>28)&0xf)<<24); 3964743Swnj #if defined(VAX750) 3974743Swnj if (cpu == VAX_750) 3984743Swnj i &= 0xfffffff; /* mask off bdp */ 3994743Swnj #endif 4004743Swnj bp->b_ubinfo = i; /* save mapping info */ 4014743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 4024743Swnj i = udaddr->udaip; /* initiate polling */ 4034743Swnj if (ui->ui_dk >= 0) { 4044743Swnj dk_busy |= 1<<ui->ui_dk; 4054743Swnj dp->b_qsize++; 4064743Swnj dk_xfer[ui->ui_dk]++; 4074743Swnj dk_wds[ui->ui_dk] += bp->b_bcount>>6; 4084743Swnj } 4094743Swnj 4104743Swnj /* 4114743Swnj * Move drive to the end of the controller queue 4124743Swnj */ 4134743Swnj if (dp->b_forw != NULL) { 4144743Swnj um->um_tab.b_actf = dp->b_forw; 4154743Swnj um->um_tab.b_actl->b_forw = dp; 4164743Swnj um->um_tab.b_actl = dp; 4174743Swnj dp->b_forw = NULL; 4184743Swnj } 4194743Swnj /* 4204743Swnj * Move buffer to I/O wait queue 4214743Swnj */ 4224743Swnj dp->b_actf = bp->av_forw; 4234743Swnj dp = &udwtab[um->um_ctlr]; 4244743Swnj bp->av_forw = dp; 4254743Swnj bp->av_back = dp->av_back; 4264743Swnj dp->av_back->av_forw = bp; 4274743Swnj dp->av_back = bp; 4284743Swnj goto loop; 4294743Swnj } 4304743Swnj 4314743Swnj /* 4324743Swnj * UDA interrupt routine. 4334743Swnj */ 4344743Swnj udintr(d) 4354743Swnj int d; 4364743Swnj { 4374743Swnj register struct uba_ctlr *um = udminfo[d]; 4384743Swnj register struct udadevice *udaddr = (struct udadevice *)um->um_addr; 4394743Swnj struct buf *bp; 4404743Swnj register int i; 4414743Swnj register struct uda_softc *sc = &uda_softc[d]; 4424743Swnj register struct uda *ud = &uda[d]; 4434743Swnj struct uda *uud; 4444743Swnj struct mscp *mp; 4454743Swnj 4464743Swnj printd("udintr: state %d, udasa %o\n", sc->sc_state, udaddr->udasa); 4474743Swnj switch (sc->sc_state) { 4484743Swnj case S_IDLE: 4494743Swnj printf("uda%d: random interrupt ignored\n", d); 4504743Swnj return; 4514743Swnj 4524743Swnj case S_STEP1: 453*6964Ssam #define STEP1MASK 0174377 4544743Swnj #define STEP1GOOD (UDA_STEP2|UDA_IE|(NCMDL2<<3)|NRSPL2) 455*6964Ssam if ((udaddr->udasa&STEP1MASK) != STEP1GOOD) { 4564743Swnj sc->sc_state = S_IDLE; 4576187Ssam wakeup((caddr_t)um); 4584743Swnj return; 4594743Swnj } 4604743Swnj udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)| 4614743Swnj (cpu == VAX_780 ? UDA_PI : 0); 4624743Swnj sc->sc_state = S_STEP2; 4634743Swnj return; 4644743Swnj 4654743Swnj case S_STEP2: 466*6964Ssam #define STEP2MASK 0174377 4674743Swnj #define STEP2GOOD (UDA_STEP3|UDA_IE|(sc->sc_ivec/4)) 468*6964Ssam if ((udaddr->udasa&STEP2MASK) != STEP2GOOD) { 4694743Swnj sc->sc_state = S_IDLE; 4706187Ssam wakeup((caddr_t)um); 4714743Swnj return; 4724743Swnj } 4734743Swnj udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)>>16; 4744743Swnj sc->sc_state = S_STEP3; 4754743Swnj return; 4764743Swnj 4774743Swnj case S_STEP3: 478*6964Ssam #define STEP3MASK 0174000 4794743Swnj #define STEP3GOOD UDA_STEP4 480*6964Ssam if ((udaddr->udasa&STEP3MASK) != STEP3GOOD) { 4814743Swnj sc->sc_state = S_IDLE; 4826187Ssam wakeup((caddr_t)um); 4834743Swnj return; 4844743Swnj } 4854743Swnj udaddr->udasa = UDA_GO; 4864743Swnj sc->sc_state = S_SCHAR; 4874743Swnj 4884743Swnj /* 4894743Swnj * Initialize the data structures. 4904743Swnj */ 4914743Swnj uud = sc->sc_uda; 4924743Swnj for (i = 0; i < NRSP; i++) { 4934743Swnj ud->uda_ca.ca_rspdsc[i] = UDA_OWN|UDA_INT| 4944743Swnj (long)&uud->uda_rsp[i].mscp_cmdref; 4954743Swnj ud->uda_rsp[i].mscp_dscptr = &ud->uda_ca.ca_rspdsc[i]; 4964743Swnj ud->uda_rsp[i].mscp_header.uda_msglen = sizeof (struct mscp); 4974743Swnj } 4984743Swnj for (i = 0; i < NCMD; i++) { 4994743Swnj ud->uda_ca.ca_cmddsc[i] = UDA_INT| 5004743Swnj (long)&uud->uda_cmd[i].mscp_cmdref; 5014743Swnj ud->uda_cmd[i].mscp_dscptr = &ud->uda_ca.ca_cmddsc[i]; 5024743Swnj ud->uda_cmd[i].mscp_header.uda_msglen = sizeof (struct mscp); 5034743Swnj } 5044743Swnj bp = &udwtab[d]; 5054743Swnj bp->av_forw = bp->av_back = bp; 5064743Swnj sc->sc_lastcmd = 0; 5074743Swnj sc->sc_lastrsp = 0; 5084743Swnj if ((mp = udgetcp(um)) == NULL) { 5094743Swnj sc->sc_state = S_IDLE; 5106187Ssam wakeup((caddr_t)um); 5114743Swnj return; 5124743Swnj } 5134743Swnj mp->mscp_opcode = M_OP_STCON; 5144743Swnj mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS; 5154743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 5164743Swnj i = udaddr->udaip; /* initiate polling */ 5174743Swnj return; 5184743Swnj 5194743Swnj case S_SCHAR: 5204743Swnj case S_RUN: 5214743Swnj break; 5224743Swnj 5234743Swnj default: 5244743Swnj printf("uda%d: interrupt in unknown state %d ignored\n", 5254743Swnj d, sc->sc_state); 5264743Swnj return; 5274743Swnj } 5284743Swnj 5294743Swnj if (udaddr->udasa&UDA_ERR) { 5304743Swnj printf("uda%d: fatal error (%o)\n", d, udaddr->udasa&0xffff); 5314743Swnj udaddr->udaip = 0; 5326187Ssam wakeup((caddr_t)um); 5334743Swnj } 5344743Swnj 5354743Swnj /* 5364743Swnj * Check for a buffer purge request. 5374743Swnj */ 5384743Swnj if (ud->uda_ca.ca_bdp) { 5394743Swnj /* 5404743Swnj * THIS IS A KLUDGE. 5414743Swnj * Maybe we should change the entire 5424743Swnj * UBA interface structure. 5434743Swnj */ 5444743Swnj int s = spl7(); 5454743Swnj 5464743Swnj i = um->um_ubinfo; 5474743Swnj printd("uda: purge bdp %d\n", ud->uda_ca.ca_bdp); 5484743Swnj um->um_ubinfo = ud->uda_ca.ca_bdp<<28; 5494743Swnj ubapurge(um); 5504743Swnj um->um_ubinfo = i; 5514743Swnj (void) splx(s); 5524743Swnj ud->uda_ca.ca_bdp = 0; 5534743Swnj udaddr->udasa = 0; /* signal purge complete */ 5544743Swnj } 5554743Swnj 5564743Swnj /* 5574743Swnj * Check for response ring transition. 5584743Swnj */ 5594743Swnj if (ud->uda_ca.ca_rspint) { 5604743Swnj ud->uda_ca.ca_rspint = 0; 5614743Swnj for (i = sc->sc_lastrsp;; i++) { 5624743Swnj i %= NRSP; 5634743Swnj if (ud->uda_ca.ca_rspdsc[i]&UDA_OWN) 5644743Swnj break; 5654743Swnj udrsp(um, ud, sc, i); 5664743Swnj ud->uda_ca.ca_rspdsc[i] |= UDA_OWN; 5674743Swnj } 5684743Swnj sc->sc_lastrsp = i; 5694743Swnj } 5704743Swnj 5714743Swnj /* 5724743Swnj * Check for command ring transition. 5734743Swnj */ 5744743Swnj if (ud->uda_ca.ca_cmdint) { 5754743Swnj printd("uda: command ring transition\n"); 5764743Swnj ud->uda_ca.ca_cmdint = 0; 5774743Swnj } 5786187Ssam (void) udstart(um); 5794743Swnj } 5804743Swnj 5814743Swnj /* 5824743Swnj * Process a response packet 5834743Swnj */ 5844743Swnj udrsp(um, ud, sc, i) 5854743Swnj register struct uba_ctlr *um; 5864743Swnj register struct uda *ud; 5874743Swnj register struct uda_softc *sc; 5884743Swnj int i; 5894743Swnj { 5904743Swnj register struct mscp *mp; 5914743Swnj struct uba_device *ui; 5924743Swnj struct buf *dp, *bp; 5934743Swnj int st; 5944743Swnj 5954743Swnj mp = &ud->uda_rsp[i]; 5964743Swnj mp->mscp_header.uda_msglen = sizeof (struct mscp); 5974743Swnj sc->sc_credits += mp->mscp_header.uda_credits & 0xf; 5984743Swnj if ((mp->mscp_header.uda_credits & 0xf0) > 0x10) 5994743Swnj return; 6004743Swnj /* 6014743Swnj * If it's an error log message (datagram), 6024743Swnj * pass it on for more extensive processing. 6034743Swnj */ 6044743Swnj if ((mp->mscp_header.uda_credits & 0xf0) == 0x10) { 6054743Swnj uderror(um, (struct mslg *)mp); 6064743Swnj return; 6074743Swnj } 6084743Swnj if (mp->mscp_unit >= 8) 6094743Swnj return; 6104743Swnj if ((ui = udip[um->um_ctlr][mp->mscp_unit]) == 0) 6114743Swnj return; 6124743Swnj st = mp->mscp_status&M_ST_MASK; 6134743Swnj switch (mp->mscp_opcode) { 6144743Swnj case M_OP_STCON|M_OP_END: 6154743Swnj if (st == M_ST_SUCC) 6164743Swnj sc->sc_state = S_RUN; 6174743Swnj else 6184743Swnj sc->sc_state = S_IDLE; 6194743Swnj um->um_tab.b_active = 0; 6206187Ssam wakeup((caddr_t)um); 6214743Swnj break; 6224743Swnj 6234743Swnj case M_OP_ONLIN|M_OP_END: 6244743Swnj /* 6254743Swnj * Link the drive onto the controller queue 6264743Swnj */ 6274743Swnj dp = &udutab[ui->ui_unit]; 6284743Swnj dp->b_forw = NULL; 6294743Swnj if (um->um_tab.b_actf == NULL) 6304743Swnj um->um_tab.b_actf = dp; 6314743Swnj else 6324743Swnj um->um_tab.b_actl->b_forw = dp; 6334743Swnj um->um_tab.b_actl = dp; 6344743Swnj if (st == M_ST_SUCC) { 6354743Swnj ui->ui_flags = 1; /* mark it online */ 6364743Swnj radsize[ui->ui_unit] = (daddr_t)mp->mscp_untsize; 6374743Swnj printd("uda: unit %d online\n", mp->mscp_unit); 6384743Swnj } else { 6394743Swnj harderr(dp->b_actf, "ra"); 6404743Swnj printf("OFFLINE\n"); 6414743Swnj while (bp = dp->b_actf) { 6424743Swnj dp->b_actf = bp->av_forw; 6434743Swnj bp->b_flags |= B_ERROR; 6444743Swnj iodone(bp); 6454743Swnj } 6464743Swnj } 6474743Swnj dp->b_active = 1; 6484743Swnj break; 6494743Swnj 6504743Swnj case M_OP_AVATN: 6514743Swnj printd("uda: unit %d attention\n", mp->mscp_unit); 6524743Swnj ui->ui_flags = 0; /* it went offline and we didn't notice */ 6534743Swnj break; 6544743Swnj 6554743Swnj case M_OP_READ|M_OP_END: 6564743Swnj case M_OP_WRITE|M_OP_END: 6574743Swnj bp = (struct buf *)mp->mscp_cmdref; 658*6964Ssam ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo); 6594743Swnj /* 6604743Swnj * Unlink buffer from I/O wait queue. 6614743Swnj */ 6624743Swnj bp->av_back->av_forw = bp->av_forw; 6634743Swnj bp->av_forw->av_back = bp->av_back; 6644743Swnj dp = &udutab[ui->ui_unit]; 6654743Swnj if (ui->ui_dk >= 0) 6664743Swnj if (--dp->b_qsize == 0) 6674743Swnj dk_busy &= ~(1<<ui->ui_dk); 6684743Swnj if (st == M_ST_OFFLN || st == M_ST_AVLBL) { 6694743Swnj ui->ui_flags = 0; /* mark unit offline */ 6704743Swnj /* 6714743Swnj * Link the buffer onto the front of the drive queue 6724743Swnj */ 6734743Swnj if ((bp->av_forw = dp->b_actf) == 0) 6744743Swnj dp->b_actl = bp; 6754743Swnj dp->b_actf = bp; 6764743Swnj /* 6774743Swnj * Link the drive onto the controller queue 6784743Swnj */ 6794743Swnj if (dp->b_active == 0) { 6804743Swnj dp->b_forw = NULL; 6814743Swnj if (um->um_tab.b_actf == NULL) 6824743Swnj um->um_tab.b_actf = dp; 6834743Swnj else 6844743Swnj um->um_tab.b_actl->b_forw = dp; 6854743Swnj um->um_tab.b_actl = dp; 6864743Swnj dp->b_active = 1; 6874743Swnj } 6884743Swnj return; 6894743Swnj } 6904743Swnj if (st != M_ST_SUCC) { 6914743Swnj harderr(bp, "ra"); 6924743Swnj printf("status %o\n", mp->mscp_status); 6934743Swnj bp->b_flags |= B_ERROR; 6944743Swnj } 6954743Swnj bp->b_resid = bp->b_bcount - mp->mscp_bytecnt; 6964743Swnj iodone(bp); 6974743Swnj break; 6984743Swnj 6994743Swnj case M_OP_GTUNT|M_OP_END: 7004743Swnj break; 7014743Swnj 7024743Swnj default: 7034743Swnj printf("uda: unknown packet\n"); 7044743Swnj } 7054743Swnj } 7064743Swnj 7074743Swnj 7084743Swnj /* 7094743Swnj * Process an error log message 7104743Swnj * 7114743Swnj * For now, just log the error on the console. 7124743Swnj * Only minimal decoding is done, only "useful" 7134743Swnj * information is printed. Eventually should 7144743Swnj * send message to an error logger. 7154743Swnj */ 7164743Swnj uderror(um, mp) 7174743Swnj register struct uba_ctlr *um; 7184743Swnj register struct mslg *mp; 7194743Swnj { 720*6964Ssam printf("uda%d: %s error, ", um->um_ctlr, 7214743Swnj mp->mslg_flags&M_LF_SUCC ? "soft" : "hard"); 7224743Swnj switch (mp->mslg_format) { 7234743Swnj case M_FM_CNTERR: 7244743Swnj printf("controller error, event 0%o\n", mp->mslg_event); 7254743Swnj break; 7264743Swnj 7274743Swnj case M_FM_BUSADDR: 7284743Swnj printf("host memory access error, event 0%o, addr 0%o\n", 7294743Swnj mp->mslg_event, *((long *)&mp->mslg_busaddr[0])); 7304743Swnj break; 7314743Swnj 7324743Swnj case M_FM_DISKTRN: 733*6964Ssam printf("disk transfer error, unit %d\n", mp->mslg_unit); 7344743Swnj break; 7354743Swnj 7364743Swnj case M_FM_SDI: 737*6964Ssam printf("SDI error, unit %d, event 0%o\n", mp->mslg_unit, 738*6964Ssam mp->mslg_event); 7394743Swnj break; 7404743Swnj 7414743Swnj case M_FM_SMLDSK: 7424743Swnj printf("small disk error, unit %d, event 0%o, cyl %d\n", 7434743Swnj mp->mslg_unit, mp->mslg_event, mp->mslg_sdecyl); 7444743Swnj break; 7454743Swnj 7464743Swnj default: 7474743Swnj printf("unknown error, unit %d, format 0%o, event 0%o\n", 7484743Swnj mp->mslg_unit, mp->mslg_format, mp->mslg_event); 7494743Swnj } 750*6964Ssam 751*6964Ssam if (udaerror) { 752*6964Ssam register long *p = (long *)mp; 753*6964Ssam register int i; 754*6964Ssam 755*6964Ssam for (i = 0; i < mp->mslg_header.uda_msglen; i += sizeof(*p)) 756*6964Ssam printf("%x ", *p++); 757*6964Ssam printf("\n"); 758*6964Ssam } 7594743Swnj } 7604743Swnj 7614743Swnj 7624743Swnj /* 7634743Swnj * Find an unused command packet 7644743Swnj */ 7654743Swnj struct mscp * 7664743Swnj udgetcp(um) 7674743Swnj struct uba_ctlr *um; 7684743Swnj { 7694743Swnj register struct mscp *mp; 7704743Swnj register struct udaca *cp; 7714743Swnj register struct uda_softc *sc; 7724743Swnj register int i; 7734743Swnj 7744743Swnj cp = &uda[um->um_ctlr].uda_ca; 7754743Swnj sc = &uda_softc[um->um_ctlr]; 7764743Swnj i = sc->sc_lastcmd; 7774743Swnj if ((cp->ca_cmddsc[i] & (UDA_OWN|UDA_INT)) == UDA_INT) { 7784743Swnj cp->ca_cmddsc[i] &= ~UDA_INT; 7794743Swnj mp = &uda[um->um_ctlr].uda_cmd[i]; 7804743Swnj mp->mscp_unit = mp->mscp_modifier = 0; 7814743Swnj mp->mscp_opcode = mp->mscp_flags = 0; 7824743Swnj mp->mscp_bytecnt = mp->mscp_buffer = 0; 7834743Swnj mp->mscp_errlgfl = mp->mscp_copyspd = 0; 7844743Swnj sc->sc_lastcmd = (i + 1) % NCMD; 7854743Swnj return(mp); 7864743Swnj } 7874743Swnj return(NULL); 7884743Swnj } 7894743Swnj 7904743Swnj udread(dev) 7914743Swnj dev_t dev; 7924743Swnj { 7934743Swnj register int unit = minor(dev) >> 3; 7944743Swnj 7954743Swnj if (unit >= NRA) 7964743Swnj u.u_error = ENXIO; 7974743Swnj else 7984743Swnj physio(udstrategy, &rudbuf[unit], dev, B_READ, minphys); 7994743Swnj } 8004743Swnj 8014743Swnj udwrite(dev) 8024743Swnj dev_t dev; 8034743Swnj { 8044743Swnj register int unit = minor(dev) >> 3; 8054743Swnj 8064743Swnj if (unit >= NRA) 8074743Swnj u.u_error = ENXIO; 8084743Swnj else 8094743Swnj physio(udstrategy, &rudbuf[unit], dev, B_WRITE, minphys); 8104743Swnj } 8114743Swnj 8124743Swnj udreset(uban) 8134743Swnj int uban; 8144743Swnj { 8154743Swnj register struct uba_ctlr *um; 8164743Swnj register struct uba_device *ui; 8174743Swnj register struct buf *bp, *dp; 8184743Swnj register int unit; 8194743Swnj struct buf *nbp; 8204743Swnj int d; 8214743Swnj 8224743Swnj for (d = 0; d < NUDA; d++) { 8234743Swnj if ((um = udminfo[d]) == 0 || um->um_ubanum != uban || 8244743Swnj um->um_alive == 0) 8254743Swnj continue; 8264743Swnj printf(" uda%d", d); 8274743Swnj um->um_tab.b_active = 0; 8284743Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8294743Swnj uda_softc[d].sc_state = S_IDLE; 8304743Swnj for (unit = 0; unit < NRA; unit++) { 8314743Swnj if ((ui = uddinfo[unit]) == 0) 8324743Swnj continue; 8334743Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 8344743Swnj continue; 8354743Swnj udutab[unit].b_active = 0; 8364743Swnj udutab[unit].b_qsize = 0; 8374743Swnj } 8384743Swnj for (bp = udwtab[d].av_forw; bp != &udwtab[d]; bp = nbp) { 8394743Swnj nbp = bp->av_forw; 8406187Ssam ubarelse(uban, (int *)&bp->b_ubinfo); 8414743Swnj /* 8424743Swnj * Link the buffer onto the drive queue 8434743Swnj */ 8444743Swnj dp = &udutab[dkunit(bp)]; 8454743Swnj if (dp->b_actf == 0) 8464743Swnj dp->b_actf = bp; 8474743Swnj else 8484743Swnj dp->b_actl->av_forw = bp; 8494743Swnj dp->b_actl = bp; 8504743Swnj bp->av_forw = 0; 8514743Swnj /* 8524743Swnj * Link the drive onto the controller queue 8534743Swnj */ 8544743Swnj if (dp->b_active == 0) { 8554743Swnj dp->b_forw = NULL; 8564743Swnj if (um->um_tab.b_actf == NULL) 8574743Swnj um->um_tab.b_actf = dp; 8584743Swnj else 8594743Swnj um->um_tab.b_actl->b_forw = dp; 8604743Swnj um->um_tab.b_actl = dp; 8614743Swnj dp->b_active = 1; 8624743Swnj } 8634743Swnj } 8644743Swnj udinit(d); 8654743Swnj } 8664743Swnj } 8674743Swnj 8684743Swnj uddump() 8694743Swnj { 8704743Swnj return(ENXIO); 8714743Swnj } 872