📄 bvp_subr.c
字号:
PCCB *pccb;u_long queno;{struct bvpregs *bvrg;u_long cmd_pend, cmd_off; switch ( queno ) { case MFREEQ: Pccb.cmd_pend |= M_freeq; break; case DFREEQ: Pccb.cmd_pend |= D_freeq; break; case CMDQ0: Pccb.cmd_pend |= C_cmdq_0; break; case CMDQ1: Pccb.cmd_pend |= C_cmdq_1; break; case CMDQ2: Pccb.cmd_pend |= C_cmdq_2; break; case CMDQ3: Pccb.cmd_pend |= C_cmdq_3; break; default: panic("bvp_qtrans: Invalid queue\n"); } bvrg = Pccb.port_regs; if (bvrg->bvp_pc & BVP_PC_OWN) { /* We don't own it */ return; } cmd_off = ffs(Pccb.cmd_pend); cmd_off--; /* Get bit position */ bvrg->bvp_pc = bvp_cmd[cmd_off].command; /* Issue command */ WBFLUSH Pccb.cmd_pend &= ~(1<<cmd_off);}/**//* * * * Name: bvp_timer * * Abstract: * * Inputs: * * * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: * */void bvp_timer( pccb )PCCB *pccb;{struct bvpregs *bvrg;u_long cmd_pend, cmd_off; bvrg = Pccb.port_regs; /* Port regs address */ if ( Pccb.cmd_pend != 0 ) { /* Have commands pending */ if ( (bvrg->bvp_pc & BVP_PC_OWN) == 0){ /* We own it */ cmd_off = ffs(Pccb.cmd_pend); cmd_off--; /* Get bit position */ bvrg->bvp_pc = bvp_cmd[cmd_off].command; /* Issue command */ WBFLUSH Pccb.cmd_pend &= ~(1<<cmd_off); } } timeout(bvp_timer,pccb,Pccb.poll_rate); /* Requeue timeout */}/**//* * * * Name: bvp_log_err * * Abstract: Log BVP port errors * * Inputs: * * pccb - Pointer to pccb for port * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: Error is logged. * */void bvp_log_error(pccb)PCCB *pccb;{struct bvpregs *bvrg;register struct el_rec *elrp;register struct el_bvp *elbod;int i,unit;u_char type; bvrg = Pccb.port_regs; cprintf("Port error: bvp_ps = %x\n", bvrg->bvp_ps); cprintf(" bvp_pe = %x\n", bvrg->bvp_pe); cprintf(" bvp_pd = %x\n", bvrg->bvp_pd); for (i = 0; i < nbvptypes; i++) { if (bvp_sw[i].type == Lpinfo.bvp_type) break; } if (i == nbvptypes) { /* Not found in BVP switch table */ panic("bvp_log_err: Invalid port type"); } if( (elrp = ealloc( (sizeof(struct el_bvp)), EL_PRIHIGH)) == EL_FULL) return; elbod = &elrp->el_body.elbvp; elbod->bvp_biic_typ = Pccb.nxv->biic_typ; elbod->bvp_biic_csr = Pccb.nxv->biic_ctrl; elbod->bvp_pcntl = bvrg->bvp_pc; elbod->bvp_pstatus = bvrg->bvp_ps; elbod->bvp_perr = bvrg->bvp_pe; elbod->bvp_pdata = bvrg->bvp_pd; LSUBID(elrp,ELCT_DCNTL,ELBI_BVP,bvp_sw[i].errlog_typ, Pccb.binode,Pccb.bvp_ctlr,bvrg->bvp_pe); EVALID(elrp);}/**//* * * * Name: bvp_port_error * * Abstract: Take action on port error. * * Inputs: * * pccb - Pointer to pccb for port in error * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: * */u_long bvp_port_error(pccb)PCCB *pccb;{struct bvpregs *bvrg;u_long errcode; bvrg = Pccb.port_regs; errcode = bvrg->bvp_ps & BVP_PS_ETYPE; switch( errcode ) { /* * Port operation continues */ case BVP_ETYPE_TBI: case BVP_ETYPE_EXC: case BVP_ETYPE_NFBI: return( RET_SUCCESS ); break; /* * This port is shutdown */ case BVP_ETYPE_FBI: case BVP_ETYPE_DSE: case BVP_ETYPE_PLE: bvp_disable( pccb, PF_PORTERROR ); return( RET_FAILURE ); break; /* * All ports are shutdown */ case BVP_ETYPE_AHE: bvp_disable( pccb, PF_PORTERROR ); return( RET_FAILURE ); break; default: break; }}/**//* * * * Name: bvp_reinit * * Abstract: * * Inputs: * * * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: * */void bvp_reinit( pccb )PCCB *pccb;{struct bvpregs *bvrg;u_long devtype;u_long bvp_status;int i,j,s,count; s = Splscs(); /* Raise IPL to SCS level */ Pccb.rip = 0; bvrg = Pccb.port_regs; bvp_init_blks( pccb ); /* Init PQB and PCCB */ if (bvp_init_port( pccb ) != RET_SUCCESS) { (void)splx(s); /* Lower IPL */ return; /* Init failed or no such port */ }/* * Issue port Enable instruction */ bvrg->bvp_pc = BVP_PC_OWN | BVP_CMD_ENAB; /* Enable the port */ WBFLUSH Wait_own_nr( bvrg ) /* Wait for PC own bit to reset */ bvp_status = bvrg->bvp_ps; if ( (bvp_status & BVP_PS_PST) != BVP_PSTATE_ENAB ) { (void)splx(s); /* Lower IPL */ return; } bvrg->bvp_ps = bvp_status & ~BVP_PS_OWN; /* Clear ownership bit */ WBFLUSH/* * Issue Read PIV instruction to turn on interrupts */ Bvpqb.piv = Pccb.ivec; /* Set in interrupt vector */ bvrg->bvp_pc = BVP_PC_OWN | BVP_CMD_RPIV; /* Read PIV command */ WBFLUSH Wait_own_nr( bvrg ) /* Wait for PC own bit to reset */ if (bvp_create_sys( pccb ) != RET_SUCCESS) { (void)splx(s); /* Lower IPL */ return; /* Failed to make system known */ } if(Pccb.poll_rate == 0) /* Set the rate for the polling */ Pccb.poll_rate = 2 * hz;/* *//* Start the timer running. The bvp_timer routine will check *//* for pending port commands and issuing one if possible. *//* */ if ( (Lpinfo.bvp_flags & BVP_TIM) == 0 ) { /* If timer not yet on */ Lpinfo.bvp_flags |= BVP_TIM; /* Indicate timer now on */ timeout(bvp_timer,pccb,Pccb.poll_rate); /* Start timer */ } (void)splx(s); /* Lower IPL */ return;}/**//* * * * Name: bvp_disable * * Abstract: * * Inputs: * * * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: * */void bvp_disable( pccb, reason )PCCB *pccb;u_long reason;{PB *pb;int s, lock;struct bvpregs *bvrg;u_long bvp_status;int count; if (Pccb.rip == 0) { /* If recovery not already in progress */ Pccb.rip = 1; /* Set recovery in progress */ /* Mark path as failed */ if( (pb = Pccb.pb) != (PB *)NULL ) { pb->pinfo.state = PS_PATH_FAILURE; pb->pinfo.reason = reason; } bvrg = Pccb.port_regs; bvp_status = bvrg->bvp_ps; /* Attempt graceful shutdown first. */ count = 0; if ( (( bvp_status & BVP_PS_OWN ) == 0) && ((bvp_status & BVP_PS_PST) == BVP_PSTATE_ENAB) ) { bvrg->bvp_pc = BVP_PC_OWN | BVP_CMD_SHUT; /* Issue Shutdown cmd */ WBFLUSH while ( count < DELAYONE ) { /* Wait for at most 1 second */ if ( ( bvrg->bvp_pc & BVP_PC_OWN) == 0 ) break; DELAY(200000) count = count + 1; } } if ( ( count == DELAYONE ) || ((bvp_status & BVP_PS_PST) != BVP_PSTATE_ENAB) ) { s = spl7(); if(Pccb.bidata->biinfo[Pccb.binode].lock == 0) { Pccb.bidata->biinfo[Pccb.binode].lock = 1; /* Set lock */ } else { /* Wait for unlock ?? */ } (void)splx(s); if( Pccb.bidata->biinfo[Pccb.binode].incarn == Pccb.incarn ) { (void)bisst(&Pccb.nxv->biic_ctrl); Pccb.bidata->biinfo[Pccb.binode].incarn++; } Pccb.incarn = Pccb.bidata->biinfo[Pccb.binode].incarn; s = spl7(); Pccb.bidata->biinfo[Pccb.binode].lock = 0; (void)splx(s); } if ( (Lpinfo.bvp_flags & BVP_TIM) != 0) { /* Turn off timer if on */ (void)untimeout(bvp_timer, pccb); Lpinfo.bvp_flags &= ~BVP_TIM; /* Timer now off */ } Kfork(&pccb->forkb, bvp_cleanup, pccb ) } return; /* If already forking then */ /* forget this request. */}/**//* * * * Name: bvp_cleanup * * Abstract: * * Inputs: * * * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: * */void bvp_cleanup( pccb )PCCB *pccb;{PB *pb;int s = Splscs(); bvp_proc_rsp( pccb ); /* Return remaining responses */ /* Remove and deallocate all packets on all port queues. * The queue is zeroed whenever the queue interlock can not * be obtained. This results in permanent loss of the entries * that had been on that queue. */ { register gvpbq *q, *qend; for( q = &Vpqb.cmdq0, qend = &Vpqb.rspq; q <= qend; ++q ) Flushq( pccb, q ) for( q = &Pccb.dfreeq, qend = &Pccb.mfreeq; q <= qend; ++q ) Flushq( pccb, q ) } if ( (pb = Pccb.pb) != (PB *)NULL ) /* If we have a path open */ scs_path_crash( Pccb.pb ); /* Notify SCS */ else Kfork(&pccb->forkb, bvp_reinit, pccb ) splx(s); return; /* Return from fork */}/**//* * * * Name: bvp_log_packet * * Abstract: * * Inputs: * * * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: * */void bvp_log_packet( pccb, pb, bvpppdbp, reason)PCCB *pccb;PB *pb;GVPPPDH *bvpppdbp;int reason;{}/**//* * * * Name: bvp_slave * * Abstract: This routine simply returns 0 indicating the drive * is offline. The class driver will configure the * drive on its own. * * Inputs: * * ui - Pointer to unibus device structure * nxv - Base address of controller * * * * Outputs: * * * * * * Return * Values: 0 * * * * * Side * Effects: * */bvp_slave( ui, nxv )struct uba_device *ui;struct bi_nodespace *nxv;{ return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -