1*15545Skarels /* uda.c 6.2 83/11/15 */ 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 */ 149781Ssam #include "../machine/pte.h" 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/map.h" 234743Swnj #include "../h/vm.h" 244743Swnj #include "../h/dk.h" 254743Swnj #include "../h/cmap.h" 267734Sroot #include "../h/uio.h" 274743Swnj 288482Sroot #include "../vax/cpu.h" 298482Sroot #include "../vaxuba/ubareg.h" 308482Sroot #include "../vaxuba/ubavar.h" 318613Sroot 328613Sroot #define NRSPL2 3 /* log2 number of response packets */ 338613Sroot #define NCMDL2 3 /* log2 number of command packets */ 348613Sroot #define NRSP (1<<NRSPL2) 358613Sroot #define NCMD (1<<NCMDL2) 368613Sroot 378482Sroot #include "../vaxuba/udareg.h" 388482Sroot #include "../vax/mscp.h" 394743Swnj 404743Swnj struct uda_softc { 414743Swnj short sc_state; /* state of controller */ 424743Swnj short sc_mapped; /* Unibus map allocated for uda struct? */ 434743Swnj int sc_ubainfo; /* Unibus mapping info */ 444743Swnj struct uda *sc_uda; /* Unibus address of uda struct */ 454743Swnj int sc_ivec; /* interrupt vector address */ 464743Swnj short sc_credits; /* transfer credits */ 474743Swnj short sc_lastcmd; /* pointer into command ring */ 484743Swnj short sc_lastrsp; /* pointer into response ring */ 494743Swnj } uda_softc[NUDA]; 504743Swnj 514743Swnj /* 524743Swnj * Controller states 534743Swnj */ 544743Swnj #define S_IDLE 0 /* hasn't been initialized */ 554743Swnj #define S_STEP1 1 /* doing step 1 init */ 564743Swnj #define S_STEP2 2 /* doing step 2 init */ 574743Swnj #define S_STEP3 3 /* doing step 3 init */ 584743Swnj #define S_SCHAR 4 /* doing "set controller characteristics" */ 594743Swnj #define S_RUN 5 /* running */ 604743Swnj 614743Swnj struct uda { 624743Swnj struct udaca uda_ca; /* communications area */ 634743Swnj struct mscp uda_rsp[NRSP]; /* response packets */ 644743Swnj struct mscp uda_cmd[NCMD]; /* command packets */ 654743Swnj } uda[NUDA]; 664743Swnj 674743Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 684743Swnj struct size { 694743Swnj daddr_t nblocks; 704743Swnj daddr_t blkoff; 714743Swnj } ra_sizes[8] ={ 724743Swnj 15884, 0, /* A=blk 0 thru 15883 */ 734743Swnj 33440, 15884, /* B=blk 15884 thru 49323 */ 744743Swnj -1, 0, /* C=blk 0 thru end */ 75*15545Skarels 15884, 242606, /* D=blk 242606 thru 258489 */ 76*15545Skarels 307200, 258490, /* E=blk 258490 thru 565689 */ 77*15545Skarels -1, 565690, /* F=blk 565690 thru end */ 78*15545Skarels -1, 242606, /* G=blk 242606 thru end */ 79*15545Skarels 193282, 49324, /* H=blk 49324 thru 242605 */ 804743Swnj }; 814743Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 824743Swnj 8312421Ssam int udaerror = 0; /* causes hex dump of packets */ 8412421Ssam int udadebug = 0; 8512421Ssam #define printd if (udadebug) printf 8612421Ssam 874743Swnj daddr_t radsize[NRA]; /* disk size, from ONLINE end packet */ 884743Swnj 894743Swnj int udprobe(), udslave(), udattach(), udintr(); 904743Swnj struct mscp *udgetcp(); 914743Swnj struct uba_ctlr *udminfo[NUDA]; 924743Swnj struct uba_device *uddinfo[NRA]; 934743Swnj struct uba_device *udip[NUDA][8]; /* 8 == max number of drives */ 944743Swnj 9511243Ssam u_short udstd[] = { 0772150, 0772550, 0777550, 0 }; 964743Swnj struct uba_driver udadriver = 974743Swnj { udprobe, udslave, udattach, 0, udstd, "ra", uddinfo, "uda", udminfo, 0 }; 984743Swnj struct buf rudbuf[NRA]; 994743Swnj struct buf udutab[NRA]; 1004743Swnj struct buf udwtab[NUDA]; /* I/O wait queue, per controller */ 1014743Swnj 1024743Swnj #define b_qsize b_resid /* queue size per drive, in udutab */ 1034743Swnj #define b_ubinfo b_resid /* Unibus mapping info, per buffer */ 1044743Swnj 1054743Swnj udprobe(reg, ctlr) 1064743Swnj caddr_t reg; 1074743Swnj int ctlr; 1084743Swnj { 1094743Swnj register int br, cvec; 1104743Swnj register struct uda_softc *sc = &uda_softc[ctlr]; 1114743Swnj 1124743Swnj #ifdef lint 1136187Ssam br = 0; cvec = br; br = cvec; reg = reg; 11412778Ssam udreset(0); udintr(0); 1154743Swnj #endif 1164743Swnj /* SHOULD CHECK THAT IT REALLY IS A UDA */ 1174743Swnj br = 0x15; 1184743Swnj cvec = sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); 1197410Skre return(sizeof (struct udadevice)); 1204743Swnj } 1214743Swnj 1224743Swnj udslave(ui, reg) 1234743Swnj struct uba_device *ui; 1244743Swnj caddr_t reg; 1254743Swnj { 1264743Swnj /* 1274743Swnj * TOO HARD TO FIND OUT IF DISK IS THERE UNTIL 1284743Swnj * INITIALIZED. WE'LL FIND OUT WHEN WE FIRST 1294743Swnj * TRY TO ACCESS IT. 1304743Swnj */ 1316187Ssam #ifdef lint 1326187Ssam ui = ui; reg = reg; 1336187Ssam #endif 1344743Swnj return(1); 1354743Swnj } 1364743Swnj 1374743Swnj udattach(ui) 1384743Swnj register struct uba_device *ui; 1394743Swnj { 1404743Swnj 14112443Ssam if (ui->ui_dk >= 0) 1424743Swnj dk_mspw[ui->ui_dk] = 1.0 / (60 * 31 * 256); /* approx */ 1434743Swnj ui->ui_flags = 0; 1444743Swnj udip[ui->ui_ctlr][ui->ui_slave] = ui; 1454743Swnj radsize[ui->ui_unit] = (daddr_t)0xffffff; /* max possible size */ 1464743Swnj } 1474743Swnj 1484743Swnj /* 1494743Swnj * Open a UDA. Initialize the device and 1504743Swnj * set the unit online. 1514743Swnj */ 1524743Swnj udopen(dev, flag) 1534743Swnj dev_t dev; 1544743Swnj int flag; 1554743Swnj { 1564743Swnj register int unit; 1574743Swnj register struct uba_device *ui; 1584743Swnj register struct uda_softc *sc; 1595434Sroot int s; 1604743Swnj 1616187Ssam #ifdef lint 1626187Ssam flag = flag; 1636187Ssam #endif 1644743Swnj unit = minor(dev) >> 3; 1658576Sroot if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0) 1668576Sroot return (ENXIO); 1674743Swnj sc = &uda_softc[ui->ui_ctlr]; 1685434Sroot s = spl5(); 1694743Swnj if (sc->sc_state != S_RUN) { 1704743Swnj if (sc->sc_state == S_IDLE) 1714743Swnj udinit(ui->ui_ctlr); 1726187Ssam /* wait for initialization to complete */ 1736187Ssam sleep((caddr_t)ui->ui_mi, 0); 1748576Sroot if (sc->sc_state != S_RUN) 1758576Sroot return (EIO); 1764743Swnj } 1775434Sroot splx(s); 1784743Swnj /* SHOULD PROBABLY FORCE AN ONLINE ATTEMPT 1794743Swnj TO SEE IF DISK IS REALLY THERE */ 1808576Sroot return (0); 1814743Swnj } 1824743Swnj 1834743Swnj /* 1844743Swnj * Initialize a UDA. Set up UBA mapping registers, 1854743Swnj * initialize data structures, and start hardware 1864743Swnj * initialization sequence. 1874743Swnj */ 1884743Swnj udinit(d) 1894743Swnj int d; 1904743Swnj { 1914743Swnj register struct uda_softc *sc; 1924743Swnj register struct uda *ud; 1934743Swnj struct udadevice *udaddr; 1944743Swnj struct uba_ctlr *um; 1954743Swnj 1964743Swnj sc = &uda_softc[d]; 1974743Swnj um = udminfo[d]; 1984743Swnj um->um_tab.b_active++; 1994743Swnj ud = &uda[d]; 2004743Swnj udaddr = (struct udadevice *)um->um_addr; 2014743Swnj if (sc->sc_mapped == 0) { 2024743Swnj /* 2034743Swnj * Map the communications area and command 2044743Swnj * and response packets into Unibus address 2054743Swnj * space. 2064743Swnj */ 2074743Swnj sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)ud, 2084743Swnj sizeof (struct uda), 0); 2094743Swnj sc->sc_uda = (struct uda *)(sc->sc_ubainfo & 0x3ffff); 2104743Swnj sc->sc_mapped = 1; 2114743Swnj } 2124743Swnj 2134743Swnj /* 2144743Swnj * Start the hardware initialization sequence. 2154743Swnj */ 2164743Swnj udaddr->udaip = 0; /* start initialization */ 2174743Swnj while ((udaddr->udasa & UDA_STEP1) == 0) 2184743Swnj ; 2194743Swnj udaddr->udasa = UDA_ERR|(NCMDL2<<11)|(NRSPL2<<8)|UDA_IE|(sc->sc_ivec/4); 2204743Swnj /* 2214743Swnj * Initialization continues in interrupt routine. 2224743Swnj */ 2234743Swnj sc->sc_state = S_STEP1; 2244743Swnj sc->sc_credits = 0; 2254743Swnj } 2264743Swnj 2274743Swnj udstrategy(bp) 2284743Swnj register struct buf *bp; 2294743Swnj { 2304743Swnj register struct uba_device *ui; 2314743Swnj register struct uba_ctlr *um; 2324743Swnj register struct buf *dp; 2334743Swnj register int unit; 2344743Swnj int xunit = minor(bp->b_dev) & 07; 2354743Swnj daddr_t sz, maxsz; 2365434Sroot int s; 2374743Swnj 2384743Swnj sz = (bp->b_bcount+511) >> 9; 2394743Swnj unit = dkunit(bp); 2404743Swnj if (unit >= NRA) 2414743Swnj goto bad; 2424743Swnj ui = uddinfo[unit]; 2434743Swnj um = ui->ui_mi; 2444743Swnj if (ui == 0 || ui->ui_alive == 0) 2454743Swnj goto bad; 2464743Swnj if ((maxsz = ra_sizes[xunit].nblocks) < 0) 2474743Swnj maxsz = radsize[unit] - ra_sizes[xunit].blkoff; 2484743Swnj if (bp->b_blkno < 0 || bp->b_blkno+sz > maxsz || 2494743Swnj ra_sizes[xunit].blkoff >= radsize[unit]) 2504743Swnj goto bad; 2515434Sroot s = spl5(); 2524743Swnj /* 2534743Swnj * Link the buffer onto the drive queue 2544743Swnj */ 2554743Swnj dp = &udutab[ui->ui_unit]; 2564743Swnj if (dp->b_actf == 0) 2574743Swnj dp->b_actf = bp; 2584743Swnj else 2594743Swnj dp->b_actl->av_forw = bp; 2604743Swnj dp->b_actl = bp; 2614743Swnj bp->av_forw = 0; 2624743Swnj /* 2634743Swnj * Link the drive onto the controller queue 2644743Swnj */ 2654743Swnj if (dp->b_active == 0) { 2664743Swnj dp->b_forw = NULL; 2674743Swnj if (um->um_tab.b_actf == NULL) 2684743Swnj um->um_tab.b_actf = dp; 2694743Swnj else 2704743Swnj um->um_tab.b_actl->b_forw = dp; 2714743Swnj um->um_tab.b_actl = dp; 2724743Swnj dp->b_active = 1; 2734743Swnj } 2744743Swnj if (um->um_tab.b_active == 0) { 2754743Swnj #if defined(VAX750) 27612421Ssam if (cpu == VAX_750 27712421Ssam && udwtab[um->um_ctlr].av_forw == &udwtab[um->um_ctlr]) { 2784743Swnj if (um->um_ubinfo != 0) 27912421Ssam printf("udastrat: ubinfo 0x%x\n",um->um_ubinfo); 2804743Swnj else 2814743Swnj um->um_ubinfo = 28212421Ssam uballoc(um->um_ubanum, (caddr_t)0, 0, 2836187Ssam UBA_NEEDBDP); 2844743Swnj } 2854743Swnj #endif 2864743Swnj (void) udstart(um); 2874743Swnj } 2885434Sroot splx(s); 2894743Swnj return; 2904743Swnj 2914743Swnj bad: 2924743Swnj bp->b_flags |= B_ERROR; 2934743Swnj iodone(bp); 2944743Swnj return; 2954743Swnj } 2964743Swnj 2974743Swnj udstart(um) 2984743Swnj register struct uba_ctlr *um; 2994743Swnj { 3004743Swnj register struct buf *bp, *dp; 3014743Swnj register struct mscp *mp; 3024743Swnj register struct uda_softc *sc; 3034743Swnj register struct uba_device *ui; 3044743Swnj struct udadevice *udaddr; 3054743Swnj int i; 3064743Swnj 3074743Swnj sc = &uda_softc[um->um_ctlr]; 3084743Swnj 3094743Swnj loop: 3104743Swnj if ((dp = um->um_tab.b_actf) == NULL) { 3114743Swnj /* 3124743Swnj * Release uneeded UBA resources and return 3134743Swnj */ 3144743Swnj um->um_tab.b_active = 0; 3156187Ssam return (0); 3164743Swnj } 3174743Swnj if ((bp = dp->b_actf) == NULL) { 3184743Swnj /* 3194743Swnj * No more requests for this drive, remove 3204743Swnj * from controller queue and look at next drive. 3214743Swnj * We know we're at the head of the controller queue. 3224743Swnj */ 3234743Swnj dp->b_active = 0; 3244743Swnj um->um_tab.b_actf = dp->b_forw; 3254743Swnj goto loop; 3264743Swnj } 3274743Swnj um->um_tab.b_active++; 3284743Swnj udaddr = (struct udadevice *)um->um_addr; 3294743Swnj if ((udaddr->udasa&UDA_ERR) || sc->sc_state != S_RUN) { 3304743Swnj harderr(bp, "ra"); 3314743Swnj printf("udasa %o, state %d\n", udaddr->udasa&0xffff, sc->sc_state); 3324743Swnj udinit(um->um_ctlr); 3334743Swnj /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE UDRESET */ 3346187Ssam return (0); 3354743Swnj } 3364743Swnj ui = uddinfo[dkunit(bp)]; 3374743Swnj /* 3384743Swnj * If no credits, can't issue any commands 3394743Swnj * until some outstanding commands complete. 3404743Swnj */ 3414743Swnj if (sc->sc_credits < 2) 3426187Ssam return (0); 3434743Swnj if ((mp = udgetcp(um)) == NULL) 3446187Ssam return (0); 3454743Swnj sc->sc_credits--; /* committed to issuing a command */ 3464743Swnj if (ui->ui_flags == 0) { /* not online */ 3474743Swnj mp->mscp_opcode = M_OP_ONLIN; 3484743Swnj mp->mscp_unit = ui->ui_slave; 3494743Swnj dp->b_active = 2; 3504743Swnj um->um_tab.b_actf = dp->b_forw; /* remove from controller q */ 3514743Swnj printd("uda: bring unit %d online\n", ui->ui_slave); 3524743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 3534743Swnj i = udaddr->udaip; 3544743Swnj goto loop; 3554743Swnj } 3564743Swnj switch (cpu) { 3574743Swnj case VAX_780: 3584743Swnj i = UBA_NEEDBDP|UBA_CANTWAIT; 3594743Swnj break; 3604743Swnj 3614743Swnj case VAX_750: 3624743Swnj i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT; 3634743Swnj break; 3644743Swnj 3656949Ssam case VAX_730: 3664743Swnj i = UBA_CANTWAIT; 3674743Swnj break; 3684743Swnj } 3694743Swnj if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) { 3704743Swnj mp->mscp_opcode = M_OP_GTUNT; 3714743Swnj mp->mscp_unit = ui->ui_slave; 3724743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 3734743Swnj i = udaddr->udaip; /* initiate polling */ 3744743Swnj return(1); /* wait for interrupt */ 3754743Swnj } 3764743Swnj mp->mscp_cmdref = (long)bp; /* pointer to get back */ 3774743Swnj mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE; 3784743Swnj mp->mscp_unit = ui->ui_slave; 3794743Swnj mp->mscp_lbn = bp->b_blkno + ra_sizes[minor(bp->b_dev)&7].blkoff; 3804743Swnj mp->mscp_bytecnt = bp->b_bcount; 3814743Swnj mp->mscp_buffer = (i & 0x3ffff) | (((i>>28)&0xf)<<24); 3824743Swnj #if defined(VAX750) 3834743Swnj if (cpu == VAX_750) 3844743Swnj i &= 0xfffffff; /* mask off bdp */ 3854743Swnj #endif 3864743Swnj bp->b_ubinfo = i; /* save mapping info */ 3874743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 3884743Swnj i = udaddr->udaip; /* initiate polling */ 3894743Swnj if (ui->ui_dk >= 0) { 3904743Swnj dk_busy |= 1<<ui->ui_dk; 3914743Swnj dp->b_qsize++; 3924743Swnj dk_xfer[ui->ui_dk]++; 3934743Swnj dk_wds[ui->ui_dk] += bp->b_bcount>>6; 3944743Swnj } 3954743Swnj 3964743Swnj /* 3974743Swnj * Move drive to the end of the controller queue 3984743Swnj */ 3994743Swnj if (dp->b_forw != NULL) { 4004743Swnj um->um_tab.b_actf = dp->b_forw; 4014743Swnj um->um_tab.b_actl->b_forw = dp; 4024743Swnj um->um_tab.b_actl = dp; 4034743Swnj dp->b_forw = NULL; 4044743Swnj } 4054743Swnj /* 4064743Swnj * Move buffer to I/O wait queue 4074743Swnj */ 4084743Swnj dp->b_actf = bp->av_forw; 4094743Swnj dp = &udwtab[um->um_ctlr]; 4104743Swnj bp->av_forw = dp; 4114743Swnj bp->av_back = dp->av_back; 4124743Swnj dp->av_back->av_forw = bp; 4134743Swnj dp->av_back = bp; 4144743Swnj goto loop; 4154743Swnj } 4164743Swnj 4174743Swnj /* 4184743Swnj * UDA interrupt routine. 4194743Swnj */ 4204743Swnj udintr(d) 4214743Swnj int d; 4224743Swnj { 4234743Swnj register struct uba_ctlr *um = udminfo[d]; 4244743Swnj register struct udadevice *udaddr = (struct udadevice *)um->um_addr; 4254743Swnj struct buf *bp; 4264743Swnj register int i; 4274743Swnj register struct uda_softc *sc = &uda_softc[d]; 4284743Swnj register struct uda *ud = &uda[d]; 4294743Swnj struct uda *uud; 4304743Swnj struct mscp *mp; 4314743Swnj 4324743Swnj printd("udintr: state %d, udasa %o\n", sc->sc_state, udaddr->udasa); 4334743Swnj switch (sc->sc_state) { 4344743Swnj case S_IDLE: 4354743Swnj printf("uda%d: random interrupt ignored\n", d); 4364743Swnj return; 4374743Swnj 4384743Swnj case S_STEP1: 4396964Ssam #define STEP1MASK 0174377 4404743Swnj #define STEP1GOOD (UDA_STEP2|UDA_IE|(NCMDL2<<3)|NRSPL2) 4416964Ssam if ((udaddr->udasa&STEP1MASK) != STEP1GOOD) { 4424743Swnj sc->sc_state = S_IDLE; 4436187Ssam wakeup((caddr_t)um); 4444743Swnj return; 4454743Swnj } 4464743Swnj udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)| 4474743Swnj (cpu == VAX_780 ? UDA_PI : 0); 4484743Swnj sc->sc_state = S_STEP2; 4494743Swnj return; 4504743Swnj 4514743Swnj case S_STEP2: 4526964Ssam #define STEP2MASK 0174377 4534743Swnj #define STEP2GOOD (UDA_STEP3|UDA_IE|(sc->sc_ivec/4)) 4546964Ssam if ((udaddr->udasa&STEP2MASK) != STEP2GOOD) { 4554743Swnj sc->sc_state = S_IDLE; 4566187Ssam wakeup((caddr_t)um); 4574743Swnj return; 4584743Swnj } 4594743Swnj udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)>>16; 4604743Swnj sc->sc_state = S_STEP3; 4614743Swnj return; 4624743Swnj 4634743Swnj case S_STEP3: 4646964Ssam #define STEP3MASK 0174000 4654743Swnj #define STEP3GOOD UDA_STEP4 4666964Ssam if ((udaddr->udasa&STEP3MASK) != STEP3GOOD) { 4674743Swnj sc->sc_state = S_IDLE; 4686187Ssam wakeup((caddr_t)um); 4694743Swnj return; 4704743Swnj } 4714743Swnj udaddr->udasa = UDA_GO; 4724743Swnj sc->sc_state = S_SCHAR; 4734743Swnj 4744743Swnj /* 4754743Swnj * Initialize the data structures. 4764743Swnj */ 4774743Swnj uud = sc->sc_uda; 4784743Swnj for (i = 0; i < NRSP; i++) { 4794743Swnj ud->uda_ca.ca_rspdsc[i] = UDA_OWN|UDA_INT| 4804743Swnj (long)&uud->uda_rsp[i].mscp_cmdref; 4814743Swnj ud->uda_rsp[i].mscp_dscptr = &ud->uda_ca.ca_rspdsc[i]; 4824743Swnj ud->uda_rsp[i].mscp_header.uda_msglen = sizeof (struct mscp); 4834743Swnj } 4844743Swnj for (i = 0; i < NCMD; i++) { 4854743Swnj ud->uda_ca.ca_cmddsc[i] = UDA_INT| 4864743Swnj (long)&uud->uda_cmd[i].mscp_cmdref; 4874743Swnj ud->uda_cmd[i].mscp_dscptr = &ud->uda_ca.ca_cmddsc[i]; 4884743Swnj ud->uda_cmd[i].mscp_header.uda_msglen = sizeof (struct mscp); 4894743Swnj } 4904743Swnj bp = &udwtab[d]; 4914743Swnj bp->av_forw = bp->av_back = bp; 4924743Swnj sc->sc_lastcmd = 0; 4934743Swnj sc->sc_lastrsp = 0; 4944743Swnj if ((mp = udgetcp(um)) == NULL) { 4954743Swnj sc->sc_state = S_IDLE; 4966187Ssam wakeup((caddr_t)um); 4974743Swnj return; 4984743Swnj } 4994743Swnj mp->mscp_opcode = M_OP_STCON; 5004743Swnj mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS; 5014743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 5024743Swnj i = udaddr->udaip; /* initiate polling */ 5034743Swnj return; 5044743Swnj 5054743Swnj case S_SCHAR: 5064743Swnj case S_RUN: 5074743Swnj break; 5084743Swnj 5094743Swnj default: 5104743Swnj printf("uda%d: interrupt in unknown state %d ignored\n", 5114743Swnj d, sc->sc_state); 5124743Swnj return; 5134743Swnj } 5144743Swnj 5154743Swnj if (udaddr->udasa&UDA_ERR) { 5164743Swnj printf("uda%d: fatal error (%o)\n", d, udaddr->udasa&0xffff); 5174743Swnj udaddr->udaip = 0; 5186187Ssam wakeup((caddr_t)um); 5194743Swnj } 5204743Swnj 5214743Swnj /* 5224743Swnj * Check for a buffer purge request. 5234743Swnj */ 5244743Swnj if (ud->uda_ca.ca_bdp) { 5254743Swnj /* 5264743Swnj * THIS IS A KLUDGE. 5274743Swnj * Maybe we should change the entire 5284743Swnj * UBA interface structure. 5294743Swnj */ 5304743Swnj int s = spl7(); 5314743Swnj 5324743Swnj i = um->um_ubinfo; 5334743Swnj printd("uda: purge bdp %d\n", ud->uda_ca.ca_bdp); 5344743Swnj um->um_ubinfo = ud->uda_ca.ca_bdp<<28; 5354743Swnj ubapurge(um); 5364743Swnj um->um_ubinfo = i; 5374743Swnj (void) splx(s); 5384743Swnj ud->uda_ca.ca_bdp = 0; 5394743Swnj udaddr->udasa = 0; /* signal purge complete */ 5404743Swnj } 5414743Swnj 5424743Swnj /* 5434743Swnj * Check for response ring transition. 5444743Swnj */ 5454743Swnj if (ud->uda_ca.ca_rspint) { 5464743Swnj ud->uda_ca.ca_rspint = 0; 5474743Swnj for (i = sc->sc_lastrsp;; i++) { 5484743Swnj i %= NRSP; 5494743Swnj if (ud->uda_ca.ca_rspdsc[i]&UDA_OWN) 5504743Swnj break; 5514743Swnj udrsp(um, ud, sc, i); 5524743Swnj ud->uda_ca.ca_rspdsc[i] |= UDA_OWN; 5534743Swnj } 5544743Swnj sc->sc_lastrsp = i; 5554743Swnj } 5564743Swnj 5574743Swnj /* 5584743Swnj * Check for command ring transition. 5594743Swnj */ 5604743Swnj if (ud->uda_ca.ca_cmdint) { 5614743Swnj printd("uda: command ring transition\n"); 5624743Swnj ud->uda_ca.ca_cmdint = 0; 5634743Swnj } 5646187Ssam (void) udstart(um); 5654743Swnj } 5664743Swnj 5674743Swnj /* 5684743Swnj * Process a response packet 5694743Swnj */ 5704743Swnj udrsp(um, ud, sc, i) 5714743Swnj register struct uba_ctlr *um; 5724743Swnj register struct uda *ud; 5734743Swnj register struct uda_softc *sc; 5744743Swnj int i; 5754743Swnj { 5764743Swnj register struct mscp *mp; 5774743Swnj struct uba_device *ui; 5784743Swnj struct buf *dp, *bp; 5794743Swnj int st; 5804743Swnj 5814743Swnj mp = &ud->uda_rsp[i]; 5824743Swnj mp->mscp_header.uda_msglen = sizeof (struct mscp); 5834743Swnj sc->sc_credits += mp->mscp_header.uda_credits & 0xf; 5844743Swnj if ((mp->mscp_header.uda_credits & 0xf0) > 0x10) 5854743Swnj return; 5864743Swnj /* 5874743Swnj * If it's an error log message (datagram), 5884743Swnj * pass it on for more extensive processing. 5894743Swnj */ 5904743Swnj if ((mp->mscp_header.uda_credits & 0xf0) == 0x10) { 5914743Swnj uderror(um, (struct mslg *)mp); 5924743Swnj return; 5934743Swnj } 5944743Swnj if (mp->mscp_unit >= 8) 5954743Swnj return; 5964743Swnj if ((ui = udip[um->um_ctlr][mp->mscp_unit]) == 0) 5974743Swnj return; 5984743Swnj st = mp->mscp_status&M_ST_MASK; 5994743Swnj switch (mp->mscp_opcode) { 6004743Swnj case M_OP_STCON|M_OP_END: 6014743Swnj if (st == M_ST_SUCC) 6024743Swnj sc->sc_state = S_RUN; 6034743Swnj else 6044743Swnj sc->sc_state = S_IDLE; 6054743Swnj um->um_tab.b_active = 0; 6066187Ssam wakeup((caddr_t)um); 6074743Swnj break; 6084743Swnj 6094743Swnj case M_OP_ONLIN|M_OP_END: 6104743Swnj /* 6114743Swnj * Link the drive onto the controller queue 6124743Swnj */ 6134743Swnj dp = &udutab[ui->ui_unit]; 6144743Swnj dp->b_forw = NULL; 6154743Swnj if (um->um_tab.b_actf == NULL) 6164743Swnj um->um_tab.b_actf = dp; 6174743Swnj else 6184743Swnj um->um_tab.b_actl->b_forw = dp; 6194743Swnj um->um_tab.b_actl = dp; 6204743Swnj if (st == M_ST_SUCC) { 6214743Swnj ui->ui_flags = 1; /* mark it online */ 6224743Swnj radsize[ui->ui_unit] = (daddr_t)mp->mscp_untsize; 6234743Swnj printd("uda: unit %d online\n", mp->mscp_unit); 62413867Ssam #ifdef notdef 62513867Ssam printf("uda%d: online, size=%d\n", 62613867Ssam mp->mscp_unit, (daddr_t)mp->mscp_untsize); 62713867Ssam #endif 6284743Swnj } else { 6294743Swnj harderr(dp->b_actf, "ra"); 6304743Swnj printf("OFFLINE\n"); 6314743Swnj while (bp = dp->b_actf) { 6324743Swnj dp->b_actf = bp->av_forw; 6334743Swnj bp->b_flags |= B_ERROR; 6344743Swnj iodone(bp); 6354743Swnj } 6364743Swnj } 6374743Swnj dp->b_active = 1; 6384743Swnj break; 6394743Swnj 6404743Swnj case M_OP_AVATN: 6414743Swnj printd("uda: unit %d attention\n", mp->mscp_unit); 6424743Swnj ui->ui_flags = 0; /* it went offline and we didn't notice */ 6434743Swnj break; 6444743Swnj 6454743Swnj case M_OP_READ|M_OP_END: 6464743Swnj case M_OP_WRITE|M_OP_END: 6474743Swnj bp = (struct buf *)mp->mscp_cmdref; 6486964Ssam ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo); 6494743Swnj /* 6504743Swnj * Unlink buffer from I/O wait queue. 6514743Swnj */ 6524743Swnj bp->av_back->av_forw = bp->av_forw; 6534743Swnj bp->av_forw->av_back = bp->av_back; 65412421Ssam #if defined(VAX750) 65512421Ssam if (cpu == VAX_750 65612421Ssam && udwtab[um->um_ctlr].av_forw == &udwtab[um->um_ctlr]) { 65712421Ssam if (um->um_ubinfo == 0) 65812421Ssam printf("udintr: um_ubinfo == 0\n"); 65912421Ssam else 66012421Ssam ubarelse(um->um_ubanum, &um->um_ubinfo); 66112421Ssam } 66212421Ssam #endif 6634743Swnj dp = &udutab[ui->ui_unit]; 6644743Swnj if (ui->ui_dk >= 0) 6654743Swnj if (--dp->b_qsize == 0) 6664743Swnj dk_busy &= ~(1<<ui->ui_dk); 6674743Swnj if (st == M_ST_OFFLN || st == M_ST_AVLBL) { 6684743Swnj ui->ui_flags = 0; /* mark unit offline */ 6694743Swnj /* 6704743Swnj * Link the buffer onto the front of the drive queue 6714743Swnj */ 6724743Swnj if ((bp->av_forw = dp->b_actf) == 0) 6734743Swnj dp->b_actl = bp; 6744743Swnj dp->b_actf = bp; 6754743Swnj /* 6764743Swnj * Link the drive onto the controller queue 6774743Swnj */ 6784743Swnj if (dp->b_active == 0) { 6794743Swnj dp->b_forw = NULL; 6804743Swnj if (um->um_tab.b_actf == NULL) 6814743Swnj um->um_tab.b_actf = dp; 6824743Swnj else 6834743Swnj um->um_tab.b_actl->b_forw = dp; 6844743Swnj um->um_tab.b_actl = dp; 6854743Swnj dp->b_active = 1; 6864743Swnj } 68712421Ssam #if defined(VAX750) 68812421Ssam if (cpu == VAX750 && um->um_ubinfo == 0) 68912421Ssam um->um_ubinfo = 69012421Ssam uballoc(um->um_ubanum, (caddr_t)0, 0, 69112421Ssam UBA_NEEDBDP); 69212421Ssam #endif 6934743Swnj return; 6944743Swnj } 6954743Swnj if (st != M_ST_SUCC) { 6964743Swnj harderr(bp, "ra"); 6974743Swnj printf("status %o\n", mp->mscp_status); 6984743Swnj bp->b_flags |= B_ERROR; 6994743Swnj } 7004743Swnj bp->b_resid = bp->b_bcount - mp->mscp_bytecnt; 7014743Swnj iodone(bp); 7024743Swnj break; 7034743Swnj 7044743Swnj case M_OP_GTUNT|M_OP_END: 7054743Swnj break; 7064743Swnj 7074743Swnj default: 7084743Swnj printf("uda: unknown packet\n"); 7094743Swnj } 7104743Swnj } 7114743Swnj 7124743Swnj 7134743Swnj /* 7144743Swnj * Process an error log message 7154743Swnj * 7164743Swnj * For now, just log the error on the console. 7174743Swnj * Only minimal decoding is done, only "useful" 7184743Swnj * information is printed. Eventually should 7194743Swnj * send message to an error logger. 7204743Swnj */ 7214743Swnj uderror(um, mp) 7224743Swnj register struct uba_ctlr *um; 7234743Swnj register struct mslg *mp; 7244743Swnj { 7256964Ssam printf("uda%d: %s error, ", um->um_ctlr, 7264743Swnj mp->mslg_flags&M_LF_SUCC ? "soft" : "hard"); 7274743Swnj switch (mp->mslg_format) { 7284743Swnj case M_FM_CNTERR: 7294743Swnj printf("controller error, event 0%o\n", mp->mslg_event); 7304743Swnj break; 7314743Swnj 7324743Swnj case M_FM_BUSADDR: 7334743Swnj printf("host memory access error, event 0%o, addr 0%o\n", 7349174Ssam mp->mslg_event, mp->mslg_busaddr); 7354743Swnj break; 7364743Swnj 7374743Swnj case M_FM_DISKTRN: 73812421Ssam printf("disk transfer error, unit %d, grp 0x%x, hdr 0x%x\n", 73912421Ssam mp->mslg_unit, mp->mslg_group, mp->mslg_hdr); 7404743Swnj break; 7414743Swnj 7424743Swnj case M_FM_SDI: 74312421Ssam printf("SDI error, unit %d, event 0%o, hdr 0x%x\n", 74412421Ssam mp->mslg_unit, mp->mslg_event, mp->mslg_hdr); 7454743Swnj break; 7464743Swnj 7474743Swnj case M_FM_SMLDSK: 7484743Swnj printf("small disk error, unit %d, event 0%o, cyl %d\n", 7494743Swnj mp->mslg_unit, mp->mslg_event, mp->mslg_sdecyl); 7504743Swnj break; 7514743Swnj 7524743Swnj default: 7534743Swnj printf("unknown error, unit %d, format 0%o, event 0%o\n", 7544743Swnj mp->mslg_unit, mp->mslg_format, mp->mslg_event); 7554743Swnj } 7566964Ssam 7576964Ssam if (udaerror) { 7586964Ssam register long *p = (long *)mp; 7596964Ssam register int i; 7606964Ssam 7616964Ssam for (i = 0; i < mp->mslg_header.uda_msglen; i += sizeof(*p)) 7626964Ssam printf("%x ", *p++); 7636964Ssam printf("\n"); 7646964Ssam } 7654743Swnj } 7664743Swnj 7674743Swnj 7684743Swnj /* 7694743Swnj * Find an unused command packet 7704743Swnj */ 7714743Swnj struct mscp * 7724743Swnj udgetcp(um) 7734743Swnj struct uba_ctlr *um; 7744743Swnj { 7754743Swnj register struct mscp *mp; 7764743Swnj register struct udaca *cp; 7774743Swnj register struct uda_softc *sc; 7784743Swnj register int i; 7794743Swnj 7804743Swnj cp = &uda[um->um_ctlr].uda_ca; 7814743Swnj sc = &uda_softc[um->um_ctlr]; 7824743Swnj i = sc->sc_lastcmd; 7834743Swnj if ((cp->ca_cmddsc[i] & (UDA_OWN|UDA_INT)) == UDA_INT) { 7844743Swnj cp->ca_cmddsc[i] &= ~UDA_INT; 7854743Swnj mp = &uda[um->um_ctlr].uda_cmd[i]; 7864743Swnj mp->mscp_unit = mp->mscp_modifier = 0; 7874743Swnj mp->mscp_opcode = mp->mscp_flags = 0; 7884743Swnj mp->mscp_bytecnt = mp->mscp_buffer = 0; 7894743Swnj mp->mscp_errlgfl = mp->mscp_copyspd = 0; 7904743Swnj sc->sc_lastcmd = (i + 1) % NCMD; 7914743Swnj return(mp); 7924743Swnj } 7934743Swnj return(NULL); 7944743Swnj } 7954743Swnj 7967734Sroot udread(dev, uio) 7974743Swnj dev_t dev; 7987734Sroot struct uio *uio; 7994743Swnj { 8004743Swnj register int unit = minor(dev) >> 3; 8014743Swnj 8024743Swnj if (unit >= NRA) 8038165Sroot return (ENXIO); 8048165Sroot return (physio(udstrategy, &rudbuf[unit], dev, B_READ, minphys, uio)); 8054743Swnj } 8064743Swnj 8077845Sroot udwrite(dev, uio) 8084743Swnj dev_t dev; 8097845Sroot struct uio *uio; 8104743Swnj { 8114743Swnj register int unit = minor(dev) >> 3; 8124743Swnj 8134743Swnj if (unit >= NRA) 8148165Sroot return (ENXIO); 8158165Sroot return (physio(udstrategy, &rudbuf[unit], dev, B_WRITE, minphys, uio)); 8164743Swnj } 8174743Swnj 8184743Swnj udreset(uban) 8194743Swnj int uban; 8204743Swnj { 8214743Swnj register struct uba_ctlr *um; 8224743Swnj register struct uba_device *ui; 8234743Swnj register struct buf *bp, *dp; 8244743Swnj register int unit; 8254743Swnj struct buf *nbp; 8264743Swnj int d; 8274743Swnj 8284743Swnj for (d = 0; d < NUDA; d++) { 8294743Swnj if ((um = udminfo[d]) == 0 || um->um_ubanum != uban || 8304743Swnj um->um_alive == 0) 8314743Swnj continue; 8324743Swnj printf(" uda%d", d); 8334743Swnj um->um_tab.b_active = 0; 8344743Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8354743Swnj uda_softc[d].sc_state = S_IDLE; 8364743Swnj for (unit = 0; unit < NRA; unit++) { 8374743Swnj if ((ui = uddinfo[unit]) == 0) 8384743Swnj continue; 8394743Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 8404743Swnj continue; 8414743Swnj udutab[unit].b_active = 0; 8424743Swnj udutab[unit].b_qsize = 0; 8434743Swnj } 8444743Swnj for (bp = udwtab[d].av_forw; bp != &udwtab[d]; bp = nbp) { 8454743Swnj nbp = bp->av_forw; 8468576Sroot bp->b_ubinfo = 0; 8474743Swnj /* 8484743Swnj * Link the buffer onto the drive queue 8494743Swnj */ 8504743Swnj dp = &udutab[dkunit(bp)]; 8514743Swnj if (dp->b_actf == 0) 8524743Swnj dp->b_actf = bp; 8534743Swnj else 8544743Swnj dp->b_actl->av_forw = bp; 8554743Swnj dp->b_actl = bp; 8564743Swnj bp->av_forw = 0; 8574743Swnj /* 8584743Swnj * Link the drive onto the controller queue 8594743Swnj */ 8604743Swnj if (dp->b_active == 0) { 8614743Swnj dp->b_forw = NULL; 8624743Swnj if (um->um_tab.b_actf == NULL) 8634743Swnj um->um_tab.b_actf = dp; 8644743Swnj else 8654743Swnj um->um_tab.b_actl->b_forw = dp; 8664743Swnj um->um_tab.b_actl = dp; 8674743Swnj dp->b_active = 1; 8684743Swnj } 8694743Swnj } 8704743Swnj udinit(d); 8714743Swnj } 8724743Swnj } 8734743Swnj 8744743Swnj uddump() 8754743Swnj { 8764743Swnj return(ENXIO); 8774743Swnj } 87812511Ssam 87912511Ssam udsize(dev) 88012511Ssam dev_t dev; 88112511Ssam { 88212511Ssam int unit = minor(dev) >> 3; 88312511Ssam struct uba_device *ui; 88412511Ssam 88512511Ssam if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0) 88612511Ssam return (-1); 88712511Ssam return (ra_sizes[minor(dev) & 07].nblocks); /* XXX */ 88812511Ssam } 88912511Ssam #endif 890