📄 sd.c
字号:
caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); register int bn, resid; register caddr_t addr; bzero((caddr_t)cbp, sizeof(*cbp)); cbp->b_proc = curproc; /* XXX */ cbp->b_dev = bp->b_dev; bn = bp->b_blkno; resid = bp->b_bcount; addr = bp->b_un.b_addr;#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", bp, bp->b_flags, bn, resid, addr);#endif while (resid > 0) { register int boff = dbtob(bn) & (bsize - 1); register int count; if (boff || resid < bsize) { sdstats[sdunit(bp->b_dev)].sdpartials++; count = min(resid, bsize - boff); cbp->b_flags = B_BUSY | B_PHYS | B_READ; cbp->b_blkno = bn - btodb(boff); cbp->b_un.b_addr = cbuf; cbp->b_bcount = bsize;#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf(" readahead: bn %x cnt %x off %x addr %x\n", cbp->b_blkno, count, boff, addr);#endif sdstrategy(cbp); biowait(cbp); if (cbp->b_flags & B_ERROR) { bp->b_flags |= B_ERROR; bp->b_error = cbp->b_error; break; } if (bp->b_flags & B_READ) { bcopy(&cbuf[boff], addr, count); goto done; } bcopy(addr, &cbuf[boff], count);#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf(" writeback: bn %x cnt %x off %x addr %x\n", cbp->b_blkno, count, boff, addr);#endif } else { count = resid & ~(bsize - 1); cbp->b_blkno = bn; cbp->b_un.b_addr = addr; cbp->b_bcount = count;#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf(" fulltrans: bn %x cnt %x addr %x\n", cbp->b_blkno, count, addr);#endif } cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); sdstrategy(cbp); biowait(cbp); if (cbp->b_flags & B_ERROR) { bp->b_flags |= B_ERROR; bp->b_error = cbp->b_error; break; }done: bn += btodb(count); resid -= count; addr += count;#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf(" done: bn %x resid %x addr %x\n", bn, resid, addr);#endif } free(cbuf, M_DEVBUF); free(cbp, M_DEVBUF);}voidsdstrategy(bp) register struct buf *bp;{ int unit = sdunit(bp->b_dev); register struct sd_softc *sc = &sd_softc[unit]; register struct buf *dp = &sdtab[unit]; register struct partition *pinfo; register daddr_t bn; register int sz, s; if (sc->sc_format_pid >= 0) { if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ bp->b_error = EPERM; goto bad; } bp->b_cylin = 0; } else { if (sc->sc_flags & SDF_ERROR) { bp->b_error = EIO; goto bad; } bn = bp->b_blkno; sz = howmany(bp->b_bcount, DEV_BSIZE); pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; if (bn < 0 || bn + sz > pinfo->p_size) { sz = pinfo->p_size - bn; if (sz == 0) { bp->b_resid = bp->b_bcount; goto done; } if (sz < 0) { bp->b_error = EINVAL; goto bad; } bp->b_bcount = dbtob(sz); } /* * Check for write to write protected label */ if (bn + pinfo->p_offset <= LABELSECTOR &&#if LABELSECTOR != 0 bn + pinfo->p_offset + sz > LABELSECTOR &&#endif !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { bp->b_error = EROFS; goto bad; } /* * Non-aligned or partial-block transfers handled specially. */ s = sc->sc_blksize - 1; if ((dbtob(bn) & s) || (bp->b_bcount & s)) { sdlblkstrat(bp, sc->sc_blksize); goto done; } bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; } s = splbio(); disksort(dp, bp); if (dp->b_active == 0) { dp->b_active = 1; sdustart(unit); } splx(s); return;bad: bp->b_flags |= B_ERROR;done: biodone(bp);}voidsdustart(unit) register int unit;{ if (scsireq(&sd_softc[unit].sc_dq)) sdstart(unit);}/* * Return: * 0 if not really an error * <0 if we should do a retry * >0 if a fatal error */static intsderror(unit, sc, hp, stat) int unit, stat; register struct sd_softc *sc; register struct hp_device *hp;{ int cond = 1; sdsense[unit].status = stat; if (stat & STS_CHECKCOND) { struct scsi_xsense *sp; scsi_request_sense(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, sdsense[unit].sense, sizeof(sdsense[unit].sense)); sp = (struct scsi_xsense *)sdsense[unit].sense; printf("sd%d: scsi sense class %d, code %d", unit, sp->class, sp->code); if (sp->class == 7) { printf(", key %d", sp->key); if (sp->valid) printf(", blk %d", *(int *)&sp->info1); switch (sp->key) { /* no sense, try again */ case 0: cond = -1; break; /* recovered error, not a problem */ case 1: cond = 0; break; /* possible media change */ case 6: /* * For removable media, if we are doing the * first open (i.e. reading the label) go * ahead and retry, otherwise someone has * changed the media out from under us and * we should abort any further operations * until a close is done. */ if (sc->sc_flags & SDF_RMEDIA) { if (sc->sc_flags & SDF_OPENING) cond = -1; else sc->sc_flags |= SDF_ERROR; } break; } } printf("\n"); } return(cond);}static voidsdfinish(unit, sc, bp) int unit; register struct sd_softc *sc; register struct buf *bp;{ register struct buf *dp = &sdtab[unit]; dp->b_errcnt = 0; dp->b_actf = bp->b_actf; bp->b_resid = 0; biodone(bp); scsifree(&sc->sc_dq); if (dp->b_actf) sdustart(unit); else { dp->b_active = 0; if (sc->sc_flags & SDF_WANTED) { sc->sc_flags &= ~SDF_WANTED; wakeup((caddr_t)dp); } }}voidsdstart(unit) register int unit;{ register struct sd_softc *sc = &sd_softc[unit]; register struct hp_device *hp = sc->sc_hd; /* * we have the SCSI bus -- in format mode, we may or may not need dma * so check now. */ if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) { register struct buf *bp = sdtab[unit].b_actf; register int sts; sdtab[unit].b_errcnt = 0; while (1) { sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, &sdcmd[unit], bp->b_un.b_addr, bp->b_bcount, bp->b_flags & B_READ); sdsense[unit].status = sts; if ((sts & 0xfe) == 0 || (sts = sderror(unit, sc, hp, sts)) == 0) break; if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) { bp->b_flags |= B_ERROR; bp->b_error = EIO; break; } } sdfinish(unit, sc, bp); } else if (scsiustart(hp->hp_ctlr)) sdgo(unit);}voidsdgo(unit) register int unit;{ register struct sd_softc *sc = &sd_softc[unit]; register struct hp_device *hp = sc->sc_hd; register struct buf *bp = sdtab[unit].b_actf; register int pad; register struct scsi_fmt_cdb *cmd; if (sc->sc_format_pid >= 0) { cmd = &sdcmd[unit]; pad = 0; } else { /* * Drive is in an error state, abort all operations */ if (sc->sc_flags & SDF_ERROR) { bp->b_flags |= B_ERROR; bp->b_error = EIO; sdfinish(unit, sc, bp); return; } cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; *(int *)(&cmd->cdb[2]) = bp->b_cylin; pad = howmany(bp->b_bcount, sc->sc_blksize); *(u_short *)(&cmd->cdb[7]) = pad; pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;#ifdef DEBUG if (pad) printf("sd%d: partial block xfer -- %x bytes\n", unit, bp->b_bcount);#endif sdstats[unit].sdtransfers++; }#ifdef USELEDS if (inledcontrol == 0) ledcontrol(0, 0, LED_DISK);#endif if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { if (hp->hp_dk >= 0) { dk_busy |= 1 << hp->hp_dk; ++dk_seek[hp->hp_dk]; ++dk_xfer[hp->hp_dk]; dk_wds[hp->hp_dk] += bp->b_bcount >> 6; } return; }#ifdef DEBUG if (sddebug & SDB_ERROR) printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", unit, bp->b_flags & B_READ? "read" : "write", bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, sdtab[unit].b_errcnt);#endif bp->b_flags |= B_ERROR; bp->b_error = EIO; sdfinish(unit, sc, bp);}voidsdintr(unit, stat) register int unit; int stat;{ register struct sd_softc *sc = &sd_softc[unit]; register struct buf *bp = sdtab[unit].b_actf; register struct hp_device *hp = sc->sc_hd; int cond; if (bp == NULL) { printf("sd%d: bp == NULL\n", unit); return; } if (hp->hp_dk >= 0) dk_busy &=~ (1 << hp->hp_dk); if (stat) {#ifdef DEBUG if (sddebug & SDB_ERROR) printf("sd%d: sdintr: bad scsi status 0x%x\n", unit, stat);#endif cond = sderror(unit, sc, hp, stat); if (cond) { if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {#ifdef DEBUG if (sddebug & SDB_ERROR) printf("sd%d: retry #%d\n", unit, sdtab[unit].b_errcnt);#endif sdstart(unit); return; } bp->b_flags |= B_ERROR; bp->b_error = EIO; } } sdfinish(unit, sc, bp);}intsdread(dev, uio, flags) dev_t dev; struct uio *uio; int flags;{ register int unit = sdunit(dev); register int pid; if ((pid = sd_softc[unit].sc_format_pid) >= 0 && pid != uio->uio_procp->p_pid) return (EPERM); return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));}intsdwrite(dev, uio, flags) dev_t dev; struct uio *uio; int flags;{ register int unit = sdunit(dev); register int pid; if ((pid = sd_softc[unit].sc_format_pid) >= 0 && pid != uio->uio_procp->p_pid) return (EPERM); return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));}intsdioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p;{ int unit = sdunit(dev); register struct sd_softc *sc = &sd_softc[unit]; register struct disklabel *lp = &sc->sc_info.si_label; int error, flags; switch (cmd) { default: return (EINVAL); case DIOCGDINFO: *(struct disklabel *)data = *lp; return (0); case DIOCGPART: ((struct partinfo *)data)->disklab = lp; ((struct partinfo *)data)->part = &lp->d_partitions[sdpart(dev)]; return (0); case DIOCWLABEL: if ((flag & FWRITE) == 0) return (EBADF); if (*(int *)data) sc->sc_flags |= SDF_WLABEL; else sc->sc_flags &= ~SDF_WLABEL; return (0); case DIOCSDINFO: if ((flag & FWRITE) == 0) return (EBADF); error = setdisklabel(lp, (struct disklabel *)data, (sc->sc_flags & SDF_WLABEL) ? 0 : sc->sc_info.si_open); return (error); case DIOCWDINFO: if ((flag & FWRITE) == 0) return (EBADF); error = setdisklabel(lp, (struct disklabel *)data, (sc->sc_flags & SDF_WLABEL) ? 0 : sc->sc_info.si_open); if (error) return (error); flags = sc->sc_flags; sc->sc_flags = SDF_ALIVE | SDF_WLABEL; error = writedisklabel(sdlabdev(dev), sdstrategy, lp); sc->sc_flags = flags; return (error); case SDIOCSFORMAT: /* take this device into or out of "format" mode */ if (suser(p->p_ucred, &p->p_acflag)) return(EPERM); if (*(int *)data) { if (sc->sc_format_pid >= 0) return (EPERM); sc->sc_format_pid = p->p_pid; } else sc->sc_format_pid = -1; return (0); case SDIOCGFORMAT: /* find out who has the device in format mode */ *(int *)data = sc->sc_format_pid; return (0); case SDIOCSCSICOMMAND: /* * Save what user gave us as SCSI cdb to use with next * read or write to the char device. */ if (sc->sc_format_pid != p->p_pid) return (EPERM); if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) return (EINVAL); bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); return (0); case SDIOCSENSE: /* * return the SCSI sense data saved after the last * operation that completed with "check condition" status. */ bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); return (0); } /*NOTREACHED*/}intsdsize(dev) dev_t dev;{ register int unit = sdunit(dev); register struct sd_softc *sc = &sd_softc[unit]; int psize, didopen = 0; if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) return(-1); /* * We get called very early on (via swapconf) * without the device being open so we may need * to handle it here. */ if (sc->sc_info.si_open == 0) { if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) return(-1); didopen = 1; } psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; if (didopen) (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); return (psize);}/* * Non-interrupt driven, non-dma dump routine. */intsddump(dev) dev_t dev;{ int part = sdpart(dev); int unit = sdunit(dev); register struct sd_softc *sc = &sd_softc[unit]; register struct hp_device *hp = sc->sc_hd; register struct partition *pinfo; register daddr_t baddr; register int maddr; register int pages, i; int stat; extern int lowram, dumpsize; /* is drive ok? */ if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) return (ENXIO); pinfo = &sc->sc_info.si_label.d_partitions[part]; /* dump parameters in range? */ if (dumplo < 0 || dumplo >= pinfo->p_size || pinfo->p_fstype != FS_SWAP) return (EINVAL); pages = dumpsize; if (dumplo + ctod(pages) > pinfo->p_size) pages = dtoc(pinfo->p_size - dumplo); maddr = lowram; baddr = dumplo + pinfo->p_offset; /* scsi bus idle? */ if (!scsireq(&sc->sc_dq)) { scsireset(hp->hp_ctlr); sdreset(sc, sc->sc_hd); printf("[ drive %d reset ] ", unit); } for (i = 0; i < pages; i++) {#define NPGMB (1024*1024/NBPG) /* print out how many Mbs we have dumped */ if (i && (i % NPGMB) == 0) printf("%d ", i / NPGMB);#undef NPBMG pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, VM_PROT_READ, TRUE); stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, vmmap, NBPG, baddr, sc->sc_bshift); if (stat) { printf("sddump: scsi write error 0x%x\n", stat); return (EIO); } maddr += NBPG; baddr += ctod(1); } return (0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -