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