1*4743Swnj /* uda.c 4.1 81/11/04 */ 2*4743Swnj 3*4743Swnj #include "ra.h" 4*4743Swnj #if NUDA > 0 5*4743Swnj /* 6*4743Swnj * UDA50/RAxx disk device driver 7*4743Swnj * 8*4743Swnj * Restrictions: 9*4743Swnj * Unit numbers must be less than 8. 10*4743Swnj * 11*4743Swnj * TO DO: 12*4743Swnj * write dump code 13*4743Swnj * test on 750 14*4743Swnj */ 15*4743Swnj 16*4743Swnj #include "../h/param.h" 17*4743Swnj #include "../h/systm.h" 18*4743Swnj #include "../h/buf.h" 19*4743Swnj #include "../h/conf.h" 20*4743Swnj #include "../h/dir.h" 21*4743Swnj #include "../h/user.h" 22*4743Swnj #include "../h/pte.h" 23*4743Swnj #include "../h/map.h" 24*4743Swnj #include "../h/vm.h" 25*4743Swnj #include "../h/ubareg.h" 26*4743Swnj #include "../h/ubavar.h" 27*4743Swnj #include "../h/dk.h" 28*4743Swnj #include "../h/cpu.h" 29*4743Swnj #include "../h/cmap.h" 30*4743Swnj 31*4743Swnj int udadebug; 32*4743Swnj #define printd if(udadebug&1)printf 33*4743Swnj 34*4743Swnj /* 35*4743Swnj * Parameters for the communications area 36*4743Swnj */ 37*4743Swnj 38*4743Swnj #define NRSPL2 3 39*4743Swnj #define NCMDL2 3 40*4743Swnj #define NRSP (1<<NRSPL2) 41*4743Swnj #define NCMD (1<<NCMDL2) 42*4743Swnj 43*4743Swnj #include "../h/udareg.h" 44*4743Swnj #include "../h/mscp.h" 45*4743Swnj 46*4743Swnj struct uda_softc { 47*4743Swnj short sc_state; /* state of controller */ 48*4743Swnj short sc_mapped; /* Unibus map allocated for uda struct? */ 49*4743Swnj int sc_ubainfo; /* Unibus mapping info */ 50*4743Swnj struct uda *sc_uda; /* Unibus address of uda struct */ 51*4743Swnj int sc_ivec; /* interrupt vector address */ 52*4743Swnj short sc_credits; /* transfer credits */ 53*4743Swnj short sc_lastcmd; /* pointer into command ring */ 54*4743Swnj short sc_lastrsp; /* pointer into response ring */ 55*4743Swnj } uda_softc[NUDA]; 56*4743Swnj 57*4743Swnj /* 58*4743Swnj * Controller states 59*4743Swnj */ 60*4743Swnj #define S_IDLE 0 /* hasn't been initialized */ 61*4743Swnj #define S_STEP1 1 /* doing step 1 init */ 62*4743Swnj #define S_STEP2 2 /* doing step 2 init */ 63*4743Swnj #define S_STEP3 3 /* doing step 3 init */ 64*4743Swnj #define S_SCHAR 4 /* doing "set controller characteristics" */ 65*4743Swnj #define S_RUN 5 /* running */ 66*4743Swnj 67*4743Swnj struct uda { 68*4743Swnj struct udaca uda_ca; /* communications area */ 69*4743Swnj struct mscp uda_rsp[NRSP]; /* response packets */ 70*4743Swnj struct mscp uda_cmd[NCMD]; /* command packets */ 71*4743Swnj } uda[NUDA]; 72*4743Swnj 73*4743Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 74*4743Swnj struct size { 75*4743Swnj daddr_t nblocks; 76*4743Swnj daddr_t blkoff; 77*4743Swnj } ra_sizes[8] ={ 78*4743Swnj 15884, 0, /* A=blk 0 thru 15883 */ 79*4743Swnj 33440, 15884, /* B=blk 15884 thru 49323 */ 80*4743Swnj -1, 0, /* C=blk 0 thru end */ 81*4743Swnj 0, 0, /* D reserved for RA81 */ 82*4743Swnj 0, 0, /* E reserved for RA81 */ 83*4743Swnj 0, 0, /* F reserved for RA81 */ 84*4743Swnj 82080, 49324, /* G=blk 49324 thru 131403 */ 85*4743Swnj -1, 131404, /* H=blk 131404 thru end */ 86*4743Swnj }; 87*4743Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 88*4743Swnj 89*4743Swnj daddr_t radsize[NRA]; /* disk size, from ONLINE end packet */ 90*4743Swnj 91*4743Swnj int udprobe(), udslave(), udattach(), udintr(); 92*4743Swnj struct mscp *udgetcp(); 93*4743Swnj struct uba_ctlr *udminfo[NUDA]; 94*4743Swnj struct uba_device *uddinfo[NRA]; 95*4743Swnj struct uba_device *udip[NUDA][8]; /* 8 == max number of drives */ 96*4743Swnj 97*4743Swnj u_short udstd[] = { 0777550, 0 }; 98*4743Swnj struct uba_driver udadriver = 99*4743Swnj { udprobe, udslave, udattach, 0, udstd, "ra", uddinfo, "uda", udminfo, 0 }; 100*4743Swnj struct buf rudbuf[NRA]; 101*4743Swnj struct buf udutab[NRA]; 102*4743Swnj struct buf udwtab[NUDA]; /* I/O wait queue, per controller */ 103*4743Swnj 104*4743Swnj #define b_qsize b_resid /* queue size per drive, in udutab */ 105*4743Swnj #define b_ubinfo b_resid /* Unibus mapping info, per buffer */ 106*4743Swnj 107*4743Swnj udprobe(reg, ctlr) 108*4743Swnj caddr_t reg; 109*4743Swnj int ctlr; 110*4743Swnj { 111*4743Swnj register int br, cvec; 112*4743Swnj register struct uda_softc *sc = &uda_softc[ctlr]; 113*4743Swnj 114*4743Swnj #ifdef lint 115*4743Swnj br = 0; cvec = br; br = cvec; 116*4743Swnj #endif 117*4743Swnj /* SHOULD CHECK THAT IT REALLY IS A UDA */ 118*4743Swnj br = 0x15; 119*4743Swnj cvec = sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); 120*4743Swnj return(1); 121*4743Swnj } 122*4743Swnj 123*4743Swnj udslave(ui, reg) 124*4743Swnj struct uba_device *ui; 125*4743Swnj caddr_t reg; 126*4743Swnj { 127*4743Swnj /* 128*4743Swnj * TOO HARD TO FIND OUT IF DISK IS THERE UNTIL 129*4743Swnj * INITIALIZED. WE'LL FIND OUT WHEN WE FIRST 130*4743Swnj * TRY TO ACCESS IT. 131*4743Swnj */ 132*4743Swnj return(1); 133*4743Swnj } 134*4743Swnj 135*4743Swnj udattach(ui) 136*4743Swnj register struct uba_device *ui; 137*4743Swnj { 138*4743Swnj 139*4743Swnj if (ui->ui_dk > 0) 140*4743Swnj dk_mspw[ui->ui_dk] = 1.0 / (60 * 31 * 256); /* approx */ 141*4743Swnj ui->ui_flags = 0; 142*4743Swnj udip[ui->ui_ctlr][ui->ui_slave] = ui; 143*4743Swnj radsize[ui->ui_unit] = (daddr_t)0xffffff; /* max possible size */ 144*4743Swnj } 145*4743Swnj 146*4743Swnj /* 147*4743Swnj * Open a UDA. Initialize the device and 148*4743Swnj * set the unit online. 149*4743Swnj */ 150*4743Swnj udopen(dev, flag) 151*4743Swnj dev_t dev; 152*4743Swnj int flag; 153*4743Swnj { 154*4743Swnj register int unit; 155*4743Swnj register struct uba_device *ui; 156*4743Swnj register struct uda_softc *sc; 157*4743Swnj 158*4743Swnj unit = minor(dev) >> 3; 159*4743Swnj if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0) { 160*4743Swnj u.u_error = ENXIO; 161*4743Swnj return; 162*4743Swnj } 163*4743Swnj sc = &uda_softc[ui->ui_ctlr]; 164*4743Swnj (void) spl5(); 165*4743Swnj if (sc->sc_state != S_RUN) { 166*4743Swnj if (sc->sc_state == S_IDLE) 167*4743Swnj udinit(ui->ui_ctlr); 168*4743Swnj sleep(ui->ui_mi, 0); /* wait for initialization to complete */ 169*4743Swnj if (sc->sc_state != S_RUN) { 170*4743Swnj u.u_error = EIO; 171*4743Swnj return; 172*4743Swnj } 173*4743Swnj } 174*4743Swnj (void) spl0(); 175*4743Swnj /* SHOULD PROBABLY FORCE AN ONLINE ATTEMPT 176*4743Swnj TO SEE IF DISK IS REALLY THERE */ 177*4743Swnj } 178*4743Swnj 179*4743Swnj /* 180*4743Swnj * Initialize a UDA. Set up UBA mapping registers, 181*4743Swnj * initialize data structures, and start hardware 182*4743Swnj * initialization sequence. 183*4743Swnj */ 184*4743Swnj udinit(d) 185*4743Swnj int d; 186*4743Swnj { 187*4743Swnj register struct uda_softc *sc; 188*4743Swnj register struct uda *ud; 189*4743Swnj struct udadevice *udaddr; 190*4743Swnj struct uba_ctlr *um; 191*4743Swnj 192*4743Swnj sc = &uda_softc[d]; 193*4743Swnj um = udminfo[d]; 194*4743Swnj um->um_tab.b_active++; 195*4743Swnj ud = &uda[d]; 196*4743Swnj udaddr = (struct udadevice *)um->um_addr; 197*4743Swnj if (sc->sc_mapped == 0) { 198*4743Swnj /* 199*4743Swnj * Map the communications area and command 200*4743Swnj * and response packets into Unibus address 201*4743Swnj * space. 202*4743Swnj */ 203*4743Swnj sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)ud, 204*4743Swnj sizeof (struct uda), 0); 205*4743Swnj sc->sc_uda = (struct uda *)(sc->sc_ubainfo & 0x3ffff); 206*4743Swnj sc->sc_mapped = 1; 207*4743Swnj } 208*4743Swnj 209*4743Swnj /* 210*4743Swnj * Start the hardware initialization sequence. 211*4743Swnj */ 212*4743Swnj udaddr->udaip = 0; /* start initialization */ 213*4743Swnj while ((udaddr->udasa & UDA_STEP1) == 0) 214*4743Swnj ; 215*4743Swnj udaddr->udasa = UDA_ERR|(NCMDL2<<11)|(NRSPL2<<8)|UDA_IE|(sc->sc_ivec/4); 216*4743Swnj /* 217*4743Swnj * Initialization continues in interrupt routine. 218*4743Swnj */ 219*4743Swnj sc->sc_state = S_STEP1; 220*4743Swnj sc->sc_credits = 0; 221*4743Swnj } 222*4743Swnj 223*4743Swnj udstrategy(bp) 224*4743Swnj register struct buf *bp; 225*4743Swnj { 226*4743Swnj register struct uba_device *ui; 227*4743Swnj register struct uba_ctlr *um; 228*4743Swnj register struct buf *dp; 229*4743Swnj register int unit; 230*4743Swnj int xunit = minor(bp->b_dev) & 07; 231*4743Swnj daddr_t sz, maxsz; 232*4743Swnj 233*4743Swnj sz = (bp->b_bcount+511) >> 9; 234*4743Swnj unit = dkunit(bp); 235*4743Swnj if (unit >= NRA) 236*4743Swnj goto bad; 237*4743Swnj ui = uddinfo[unit]; 238*4743Swnj um = ui->ui_mi; 239*4743Swnj if (ui == 0 || ui->ui_alive == 0) 240*4743Swnj goto bad; 241*4743Swnj if ((maxsz = ra_sizes[xunit].nblocks) < 0) 242*4743Swnj maxsz = radsize[unit] - ra_sizes[xunit].blkoff; 243*4743Swnj if (bp->b_blkno < 0 || bp->b_blkno+sz > maxsz || 244*4743Swnj ra_sizes[xunit].blkoff >= radsize[unit]) 245*4743Swnj goto bad; 246*4743Swnj (void) spl5(); 247*4743Swnj /* 248*4743Swnj * Link the buffer onto the drive queue 249*4743Swnj */ 250*4743Swnj dp = &udutab[ui->ui_unit]; 251*4743Swnj if (dp->b_actf == 0) 252*4743Swnj dp->b_actf = bp; 253*4743Swnj else 254*4743Swnj dp->b_actl->av_forw = bp; 255*4743Swnj dp->b_actl = bp; 256*4743Swnj bp->av_forw = 0; 257*4743Swnj /* 258*4743Swnj * Link the drive onto the controller queue 259*4743Swnj */ 260*4743Swnj if (dp->b_active == 0) { 261*4743Swnj dp->b_forw = NULL; 262*4743Swnj if (um->um_tab.b_actf == NULL) 263*4743Swnj um->um_tab.b_actf = dp; 264*4743Swnj else 265*4743Swnj um->um_tab.b_actl->b_forw = dp; 266*4743Swnj um->um_tab.b_actl = dp; 267*4743Swnj dp->b_active = 1; 268*4743Swnj } 269*4743Swnj if (um->um_tab.b_active == 0) { 270*4743Swnj #if defined(VAX750) 271*4743Swnj if (cpu == VAX_750) { 272*4743Swnj if (um->um_ubinfo != 0) 273*4743Swnj printf("uda: ubinfo %x\n",um->um_ubinfo); 274*4743Swnj else 275*4743Swnj um->um_ubinfo = 276*4743Swnj uballoc(um->um_ubanum, 0, 0, UBA_NEEDBDP); 277*4743Swnj } 278*4743Swnj #endif 279*4743Swnj (void) udstart(um); 280*4743Swnj } 281*4743Swnj (void) spl0(); 282*4743Swnj return; 283*4743Swnj 284*4743Swnj bad: 285*4743Swnj bp->b_flags |= B_ERROR; 286*4743Swnj iodone(bp); 287*4743Swnj return; 288*4743Swnj } 289*4743Swnj 290*4743Swnj udstart(um) 291*4743Swnj register struct uba_ctlr *um; 292*4743Swnj { 293*4743Swnj register struct buf *bp, *dp; 294*4743Swnj register struct mscp *mp; 295*4743Swnj register struct uda_softc *sc; 296*4743Swnj register struct uba_device *ui; 297*4743Swnj struct udadevice *udaddr; 298*4743Swnj int i; 299*4743Swnj 300*4743Swnj sc = &uda_softc[um->um_ctlr]; 301*4743Swnj 302*4743Swnj loop: 303*4743Swnj if ((dp = um->um_tab.b_actf) == NULL) { 304*4743Swnj /* 305*4743Swnj * Release uneeded UBA resources and return 306*4743Swnj */ 307*4743Swnj um->um_tab.b_active = 0; 308*4743Swnj #if defined(VAX750) 309*4743Swnj if (cpu == VAX_750) { 310*4743Swnj if (um->um_ubinfo == 0) 311*4743Swnj printf("uda: um_ubinfo == 0\n"); 312*4743Swnj else 313*4743Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 314*4743Swnj } 315*4743Swnj #endif 316*4743Swnj return(0); 317*4743Swnj } 318*4743Swnj if ((bp = dp->b_actf) == NULL) { 319*4743Swnj /* 320*4743Swnj * No more requests for this drive, remove 321*4743Swnj * from controller queue and look at next drive. 322*4743Swnj * We know we're at the head of the controller queue. 323*4743Swnj */ 324*4743Swnj dp->b_active = 0; 325*4743Swnj um->um_tab.b_actf = dp->b_forw; 326*4743Swnj goto loop; 327*4743Swnj } 328*4743Swnj um->um_tab.b_active++; 329*4743Swnj udaddr = (struct udadevice *)um->um_addr; 330*4743Swnj if ((udaddr->udasa&UDA_ERR) || sc->sc_state != S_RUN) { 331*4743Swnj harderr(bp, "ra"); 332*4743Swnj printf("udasa %o, state %d\n", udaddr->udasa&0xffff, sc->sc_state); 333*4743Swnj udinit(um->um_ctlr); 334*4743Swnj /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE UDRESET */ 335*4743Swnj return; 336*4743Swnj } 337*4743Swnj ui = uddinfo[dkunit(bp)]; 338*4743Swnj /* 339*4743Swnj * If no credits, can't issue any commands 340*4743Swnj * until some outstanding commands complete. 341*4743Swnj */ 342*4743Swnj if (sc->sc_credits < 2) 343*4743Swnj return(0); 344*4743Swnj if ((mp = udgetcp(um)) == NULL) 345*4743Swnj return(0); 346*4743Swnj sc->sc_credits--; /* committed to issuing a command */ 347*4743Swnj if (ui->ui_flags == 0) { /* not online */ 348*4743Swnj mp->mscp_opcode = M_OP_ONLIN; 349*4743Swnj mp->mscp_unit = ui->ui_slave; 350*4743Swnj dp->b_active = 2; 351*4743Swnj um->um_tab.b_actf = dp->b_forw; /* remove from controller q */ 352*4743Swnj printd("uda: bring unit %d online\n", ui->ui_slave); 353*4743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 354*4743Swnj i = udaddr->udaip; 355*4743Swnj goto loop; 356*4743Swnj } 357*4743Swnj switch (cpu) { 358*4743Swnj case VAX_780: 359*4743Swnj i = UBA_NEEDBDP|UBA_CANTWAIT; 360*4743Swnj break; 361*4743Swnj 362*4743Swnj case VAX_750: 363*4743Swnj i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT; 364*4743Swnj break; 365*4743Swnj 366*4743Swnj case VAX_7ZZ: 367*4743Swnj i = UBA_CANTWAIT; 368*4743Swnj break; 369*4743Swnj } 370*4743Swnj if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) { 371*4743Swnj mp->mscp_opcode = M_OP_GTUNT; 372*4743Swnj mp->mscp_unit = ui->ui_slave; 373*4743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 374*4743Swnj i = udaddr->udaip; /* initiate polling */ 375*4743Swnj return(1); /* wait for interrupt */ 376*4743Swnj } 377*4743Swnj mp->mscp_cmdref = (long)bp; /* pointer to get back */ 378*4743Swnj mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE; 379*4743Swnj mp->mscp_unit = ui->ui_slave; 380*4743Swnj mp->mscp_lbn = bp->b_blkno + ra_sizes[minor(bp->b_dev)&7].blkoff; 381*4743Swnj mp->mscp_bytecnt = bp->b_bcount; 382*4743Swnj mp->mscp_buffer = (i & 0x3ffff) | (((i>>28)&0xf)<<24); 383*4743Swnj #if defined(VAX750) 384*4743Swnj if (cpu == VAX_750) 385*4743Swnj i &= 0xfffffff; /* mask off bdp */ 386*4743Swnj #endif 387*4743Swnj bp->b_ubinfo = i; /* save mapping info */ 388*4743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 389*4743Swnj i = udaddr->udaip; /* initiate polling */ 390*4743Swnj if (ui->ui_dk >= 0) { 391*4743Swnj dk_busy |= 1<<ui->ui_dk; 392*4743Swnj dp->b_qsize++; 393*4743Swnj dk_xfer[ui->ui_dk]++; 394*4743Swnj dk_wds[ui->ui_dk] += bp->b_bcount>>6; 395*4743Swnj } 396*4743Swnj 397*4743Swnj /* 398*4743Swnj * Move drive to the end of the controller queue 399*4743Swnj */ 400*4743Swnj if (dp->b_forw != NULL) { 401*4743Swnj um->um_tab.b_actf = dp->b_forw; 402*4743Swnj um->um_tab.b_actl->b_forw = dp; 403*4743Swnj um->um_tab.b_actl = dp; 404*4743Swnj dp->b_forw = NULL; 405*4743Swnj } 406*4743Swnj /* 407*4743Swnj * Move buffer to I/O wait queue 408*4743Swnj */ 409*4743Swnj dp->b_actf = bp->av_forw; 410*4743Swnj dp = &udwtab[um->um_ctlr]; 411*4743Swnj bp->av_forw = dp; 412*4743Swnj bp->av_back = dp->av_back; 413*4743Swnj dp->av_back->av_forw = bp; 414*4743Swnj dp->av_back = bp; 415*4743Swnj goto loop; 416*4743Swnj } 417*4743Swnj 418*4743Swnj /* 419*4743Swnj * UDA interrupt routine. 420*4743Swnj */ 421*4743Swnj udintr(d) 422*4743Swnj int d; 423*4743Swnj { 424*4743Swnj register struct uba_ctlr *um = udminfo[d]; 425*4743Swnj register struct udadevice *udaddr = (struct udadevice *)um->um_addr; 426*4743Swnj struct buf *bp; 427*4743Swnj register int i; 428*4743Swnj register struct uda_softc *sc = &uda_softc[d]; 429*4743Swnj register struct uda *ud = &uda[d]; 430*4743Swnj struct uda *uud; 431*4743Swnj struct mscp *mp; 432*4743Swnj 433*4743Swnj printd("udintr: state %d, udasa %o\n", sc->sc_state, udaddr->udasa); 434*4743Swnj switch (sc->sc_state) { 435*4743Swnj case S_IDLE: 436*4743Swnj printf("uda%d: random interrupt ignored\n", d); 437*4743Swnj return; 438*4743Swnj 439*4743Swnj case S_STEP1: 440*4743Swnj #define STEP1GOOD (UDA_STEP2|UDA_IE|(NCMDL2<<3)|NRSPL2) 441*4743Swnj if ((udaddr->udasa&(UDA_ERR|STEP1GOOD)) != STEP1GOOD) { 442*4743Swnj sc->sc_state = S_IDLE; 443*4743Swnj wakeup(um); 444*4743Swnj return; 445*4743Swnj } 446*4743Swnj udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)| 447*4743Swnj (cpu == VAX_780 ? UDA_PI : 0); 448*4743Swnj sc->sc_state = S_STEP2; 449*4743Swnj return; 450*4743Swnj 451*4743Swnj case S_STEP2: 452*4743Swnj #define STEP2GOOD (UDA_STEP3|UDA_IE|(sc->sc_ivec/4)) 453*4743Swnj if ((udaddr->udasa&(UDA_ERR|STEP2GOOD)) != STEP2GOOD) { 454*4743Swnj sc->sc_state = S_IDLE; 455*4743Swnj wakeup(um); 456*4743Swnj return; 457*4743Swnj } 458*4743Swnj udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)>>16; 459*4743Swnj sc->sc_state = S_STEP3; 460*4743Swnj return; 461*4743Swnj 462*4743Swnj case S_STEP3: 463*4743Swnj #define STEP3GOOD UDA_STEP4 464*4743Swnj if ((udaddr->udasa&(UDA_ERR|STEP3GOOD)) != STEP3GOOD) { 465*4743Swnj sc->sc_state = S_IDLE; 466*4743Swnj wakeup(um); 467*4743Swnj return; 468*4743Swnj } 469*4743Swnj udaddr->udasa = UDA_GO; 470*4743Swnj sc->sc_state = S_SCHAR; 471*4743Swnj 472*4743Swnj /* 473*4743Swnj * Initialize the data structures. 474*4743Swnj */ 475*4743Swnj uud = sc->sc_uda; 476*4743Swnj for (i = 0; i < NRSP; i++) { 477*4743Swnj ud->uda_ca.ca_rspdsc[i] = UDA_OWN|UDA_INT| 478*4743Swnj (long)&uud->uda_rsp[i].mscp_cmdref; 479*4743Swnj ud->uda_rsp[i].mscp_dscptr = &ud->uda_ca.ca_rspdsc[i]; 480*4743Swnj ud->uda_rsp[i].mscp_header.uda_msglen = sizeof (struct mscp); 481*4743Swnj } 482*4743Swnj for (i = 0; i < NCMD; i++) { 483*4743Swnj ud->uda_ca.ca_cmddsc[i] = UDA_INT| 484*4743Swnj (long)&uud->uda_cmd[i].mscp_cmdref; 485*4743Swnj ud->uda_cmd[i].mscp_dscptr = &ud->uda_ca.ca_cmddsc[i]; 486*4743Swnj ud->uda_cmd[i].mscp_header.uda_msglen = sizeof (struct mscp); 487*4743Swnj } 488*4743Swnj bp = &udwtab[d]; 489*4743Swnj bp->av_forw = bp->av_back = bp; 490*4743Swnj sc->sc_lastcmd = 0; 491*4743Swnj sc->sc_lastrsp = 0; 492*4743Swnj if ((mp = udgetcp(um)) == NULL) { 493*4743Swnj sc->sc_state = S_IDLE; 494*4743Swnj wakeup(um); 495*4743Swnj return; 496*4743Swnj } 497*4743Swnj mp->mscp_opcode = M_OP_STCON; 498*4743Swnj mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS; 499*4743Swnj *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; 500*4743Swnj i = udaddr->udaip; /* initiate polling */ 501*4743Swnj return; 502*4743Swnj 503*4743Swnj case S_SCHAR: 504*4743Swnj case S_RUN: 505*4743Swnj break; 506*4743Swnj 507*4743Swnj default: 508*4743Swnj printf("uda%d: interrupt in unknown state %d ignored\n", 509*4743Swnj d, sc->sc_state); 510*4743Swnj return; 511*4743Swnj } 512*4743Swnj 513*4743Swnj if (udaddr->udasa&UDA_ERR) { 514*4743Swnj printf("uda%d: fatal error (%o)\n", d, udaddr->udasa&0xffff); 515*4743Swnj udaddr->udaip = 0; 516*4743Swnj wakeup(um); 517*4743Swnj } 518*4743Swnj 519*4743Swnj /* 520*4743Swnj * Check for a buffer purge request. 521*4743Swnj */ 522*4743Swnj if (ud->uda_ca.ca_bdp) { 523*4743Swnj /* 524*4743Swnj * THIS IS A KLUDGE. 525*4743Swnj * Maybe we should change the entire 526*4743Swnj * UBA interface structure. 527*4743Swnj */ 528*4743Swnj int s = spl7(); 529*4743Swnj 530*4743Swnj i = um->um_ubinfo; 531*4743Swnj printd("uda: purge bdp %d\n", ud->uda_ca.ca_bdp); 532*4743Swnj um->um_ubinfo = ud->uda_ca.ca_bdp<<28; 533*4743Swnj ubapurge(um); 534*4743Swnj um->um_ubinfo = i; 535*4743Swnj (void) splx(s); 536*4743Swnj ud->uda_ca.ca_bdp = 0; 537*4743Swnj udaddr->udasa = 0; /* signal purge complete */ 538*4743Swnj } 539*4743Swnj 540*4743Swnj /* 541*4743Swnj * Check for response ring transition. 542*4743Swnj */ 543*4743Swnj if (ud->uda_ca.ca_rspint) { 544*4743Swnj ud->uda_ca.ca_rspint = 0; 545*4743Swnj for (i = sc->sc_lastrsp;; i++) { 546*4743Swnj i %= NRSP; 547*4743Swnj if (ud->uda_ca.ca_rspdsc[i]&UDA_OWN) 548*4743Swnj break; 549*4743Swnj udrsp(um, ud, sc, i); 550*4743Swnj ud->uda_ca.ca_rspdsc[i] |= UDA_OWN; 551*4743Swnj } 552*4743Swnj sc->sc_lastrsp = i; 553*4743Swnj } 554*4743Swnj 555*4743Swnj /* 556*4743Swnj * Check for command ring transition. 557*4743Swnj */ 558*4743Swnj if (ud->uda_ca.ca_cmdint) { 559*4743Swnj printd("uda: command ring transition\n"); 560*4743Swnj ud->uda_ca.ca_cmdint = 0; 561*4743Swnj } 562*4743Swnj udstart(um); 563*4743Swnj } 564*4743Swnj 565*4743Swnj /* 566*4743Swnj * Process a response packet 567*4743Swnj */ 568*4743Swnj udrsp(um, ud, sc, i) 569*4743Swnj register struct uba_ctlr *um; 570*4743Swnj register struct uda *ud; 571*4743Swnj register struct uda_softc *sc; 572*4743Swnj int i; 573*4743Swnj { 574*4743Swnj register struct mscp *mp; 575*4743Swnj struct uba_device *ui; 576*4743Swnj struct buf *dp, *bp; 577*4743Swnj int st; 578*4743Swnj 579*4743Swnj mp = &ud->uda_rsp[i]; 580*4743Swnj mp->mscp_header.uda_msglen = sizeof (struct mscp); 581*4743Swnj sc->sc_credits += mp->mscp_header.uda_credits & 0xf; 582*4743Swnj if ((mp->mscp_header.uda_credits & 0xf0) > 0x10) 583*4743Swnj return; 584*4743Swnj /* 585*4743Swnj * If it's an error log message (datagram), 586*4743Swnj * pass it on for more extensive processing. 587*4743Swnj */ 588*4743Swnj if ((mp->mscp_header.uda_credits & 0xf0) == 0x10) { 589*4743Swnj uderror(um, (struct mslg *)mp); 590*4743Swnj return; 591*4743Swnj } 592*4743Swnj if (mp->mscp_unit >= 8) 593*4743Swnj return; 594*4743Swnj if ((ui = udip[um->um_ctlr][mp->mscp_unit]) == 0) 595*4743Swnj return; 596*4743Swnj st = mp->mscp_status&M_ST_MASK; 597*4743Swnj switch (mp->mscp_opcode) { 598*4743Swnj case M_OP_STCON|M_OP_END: 599*4743Swnj if (st == M_ST_SUCC) 600*4743Swnj sc->sc_state = S_RUN; 601*4743Swnj else 602*4743Swnj sc->sc_state = S_IDLE; 603*4743Swnj um->um_tab.b_active = 0; 604*4743Swnj wakeup(um); 605*4743Swnj break; 606*4743Swnj 607*4743Swnj case M_OP_ONLIN|M_OP_END: 608*4743Swnj /* 609*4743Swnj * Link the drive onto the controller queue 610*4743Swnj */ 611*4743Swnj dp = &udutab[ui->ui_unit]; 612*4743Swnj dp->b_forw = NULL; 613*4743Swnj if (um->um_tab.b_actf == NULL) 614*4743Swnj um->um_tab.b_actf = dp; 615*4743Swnj else 616*4743Swnj um->um_tab.b_actl->b_forw = dp; 617*4743Swnj um->um_tab.b_actl = dp; 618*4743Swnj if (st == M_ST_SUCC) { 619*4743Swnj ui->ui_flags = 1; /* mark it online */ 620*4743Swnj radsize[ui->ui_unit] = (daddr_t)mp->mscp_untsize; 621*4743Swnj printd("uda: unit %d online\n", mp->mscp_unit); 622*4743Swnj } else { 623*4743Swnj harderr(dp->b_actf, "ra"); 624*4743Swnj printf("OFFLINE\n"); 625*4743Swnj while (bp = dp->b_actf) { 626*4743Swnj dp->b_actf = bp->av_forw; 627*4743Swnj bp->b_flags |= B_ERROR; 628*4743Swnj iodone(bp); 629*4743Swnj } 630*4743Swnj } 631*4743Swnj dp->b_active = 1; 632*4743Swnj break; 633*4743Swnj 634*4743Swnj case M_OP_AVATN: 635*4743Swnj printd("uda: unit %d attention\n", mp->mscp_unit); 636*4743Swnj ui->ui_flags = 0; /* it went offline and we didn't notice */ 637*4743Swnj break; 638*4743Swnj 639*4743Swnj case M_OP_READ|M_OP_END: 640*4743Swnj case M_OP_WRITE|M_OP_END: 641*4743Swnj bp = (struct buf *)mp->mscp_cmdref; 642*4743Swnj ubarelse(um->um_ubanum, &bp->b_resid); 643*4743Swnj /* 644*4743Swnj * Unlink buffer from I/O wait queue. 645*4743Swnj */ 646*4743Swnj bp->av_back->av_forw = bp->av_forw; 647*4743Swnj bp->av_forw->av_back = bp->av_back; 648*4743Swnj dp = &udutab[ui->ui_unit]; 649*4743Swnj if (ui->ui_dk >= 0) 650*4743Swnj if (--dp->b_qsize == 0) 651*4743Swnj dk_busy &= ~(1<<ui->ui_dk); 652*4743Swnj if (st == M_ST_OFFLN || st == M_ST_AVLBL) { 653*4743Swnj ui->ui_flags = 0; /* mark unit offline */ 654*4743Swnj /* 655*4743Swnj * Link the buffer onto the front of the drive queue 656*4743Swnj */ 657*4743Swnj if ((bp->av_forw = dp->b_actf) == 0) 658*4743Swnj dp->b_actl = bp; 659*4743Swnj dp->b_actf = bp; 660*4743Swnj /* 661*4743Swnj * Link the drive onto the controller queue 662*4743Swnj */ 663*4743Swnj if (dp->b_active == 0) { 664*4743Swnj dp->b_forw = NULL; 665*4743Swnj if (um->um_tab.b_actf == NULL) 666*4743Swnj um->um_tab.b_actf = dp; 667*4743Swnj else 668*4743Swnj um->um_tab.b_actl->b_forw = dp; 669*4743Swnj um->um_tab.b_actl = dp; 670*4743Swnj dp->b_active = 1; 671*4743Swnj } 672*4743Swnj return; 673*4743Swnj } 674*4743Swnj if (st != M_ST_SUCC) { 675*4743Swnj harderr(bp, "ra"); 676*4743Swnj printf("status %o\n", mp->mscp_status); 677*4743Swnj bp->b_flags |= B_ERROR; 678*4743Swnj } 679*4743Swnj bp->b_resid = bp->b_bcount - mp->mscp_bytecnt; 680*4743Swnj iodone(bp); 681*4743Swnj break; 682*4743Swnj 683*4743Swnj case M_OP_GTUNT|M_OP_END: 684*4743Swnj break; 685*4743Swnj 686*4743Swnj default: 687*4743Swnj printf("uda: unknown packet\n"); 688*4743Swnj } 689*4743Swnj } 690*4743Swnj 691*4743Swnj 692*4743Swnj /* 693*4743Swnj * Process an error log message 694*4743Swnj * 695*4743Swnj * For now, just log the error on the console. 696*4743Swnj * Only minimal decoding is done, only "useful" 697*4743Swnj * information is printed. Eventually should 698*4743Swnj * send message to an error logger. 699*4743Swnj */ 700*4743Swnj uderror(um, mp) 701*4743Swnj register struct uba_ctlr *um; 702*4743Swnj register struct mslg *mp; 703*4743Swnj { 704*4743Swnj printf("uda%d:%d: %s error, ", um->um_ctlr, mp->mslg_seqnum, 705*4743Swnj mp->mslg_flags&M_LF_SUCC ? "soft" : "hard"); 706*4743Swnj switch (mp->mslg_format) { 707*4743Swnj case M_FM_CNTERR: 708*4743Swnj printf("controller error, event 0%o\n", mp->mslg_event); 709*4743Swnj break; 710*4743Swnj 711*4743Swnj case M_FM_BUSADDR: 712*4743Swnj printf("host memory access error, event 0%o, addr 0%o\n", 713*4743Swnj mp->mslg_event, *((long *)&mp->mslg_busaddr[0])); 714*4743Swnj break; 715*4743Swnj 716*4743Swnj case M_FM_DISKTRN: 717*4743Swnj printf("disk transfer error, unit %d, grp %d, cyl %d, sec %d, ", 718*4743Swnj mp->mslg_unit, mp->mslg_group, mp->mslg_cylinder, 719*4743Swnj mp->mslg_sector); 720*4743Swnj printf("trk %d, lbn %d, retry %d, level %d\n", mp->mslg_track, 721*4743Swnj mp->mslg_lbn, mp->mslg_retry, mp->mslg_level); 722*4743Swnj break; 723*4743Swnj 724*4743Swnj case M_FM_SDI: 725*4743Swnj printf("SDI error, unit %d, event 0%o, cyl %d\n", mp->mslg_unit, 726*4743Swnj mp->mslg_event, mp->mslg_cylinder); 727*4743Swnj break; 728*4743Swnj 729*4743Swnj case M_FM_SMLDSK: 730*4743Swnj printf("small disk error, unit %d, event 0%o, cyl %d\n", 731*4743Swnj mp->mslg_unit, mp->mslg_event, mp->mslg_sdecyl); 732*4743Swnj break; 733*4743Swnj 734*4743Swnj default: 735*4743Swnj printf("unknown error, unit %d, format 0%o, event 0%o\n", 736*4743Swnj mp->mslg_unit, mp->mslg_format, mp->mslg_event); 737*4743Swnj } 738*4743Swnj } 739*4743Swnj 740*4743Swnj 741*4743Swnj /* 742*4743Swnj * Find an unused command packet 743*4743Swnj */ 744*4743Swnj struct mscp * 745*4743Swnj udgetcp(um) 746*4743Swnj struct uba_ctlr *um; 747*4743Swnj { 748*4743Swnj register struct mscp *mp; 749*4743Swnj register struct udaca *cp; 750*4743Swnj register struct uda_softc *sc; 751*4743Swnj register int i; 752*4743Swnj 753*4743Swnj cp = &uda[um->um_ctlr].uda_ca; 754*4743Swnj sc = &uda_softc[um->um_ctlr]; 755*4743Swnj i = sc->sc_lastcmd; 756*4743Swnj if ((cp->ca_cmddsc[i] & (UDA_OWN|UDA_INT)) == UDA_INT) { 757*4743Swnj cp->ca_cmddsc[i] &= ~UDA_INT; 758*4743Swnj mp = &uda[um->um_ctlr].uda_cmd[i]; 759*4743Swnj mp->mscp_unit = mp->mscp_modifier = 0; 760*4743Swnj mp->mscp_opcode = mp->mscp_flags = 0; 761*4743Swnj mp->mscp_bytecnt = mp->mscp_buffer = 0; 762*4743Swnj mp->mscp_errlgfl = mp->mscp_copyspd = 0; 763*4743Swnj sc->sc_lastcmd = (i + 1) % NCMD; 764*4743Swnj return(mp); 765*4743Swnj } 766*4743Swnj return(NULL); 767*4743Swnj } 768*4743Swnj 769*4743Swnj udread(dev) 770*4743Swnj dev_t dev; 771*4743Swnj { 772*4743Swnj register int unit = minor(dev) >> 3; 773*4743Swnj 774*4743Swnj if (unit >= NRA) 775*4743Swnj u.u_error = ENXIO; 776*4743Swnj else 777*4743Swnj physio(udstrategy, &rudbuf[unit], dev, B_READ, minphys); 778*4743Swnj } 779*4743Swnj 780*4743Swnj udwrite(dev) 781*4743Swnj dev_t dev; 782*4743Swnj { 783*4743Swnj register int unit = minor(dev) >> 3; 784*4743Swnj 785*4743Swnj if (unit >= NRA) 786*4743Swnj u.u_error = ENXIO; 787*4743Swnj else 788*4743Swnj physio(udstrategy, &rudbuf[unit], dev, B_WRITE, minphys); 789*4743Swnj } 790*4743Swnj 791*4743Swnj udreset(uban) 792*4743Swnj int uban; 793*4743Swnj { 794*4743Swnj register struct uba_ctlr *um; 795*4743Swnj register struct uba_device *ui; 796*4743Swnj register struct buf *bp, *dp; 797*4743Swnj register int unit; 798*4743Swnj struct buf *nbp; 799*4743Swnj int d; 800*4743Swnj 801*4743Swnj for (d = 0; d < NUDA; d++) { 802*4743Swnj if ((um = udminfo[d]) == 0 || um->um_ubanum != uban || 803*4743Swnj um->um_alive == 0) 804*4743Swnj continue; 805*4743Swnj printf(" uda%d", d); 806*4743Swnj um->um_tab.b_active = 0; 807*4743Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 808*4743Swnj uda_softc[d].sc_state = S_IDLE; 809*4743Swnj for (unit = 0; unit < NRA; unit++) { 810*4743Swnj if ((ui = uddinfo[unit]) == 0) 811*4743Swnj continue; 812*4743Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 813*4743Swnj continue; 814*4743Swnj udutab[unit].b_active = 0; 815*4743Swnj udutab[unit].b_qsize = 0; 816*4743Swnj } 817*4743Swnj for (bp = udwtab[d].av_forw; bp != &udwtab[d]; bp = nbp) { 818*4743Swnj nbp = bp->av_forw; 819*4743Swnj ubarelse(uban, &bp->b_ubinfo); 820*4743Swnj /* 821*4743Swnj * Link the buffer onto the drive queue 822*4743Swnj */ 823*4743Swnj dp = &udutab[dkunit(bp)]; 824*4743Swnj if (dp->b_actf == 0) 825*4743Swnj dp->b_actf = bp; 826*4743Swnj else 827*4743Swnj dp->b_actl->av_forw = bp; 828*4743Swnj dp->b_actl = bp; 829*4743Swnj bp->av_forw = 0; 830*4743Swnj /* 831*4743Swnj * Link the drive onto the controller queue 832*4743Swnj */ 833*4743Swnj if (dp->b_active == 0) { 834*4743Swnj dp->b_forw = NULL; 835*4743Swnj if (um->um_tab.b_actf == NULL) 836*4743Swnj um->um_tab.b_actf = dp; 837*4743Swnj else 838*4743Swnj um->um_tab.b_actl->b_forw = dp; 839*4743Swnj um->um_tab.b_actl = dp; 840*4743Swnj dp->b_active = 1; 841*4743Swnj } 842*4743Swnj } 843*4743Swnj udinit(d); 844*4743Swnj } 845*4743Swnj } 846*4743Swnj 847*4743Swnj uddump() 848*4743Swnj { 849*4743Swnj return(ENXIO); 850*4743Swnj } 851