📄 kdb.c
字号:
mp->mscp_addr = &ki->ki_ca.ca_rspdsc[i]; mp->mscp_msglen = MSCP_MSGLEN; } for (i = 0, mp = ki->ki_cmd; i < NCMD; i++, mp++) { ki->ki_ca.ca_cmddsc[i] = MSCP_INT | PHYS(long, &ki->ki_cmd[i].mscp_cmdref); mp->mscp_addr = &ki->ki_ca.ca_cmddsc[i]; mp->mscp_msglen = MSCP_MSGLEN; } /* * Before we can get a command packet, we need some * credits. Fake some up to keep mscp_getcp() happy, * get a packet, and cancel all credits (the right * number should come back in the response to the * SCC packet). */ ki->ki_mi.mi_credits = MSCP_MINCREDITS + 1; mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT); if (mp == NULL) /* `cannot happen' */ panic("kdbintr"); ki->ki_mi.mi_credits = 0; mp->mscp_opcode = M_OP_SETCTLRC; mp->mscp_unit = 0; mp->mscp_sccc.sccc_ctlrflags = M_CF_ATTN | M_CF_MISC | M_CF_THIS; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; i = kdbaddr->kdb_ip; ki->ki_state = ST_SETCHAR; return; case ST_SETCHAR: case ST_RUN: /* * Handle Set Ctlr Characteristics responses and operational * responses (via mscp_dorsp). */ break; default: log(LOG_ERR, "kdb%d: driver bug, state %d\n", ctlr, ki->ki_state); return; } if (kdbaddr->kdb_sa & KDB_ERR) {/* ctlr fatal error */ kdbsaerror(ki); return; } /* * Handle buffer purge requests. * KDB DOES NOT HAVE BDPs */ if (ki->ki_ca.ca_bdp) { printf("kdb%d: purge bdp %d\n", ctlr, ki->ki_ca.ca_bdp); panic("kdb purge"); } /* * Check for response and command ring transitions. */ if (ki->ki_ca.ca_rspint) { ki->ki_ca.ca_rspint = 0; mscp_dorsp(&ki->ki_mi); } if (ki->ki_ca.ca_cmdint) { ki->ki_ca.ca_cmdint = 0; MSCP_DOCMD(&ki->ki_mi); } if (ki->ki_tab.b_actf != NULL) kdbstart(ki);}/* * Handle an error datagram. All we do now is decode it. */kdbdgram(mi, mp) struct mscp_info *mi; struct mscp *mp;{ mscp_decodeerror(mi->mi_md->md_mname, mi->mi_ctlr, mp);}/* * The Set Controller Characteristics command finished. * Record the new state of the controller. */kdbctlrdone(mi, mp) struct mscp_info *mi; struct mscp *mp;{ register struct kdbinfo *ki = &kdbinfo[mi->mi_ctlr]; if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS) ki->ki_state = ST_RUN; else { printf("kdb%d: SETCTLRC failed, status 0x%x\n", ki->ki_ctlr, mp->mscp_status); ki->ki_state = ST_IDLE; } if (ki->ki_flags & KDB_DOWAKE) { ki->ki_flags &= ~KDB_DOWAKE; wakeup((caddr_t)&ki->ki_flags); }}/* * Received a response from an as-yet unconfigured drive. Configure it * in, if possible. */kdbunconf(mi, mp) struct mscp_info *mi; register struct mscp *mp;{ /* * If it is a slave response, copy it to kdbslavereply for * kdbslave() to look at. */ if (mp->mscp_opcode == (M_OP_GETUNITST | M_OP_END) && (kdbinfo[mi->mi_ctlr].ki_flags & KDB_INSLAVE) != 0) { kdbslavereply = *mp; return (MSCP_DONE); } /* * Otherwise, it had better be an available attention response. */ if (mp->mscp_opcode != M_OP_AVAILATTN) return (MSCP_FAILED); /* do what autoconf does */ return (MSCP_FAILED); /* not yet */}/* * A drive came on line. Check its type and size. Return DONE if * we think the drive is truly on line. In any case, awaken anyone * sleeping on the drive on-line-ness. */kdbonline(ui, mp) register struct uba_device *ui; struct mscp *mp;{ register int type; wakeup((caddr_t)&ui->ui_flags); if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("kdb%d: attempt to bring %s%d on line failed:", ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit); mscp_printevent(mp); return (MSCP_FAILED); } type = mp->mscp_onle.onle_drivetype; if (type >= NTYPES || kdbtypes[type].ut_name == 0) { printf("kdb%d: %s%d: unknown type %d\n", ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit, type); return (MSCP_FAILED); } /* * Note any change of types. Not sure if we should do * something special about them, or if so, what.... */ if (type != ui->ui_type) { printf("%s%d: changed types! was %s\n", kdbdriver.ud_dname, ui->ui_unit, kdbtypes[ui->ui_type].ut_name); ui->ui_type = type; } ra_dsize[ui->ui_unit] = (daddr_t) mp->mscp_onle.onle_unitsize; printf("%s%d: %s, size = %d sectors\n", kdbdriver.ud_dname, ui->ui_unit, kdbtypes[type].ut_name, ra_dsize[ui->ui_unit]); return (MSCP_DONE);}/* * We got some (configured) unit's status. Return DONE if it succeeded. */kdbgotstatus(ui, mp) register struct uba_device *ui; register struct mscp *mp;{ if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("kdb%d: attempt to get status for %s%d failed:", ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit); mscp_printevent(mp); return (MSCP_FAILED); } /* need to record later for bad block forwarding - for now, print */ printf("\%s%d: unit %d, nspt %d, group %d, ngpc %d, rctsize %d, nrpt %d, nrct %d\n", kdbdriver.ud_dname, ui->ui_unit, mp->mscp_unit, mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group, mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize, mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct); return (MSCP_DONE);}/* * A transfer failed. We get a chance to fix or restart it. * Need to write the bad block forwaring code first.... *//*ARGSUSED*/kdbioerror(ui, mp, bp) register struct uba_device *ui; register struct mscp *mp; struct buf *bp;{ if (mp->mscp_flags & M_EF_BBLKR) { /* * A bad block report. Eventually we will * restart this transfer, but for now, just * log it and give up. */ log(LOG_ERR, "%s%d: bad block report: %d%s\n", kdbdriver.ud_dname, ui->ui_unit, mp->mscp_seq.seq_lbn, mp->mscp_flags & M_EF_BBLKU ? " + others" : ""); } else { /* * What the heck IS a `serious exception' anyway? */ if (mp->mscp_flags & M_EF_SEREX) log(LOG_ERR, "%s%d: serious exception reported\n", kdbdriver.ud_dname, ui->ui_unit); } return (MSCP_FAILED);}#ifdef notyet/* * I/O controls. Not yet! */kdbioctl(dev, cmd, flag, data) dev_t dev; int cmd, flag; caddr_t data;{ int error = 0; register int unit = kdbunit(dev); if (unit >= NKRA || uddinfo[unit] == NULL) return (ENXIO); switch (cmd) { case KDBIOCREPLACE: /* * Initiate bad block replacement for the given LBN. * (Should we allow modifiers?) */ error = EOPNOTSUPP; break; case KDBIOCGMICRO: /* * Return the microcode revision for the KDB50 running * this drive. */ *(int *)data = kdbinfo[kdbdinfo[unit]->ui_ctlr].ki_micro; break; case KDBIOCGSIZE: /* * Return the size (in 512 byte blocks) of this * disk drive. */ *(daddr_t *)data = ra_dsize[unit]; break; default: error = EINVAL; break; } return (error);}#endif#ifdef notyet/* * Reset a KDB50 (self test and all). * What if it fails? */kdbreset(ki) register struct kdbinfo *ki;{ printf("reset kdb%d", ki->ki_ctlr); bi_selftest(&ki->ki_kdb.kdb_bi); ki->ki_state = ST_IDLE; rminit(ki->ki_map, (long)KI_PTES, (long)1, "kdb", KI_MAPSIZ); mscp_requeue(&ki->ki_mi); if (kdbinit(ctlr)) printf(" (hung)"); printf("\n");}#endif/* * Watchdog timer: If the controller is active, and no interrupts * have occurred for 30 seconds, assume it has gone away. */kdbwatch(){ register struct kdbinfo *ki; register int i; timeout(kdbwatch, (caddr_t)0, hz); /* every second */ for (i = 0, ki = kdbinfo; i < NKDB; i++, ki++) { if ((ki->ki_flags & KDB_ALIVE) == 0) continue; if (ki->ki_state == ST_IDLE) continue; if (ki->ki_state == ST_RUN && !ki->ki_tab.b_active) ki->ki_wticks = 0; else if (++ki->ki_wticks >= 30) { ki->ki_wticks = 0; printf("kdb%d: lost interrupt\n", i); /* kdbreset(ki); */ panic("kdb lost interrupt"); } }}/* * Do a panic dump. */#define DBSIZE 32 /* dump 16K at a time */struct kdbdumpspace { struct kdb1ca kd_ca; struct mscp kd_rsp; struct mscp kd_cmd;} kdbdumpspace;kdbdump(dev) dev_t dev;{ register struct kdbdumpspace *kd; register struct kdb_regs *k; register int i; struct uba_device *ui; char *start; int num, blk, unit, maxsz, blkoff; /* * Make sure the device is a reasonable place on which to dump. */ unit = kdbunit(dev); if (unit >= NKRA) return (ENXIO); ui = PHYS(struct uba_device *, kdbdinfo[unit]); if (ui == NULL || ui->ui_alive == 0) return (ENXIO); /* * Find and initialise the KDB; get the physical address of the * device registers, and of communications area and command and * response packet. */ k = PHYS(struct kdbinfo *, &kdbinfo[ui->ui_ctlr])->ki_physkdb; kd = PHYS(struct kdbdumpspace *, &kdbdumpspace); /* * Initialise the controller, with one command and one response * packet. */ bi_reset(&k->kdb_bi); if (kdbdumpwait(k, KDB_STEP1)) return (EFAULT); k->kdb_sw = KDB_ERR; if (kdbdumpwait(k, KDB_STEP2)) return (EFAULT); k->kdb_sw = (int)&kd->kd_ca.ca_rspdsc; if (kdbdumpwait(k, KDB_STEP3)) return (EFAULT); k->kdb_sw = ((int)&kd->kd_ca.ca_rspdsc) >> 16; if (kdbdumpwait(k, KDB_STEP4)) return (EFAULT); k->kdb_sw = KDB_GO; /* * Set up the command and response descriptor, then set the * controller characteristics and bring the drive on line. * Note that all uninitialised locations in kd_cmd are zero. */ kd->kd_ca.ca_rspdsc = (long)&kd->kd_rsp.mscp_cmdref; kd->kd_ca.ca_cmddsc = (long)&kd->kd_cmd.mscp_cmdref; /* kd->kd_cmd.mscp_sccc.sccc_ctlrflags = 0; */ /* kd->kd_cmd.mscp_sccc.sccc_version = 0; */ if (kdbdumpcmd(M_OP_SETCTLRC, k, kd, ui->ui_ctlr)) return (EFAULT); kd->kd_cmd.mscp_unit = ui->ui_slave; if (kdbdumpcmd(M_OP_ONLINE, k, kd, ui->ui_ctlr)) return (EFAULT); /* * Pick up the drive type from the on line end packet; * convert that to a dump area size and a disk offset. * Note that the assembler uses pc-relative addressing * to get at kdbtypes[], no need for PHYS(). */ i = kd->kd_rsp.mscp_onle.onle_drivetype; if (i >= NTYPES || kdbtypes[i].ut_name == 0) { printf("disk type %d unknown\ndump "); return (EINVAL); } printf("on %s ", kdbtypes[i].ut_name); maxsz = kdbtypes[i].ut_sizes[kdbpart(dev)].nblocks; blkoff = kdbtypes[i].ut_sizes[kdbpart(dev)].blkoff; /* * Dump all of physical memory, or as much as will fit in the * space provided. */ start = 0; num = maxfree; if (dumplo < 0) return (EINVAL); if (dumplo + num >= maxsz) num = maxsz - dumplo; blkoff += dumplo; /* * Write out memory, DBSIZE pages at a time. * N.B.: this code depends on the fact that the sector * size == the page size. */ while (num > 0) { blk = num > DBSIZE ? DBSIZE : num; kd->kd_cmd.mscp_unit = ui->ui_slave; kd->kd_cmd.mscp_seq.seq_lbn = btop(start) + blkoff; kd->kd_cmd.mscp_seq.seq_bytecount = blk << PGSHIFT; kd->kd_cmd.mscp_seq.seq_buffer = (long)start | KDB_PHYS; if (kdbdumpcmd(M_OP_WRITE, k, kd, ui->ui_ctlr)) return (EIO); start += blk << PGSHIFT; num -= blk; } return (0); /* made it! */}/* * Wait for some of the bits in `bits' to come on. If the error bit * comes on, or ten seconds pass without response, return true (error). */kdbdumpwait(k, bits) register struct kdb_regs *k; register int bits;{ register int timo = todr() + 1000; while ((k->kdb_sa & bits) == 0) { if (k->kdb_sa & KDB_ERR) { printf("kdb_sa=%b\ndump ", k->kdb_sa, kdbsr_bits); return (1); } if (todr() >= timo) { printf("timeout\ndump "); return (1); } } return (0);}/* * Feed a command to the KDB50, wait for its response, and return * true iff something went wrong. */kdbdumpcmd(op, k, kd, ctlr) int op; register struct kdb_regs *k; register struct kdbdumpspace *kd; int ctlr;{ register int n;#define mp (&kd->kd_rsp) kd->kd_cmd.mscp_opcode = op; kd->kd_cmd.mscp_msglen = MSCP_MSGLEN; kd->kd_rsp.mscp_msglen = MSCP_MSGLEN; kd->kd_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT; kd->kd_ca.ca_cmddsc |= MSCP_OWN | MSCP_INT; if (k->kdb_sa & KDB_ERR) { printf("kdb_sa=%b\ndump ", k->kdb_sa, kdbsr_bits); return (1); } n = k->kdb_ip; n = todr() + 1000; for (;;) { if (todr() > n) { printf("timeout\ndump "); return (1); } if (kd->kd_ca.ca_cmdint) kd->kd_ca.ca_cmdint = 0; if (kd->kd_ca.ca_rspint == 0) continue; kd->kd_ca.ca_rspint = 0; if (mp->mscp_opcode == (op | M_OP_END)) break; printf("\n"); switch (MSCP_MSGTYPE(mp->mscp_msgtc)) { case MSCPT_SEQ: printf("sequential"); break; case MSCPT_DATAGRAM: mscp_decodeerror("kdb", ctlr, mp); printf("datagram"); break; case MSCPT_CREDITS: printf("credits"); break; case MSCPT_MAINTENANCE: printf("maintenance"); break; default: printf("unknown (type 0x%x)", MSCP_MSGTYPE(mp->mscp_msgtc)); break; } printf(" ignored\ndump "); kd->kd_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT; } if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("error: op 0x%x => 0x%x status 0x%x\ndump ", op, mp->mscp_opcode, mp->mscp_status); return (1); } return (0);#undef mp}/* * Return the size of a partition, if known, or -1 if not. */kdbsize(dev) dev_t dev;{ register int unit = kdbunit(dev); register struct uba_device *ui; register struct size *st; if (unit >= NKRA || (ui = kdbdinfo[unit]) == NULL || ui->ui_alive == 0) return (-1); st = &kdbtypes[ui->ui_type].ut_sizes[kdbpart(dev)]; if (st->nblocks == -1) { int s = spl5(); /* * We need to have the drive on line to find the size * of this particular partition. * IS IT OKAY TO GO TO SLEEP IN THIS ROUTINE? * (If not, better not page on one of these...) */ if ((ui->ui_flags & UNIT_ONLINE) == 0) { if (kdb_bringonline(ui, 0)) { splx(s); return (-1); } } splx(s); if (st->blkoff > ra_dsize[unit]) return (-1); return (ra_dsize[unit] - st->blkoff); } return (st->nblocks);}#endif NKDB > 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -