📄 kdb.c
字号:
return (-1); } } if ((ka->kdb_sa & STEP0MASK) != KDB_STEP1) { printf("kdb%d: init failed, sa=%b\n", ki->ki_ctlr, ka->kdb_sa, kdbsr_bits); return (-1); } /* * Success! Record new state, and start step 1 initialisation. * The rest is done in the interrupt handler. */ ki->ki_state = ST_STEP1; ka->kdb_bi.bi_intrdes = 1 << mastercpu;#ifdef unneeded /* is it? */ ka->kdb_bi.bi_csr = (ka->kdb_bi.bi_csr&~BICSR_ARB_MASK)|BICSR_ARB_???;#endif ka->kdb_bi.bi_bcicsr |= BCI_STOPEN | BCI_IDENTEN | BCI_UINTEN | BCI_INTEN;/* I THINK THIS IS WRONG *//* Mach uses 0x601d0, which includes IPL16, but 1d0 is IPL17, nexzvec...? */ ka->kdb_bi.bi_eintrcsr = BIEIC_IPL15 | ki->ki_vec; /* ??? *//* END I THINK WRONG */ ka->kdb_bi.bi_uintrcsr = ki->ki_vec; ka->kdb_sw = KDB_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | KDB_IE | (ki->ki_vec >> 2); return (0);}/* * Open a drive. *//*ARGSUSED*/kdbopen(dev, flag) dev_t dev; int flag;{ register int unit; register struct uba_device *ui; register struct kdbinfo *ki; int s; /* * Make sure this is a reasonable open request. */ unit = kdbunit(dev); if (unit >= NKRA || (ui = kdbdinfo[unit]) == 0 || ui->ui_alive == 0) return (ENXIO); /* * Make sure the controller is running, by (re)initialising it if * necessary. */ ki = &kdbinfo[ui->ui_ctlr]; s = spl5(); if (ki->ki_state != ST_RUN) { if (ki->ki_state == ST_IDLE && kdbinit(ki)) { splx(s); return (EIO); } /* * In case it does not come up, make sure we will be * restarted in 10 seconds. This corresponds to the * 10 second timeouts in kdbprobe() and kdbslave(). */ ki->ki_flags |= KDB_DOWAKE; timeout(wakeup, (caddr_t)&ki->ki_flags, 10 * hz); sleep((caddr_t)&ki->ki_flags, PRIBIO); if (ki->ki_state != ST_RUN) { splx(s); printf("kdb%d: controller hung\n", ui->ui_ctlr); return (EIO); } untimeout(wakeup, (caddr_t)&ki->ki_flags); } if ((ui->ui_flags & UNIT_ONLINE) == 0) { /* * Bring the drive on line so we can find out how * big it is. If it is not spun up, it will not * come on line; this cannot really be considered * an `error condition'. */ if (kdb_bringonline(ui, 0)) { splx(s); printf("%s%d: drive will not come on line\n", kdbdriver.ud_dname, unit); return (EIO); } } splx(s); return (0);}/* * Bring a drive on line. In case it fails to respond, we set * a timeout on it. The `nosleep' parameter should be set if * we are to spin-wait; otherwise this must be called at spl5(). */kdb_bringonline(ui, nosleep) register struct uba_device *ui; int nosleep;{ register struct kdbinfo *ki = &kdbinfo[ui->ui_ctlr]; register struct mscp *mp; int i; if (nosleep) { mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT); if (mp == NULL) return (-1); } else mp = mscp_getcp(&ki->ki_mi, MSCP_WAIT); mp->mscp_opcode = M_OP_ONLINE; mp->mscp_unit = ui->ui_slave; mp->mscp_cmdref = (long)&ui->ui_flags; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; i = ki->ki_kdb->kdb_ip; if (nosleep) { i = todr() + 1000; while ((ui->ui_flags & UNIT_ONLINE) == 0) if (todr() > i) return (-1); } else { timeout(wakeup, (caddr_t)&ui->ui_flags, 10 * hz); sleep((caddr_t)&ui->ui_flags, PRIBIO); if ((ui->ui_flags & UNIT_ONLINE) == 0) return (-1); untimeout(wakeup, (caddr_t)&ui->ui_flags); } return (0); /* made it */}/* * Queue a transfer request, and if possible, hand it to the controller. * * This routine is broken into two so that the internal version * kdbstrat1() can be called by the (nonexistent, as yet) bad block * revectoring routine. */kdbstrategy(bp) register struct buf *bp;{ register int unit; register struct uba_device *ui; register struct size *st; daddr_t sz, maxsz; /* * Make sure this is a reasonable drive to use. */ if ((unit = kdbunit(bp->b_dev)) >= NKRA || (ui = kdbdinfo[unit]) == NULL || ui->ui_alive == 0) { bp->b_error = ENXIO; bp->b_flags |= B_ERROR; biodone(bp); return; } /* * Determine the size of the transfer, and make sure it is * within the boundaries of the drive. */ sz = (bp->b_bcount + 511) >> 9; st = &kdbtypes[ui->ui_type].ut_sizes[kdbpart(bp->b_dev)]; if ((maxsz = st->nblocks) < 0) maxsz = ra_dsize[unit] - st->blkoff; if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz || st->blkoff >= ra_dsize[unit]) { /* if exactly at end of disk, return an EOF */ if (bp->b_blkno == maxsz) bp->b_resid = bp->b_bcount; else { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; } biodone(bp); return; } kdbstrat1(bp);}/* * Work routine for kdbstrategy. */kdbstrat1(bp) register struct buf *bp;{ register int unit = kdbunit(bp->b_dev); register struct buf *dp; register struct kdbinfo *ki; struct uba_device *ui; int s; /* * Append the buffer to the drive queue, and if it is not * already there, the drive to the controller queue. (However, * if the drive queue is marked to be requeued, we must be * awaiting an on line or get unit status command; in this * case, leave it off the controller queue.) */ ui = kdbdinfo[unit]; ki = &kdbinfo[ui->ui_ctlr]; dp = &kdbutab[unit]; s = spl5(); APPEND(bp, dp, av_forw); if (dp->b_active == 0 && (ui->ui_flags & UNIT_REQUEUE) == 0) { APPEND(dp, &ki->ki_tab, b_forw); dp->b_active++; } /* * Start activity on the controller. */ kdbstart(ki); splx(s);}/* * Find the physical address of some contiguous PTEs that map the * transfer described in `bp', creating them (by copying) if * necessary. Store the physical base address of the map through * mapbase, and the page offset through offset, and any resource * information in *info (or 0 if none). * * If we cannot allocate space, return a nonzero status. */intkdbmap(ki, bp, mapbase, offset, info) struct kdbinfo *ki; register struct buf *bp; long *mapbase, *offset; int *info;{ register struct pte *spte, *dpte; register struct proc *rp; register int i, a, o; u_int v; int npf; o = (int)bp->b_un.b_addr & PGOFSET; /* handle contiguous cases */ if ((bp->b_flags & B_PHYS) == 0) { spte = kvtopte(bp->b_un.b_addr); kdbstats.ks_sys++; *mapbase = PHYS(long, spte); *offset = o; *info = 0; return (0); } if (bp->b_flags & B_PAGET) { spte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];if (spte->pg_v == 0) panic("kdbmap"); kdbstats.ks_paget++; *mapbase = PHYS(long, spte); *offset = o; *info = 0; return (0); } /* potentially discontiguous or invalid ptes */ v = btop(bp->b_un.b_addr); rp = bp->b_flags & B_DIRTY ? &proc[2] : bp->b_proc; if (bp->b_flags & B_UAREA) spte = &rp->p_addr[v]; else spte = vtopte(rp, v); npf = btoc(bp->b_bcount + o);#ifdef notdef /* * The current implementation of the VM system requires * that all of these be done with a copy. Even if the * PTEs could be used now, they may be snatched out from * under us later. It would be nice if we could stop that.... */ /* check for invalid */ /* CONSIDER CHANGING VM TO VALIDATE PAGES EARLIER */ for (dpte = spte, i = npf; --i >= 0; dpte++) if (dpte->pg_v == 0) goto copy1; /* * Check for discontiguous physical pte addresses. It is * not necessary to check each pte, since they come in clumps * of pages. */ i = howmany(npf + (((int)spte & PGOFSET) / sizeof (*spte)), NPTEPG); /* often i==1, and we can avoid work */ if (--i > 0) { dpte = kvtopte(spte); a = dpte->pg_pfnum; while (--i >= 0) if ((++dpte)->pg_pfnum != ++a) goto copy2; } /* made it */ kdbstats.ks_contig++; *mapbase = kvtophys(spte); *offset = o; *info = 0; return (0);copy1: kdbstats.ks_inval++; /* temp */copy2:#endif /* notdef */ kdbstats.ks_copies++; i = npf + 1; if ((a = rmalloc(ki->ki_map, (long)i)) == 0) { kdbstats.ks_mapwait++; return (-1); } *info = (i << 16) | a; a--; /* if offset > PGOFSET, btop(offset) indexes mapbase */ *mapbase = ki->ki_ptephys; *offset = (a << PGSHIFT) | o; dpte = &ki->ki_pte[a]; while (--i > 0) *(int *)dpte++ = PG_V | *(int *)spte++; *(int *)dpte = 0; return (0);}#define KDBFREE(ki, info) if (info) \ rmfree((ki)->ki_map, (long)((info) >> 16), (long)((info) & 0xffff))/* * Start up whatever transfers we can find. * Note that kdbstart() must be called at spl5(). */kdbstart(ki) register struct kdbinfo *ki;{ register struct buf *bp, *dp; register struct mscp *mp; register struct uba_device *ui; long mapbase, offset; int info, ncmd = 0; /* * If it is not running, try (again and again...) to initialise * it. If it is currently initialising just ignore it for now. */ if (ki->ki_state != ST_RUN) { if (ki->ki_state == ST_IDLE && kdbinit(ki)) printf("kdb%d: still hung\n", ki->ki_ctlr); return; }loop: /* if insufficient credit, avoid overhead */ if (ki->ki_mi.mi_credits <= MSCP_MINCREDITS) goto out; /* * Service the drive at the head of the queue. It may not * need anything; eventually this will finish up the close * protocol, but that is yet to be implemented here. */ if ((dp = ki->ki_tab.b_actf) == NULL) goto out; if ((bp = dp->b_actf) == NULL) { dp->b_active = 0; ki->ki_tab.b_actf = dp->b_forw; goto loop; } if (ki->ki_kdb->kdb_sa & KDB_ERR) { /* ctlr fatal error */ kdbsaerror(ki); goto out; } /* find or create maps for this transfer */ if (kdbmap(ki, bp, &mapbase, &offset, &info)) goto out; /* effectively, resource wait */ /* * Get an MSCP packet, then figure out what to do. If * we cannot get a command packet, the command ring may * be too small: We should have at least as many command * packets as credits, for best performance. */ if ((mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT)) == NULL) { if (ki->ki_mi.mi_credits > MSCP_MINCREDITS && (ki->ki_flags & KDB_GRIPED) == 0) { log(LOG_NOTICE, "kdb%d: command ring too small\n", ki->ki_ctlr); ki->ki_flags |= KDB_GRIPED;/* complain only once */ } KDBFREE(ki, info); goto out; } /* * Bring the drive on line if it is not already. Get its status * if we do not already have it. Otherwise just start the transfer. */ ui = kdbdinfo[kdbunit(bp->b_dev)]; if ((ui->ui_flags & UNIT_ONLINE) == 0) { mp->mscp_opcode = M_OP_ONLINE; goto common; } if ((ui->ui_flags & UNIT_HAVESTATUS) == 0) { mp->mscp_opcode = M_OP_GETUNITST;common:if (ui->ui_flags & UNIT_REQUEUE) panic("kdbstart"); /* * Take the drive off the controller queue. When the * command finishes, make sure the drive is requeued. * Give up any mapping (not needed now). This last is * not efficient, but is rare. */ KDBFREE(ki, info); ki->ki_tab.b_actf = dp->b_forw; dp->b_active = 0; ui->ui_flags |= UNIT_REQUEUE; mp->mscp_unit = ui->ui_slave; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; ncmd++; goto loop; } mp->mscp_opcode = (bp->b_flags & B_READ) ? M_OP_READ : M_OP_WRITE; mp->mscp_unit = ui->ui_slave; mp->mscp_seq.seq_lbn = bp->b_blkno + kdbtypes[ui->ui_type].ut_sizes[kdbpart(bp->b_dev)].blkoff; mp->mscp_seq.seq_bytecount = bp->b_bcount; mp->mscp_seq.seq_buffer = offset | KDB_MAP; mp->mscp_seq.seq_mapbase = mapbase; /* profile the drive */ if (ui->ui_dk >= 0) { dk_busy |= 1 << ui->ui_dk; dk_xfer[ui->ui_dk]++; dk_wds[ui->ui_dk] += bp->b_bcount >> 6; } /* * Fill in the rest of the MSCP packet and move the buffer to the * I/O wait queue. */ mscp_go(&ki->ki_mi, mp, info); ncmd++; /* note the transfer */ ki->ki_tab.b_active++; /* another one going */ goto loop;out: if (ncmd >= KS_MAXC) ncmd = KS_MAXC - 1; kdbstats.ks_cmd[ncmd]++; if (ncmd) /* start some transfers */ ncmd = ki->ki_kdb->kdb_ip;}/* ARGSUSED */kdbiodone(mi, bp, info) struct mscp_info *mi; struct buf *bp; int info;{ register struct kdbinfo *ki = &kdbinfo[mi->mi_ctlr]; KDBFREE(ki, info); biodone(bp); ki->ki_tab.b_active--; /* another one done */}/* * The error bit was set in the controller status register. Gripe, * reset the controller, requeue pending transfers. */kdbsaerror(ki) register struct kdbinfo *ki;{ printf("kdb%d: controller error, sa=%b\n", ki->ki_ctlr, ki->ki_kdb->kdb_sa, kdbsr_bits); mscp_requeue(&ki->ki_mi); (void) kdbinit(ki);}/* * Interrupt routine. Depending on the state of the controller, * continue initialisation, or acknowledge command and response * interrupts, and process responses. */kdbintr(ctlr) int ctlr;{ register struct kdbinfo *ki = &kdbinfo[ctlr]; register struct kdb_regs *kdbaddr = ki->ki_kdb; register struct mscp *mp; register int i; ki->ki_wticks = 0; /* reset interrupt watchdog */ /* * Combinations during steps 1, 2, and 3: STEPnMASK * corresponds to which bits should be tested; * STEPnGOOD corresponds to the pattern that should * appear after the interrupt from STEPn initialisation. * All steps test the bits in ALLSTEPS. */#define ALLSTEPS (KDB_ERR|KDB_STEP4|KDB_STEP3|KDB_STEP2|KDB_STEP1)#define STEP1MASK (ALLSTEPS | KDB_IE | KDB_NCNRMASK)#define STEP1GOOD (KDB_STEP2 | KDB_IE | (NCMDL2 << 3) | NRSPL2)#define STEP2MASK (ALLSTEPS | KDB_IE | KDB_IVECMASK)#define STEP2GOOD (KDB_STEP3 | KDB_IE | (ki->ki_vec >> 2))#define STEP3MASK ALLSTEPS#define STEP3GOOD KDB_STEP4 switch (ki->ki_state) { case ST_IDLE: /* * Ignore unsolicited interrupts. */ log(LOG_WARNING, "kdb%d: stray intr\n", ctlr); return; case ST_STEP1: /* * Begin step two initialisation. */ if ((kdbaddr->kdb_sa & STEP1MASK) != STEP1GOOD) { i = 1;initfailed: printf("kdb%d: init step %d failed, sa=%b\n", ctlr, i, kdbaddr->kdb_sa, kdbsr_bits); ki->ki_state = ST_IDLE; if (ki->ki_flags & KDB_DOWAKE) { ki->ki_flags &= ~KDB_DOWAKE; wakeup((caddr_t)&ki->ki_flags); } return; } kdbaddr->kdb_sw = PHYS(int, &ki->ki_ca.ca_rspdsc[0]); ki->ki_state = ST_STEP2; return; case ST_STEP2: /* * Begin step 3 initialisation. */ if ((kdbaddr->kdb_sa & STEP2MASK) != STEP2GOOD) { i = 2; goto initfailed; } kdbaddr->kdb_sw = PHYS(int, &ki->ki_ca.ca_rspdsc[0]) >> 16; ki->ki_state = ST_STEP3; return; case ST_STEP3: /* * Set controller characteristics (finish initialisation). */ if ((kdbaddr->kdb_sa & STEP3MASK) != STEP3GOOD) { i = 3; goto initfailed; } i = kdbaddr->kdb_sa & 0xff; if (i != ki->ki_micro) { ki->ki_micro = i; printf("kdb%d: version %d model %d\n", ctlr, i & 0xf, i >> 4); } kdbaddr->kdb_sw = KDB_GO; /* initialise hardware data structures */ for (i = 0, mp = ki->ki_rsp; i < NRSP; i++, mp++) { ki->ki_ca.ca_rspdsc[i] = MSCP_OWN | MSCP_INT | PHYS(long, &ki->ki_rsp[i].mscp_cmdref);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -