📄 sd.c
字号:
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((caddr_t)tbp, M_DEVBUF); biodone(bp);}/* * Start a transfer on sc as described by bp * (i.e., call hba or target start). * If in format mode, we may not need dma. */#define sdstart(sc, bp) { \ SD_TRACE(T_START, sc, bp); \ if ((sc)->sc_format_pid && legal_cmds[(sc)->sc_cmd.cdb_bytes[0]] > 0) \ (*(sc)->sc_unit.u_start)((sc)->sc_unit.u_updev, \ &(sc)->sc_unit.u_forw, (struct buf *)NULL, \ sdigo, &(sc)->sc_dk.dk_dev); \ else \ (*(sc)->sc_unit.u_start)((sc)->sc_unit.u_updev, \ &(sc)->sc_unit.u_forw, bp, sdgo, &(sc)->sc_dk.dk_dev); \}voidsdstrategy(bp) register struct buf *bp;{ register struct sd_softc *sc = sdcd.cd_devs[sdunit(bp->b_dev)]; register int s; if (sc->sc_format_pid) { /* XXXXXXXXX SHOULD NOT COMPARE curproc IN HERE!?! */ /* * In format mode, only allow the owner to mess * with the drive. Skip all the partition checks. */ if (sc->sc_format_pid != curproc->p_pid) { bp->b_error = EPERM; bp->b_flags |= B_ERROR; biodone(bp); return; } bp->b_cylin = 0; } else { register daddr_t bn = bp->b_blkno; register int sz = howmany(bp->b_bcount, DEV_BSIZE); register struct partition *p; /* * Make sure transfer is within partition. * If it starts at the end, return EOF; if * it extends past the end, truncate it. */ p = &sc->sc_dk.dk_label.d_partitions[sdpart(bp->b_dev)]; if ((unsigned)bn >= p->p_size) { if ((unsigned)bn > p->p_size) { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; } else bp->b_resid = bp->b_bcount; biodone(bp); return; } if (bn + sz > p->p_size) { sz = p->p_size - bn; bp->b_bcount = dbtob(sz); } /* * Non-aligned or partial-block transfers handled specially. * SHOULD THIS BE AT A HIGHER LEVEL? */ s = sc->sc_blksize - 1; if ((dbtob(bn) & s) || (bp->b_bcount & s)) { sdlblkstrat(bp, sc->sc_blksize); return; } bp->b_cylin = (bn + p->p_offset) >> sc->sc_bshift; } /* * Transfer valid, or format mode. Queue the request * on the drive, and maybe try to start it. */ s = splbio(); disksort(&sc->sc_tab, bp); if (sc->sc_tab.b_active == 0) { sc->sc_tab.b_active = 1; sdstart(sc, bp); } splx(s);}intsderror(sc, stat) register struct sd_softc *sc; register int stat;{ register struct scsi_sense *sn; int retry = 0; sc->sc_sense.status = stat; if ((stat & STS_MASK) == STS_CHECKCOND) { sn = (struct scsi_sense *)sc->sc_sense.sense; stat = scsi_request_sense(sc->sc_unit.u_hba, sc->sc_unit.u_targ, sc->sc_unit.u_unit, (caddr_t)sn, sizeof sc->sc_sense.sense); sc->sc_sense.status = stat; /* ??? */ if ((stat & STS_MASK) != STS_GOOD) { printf("%s: sense failed, status %x\n", sc->sc_dk.dk_dev.dv_xname, stat); return (0); } printf("%s: scsi sense class %d, code %d", sc->sc_dk.dk_dev.dv_xname, SENSE_ECLASS(sn), SENSE_ECODE(sn)); if (SENSE_ISXSENSE(sn) && XSENSE_ISSTD(sn)) { int key; /* * Standard extended sense: can examine sense key * and (if valid) info. */ key = XSENSE_KEY(sn); printf(", key %d", key); if (XSENSE_IVALID(sn)) printf(", blk %d", XSENSE_INFO(sn)); /* no sense or recovered error, try again */ if (key == 0 || key == 1) retry = 1; } printf("\n"); } return (retry);}/* * sdigo is called from the hba driver when it has got the scsi bus * for us, and we were doing a format op that did not need dma. */voidsdigo(sc0, cdb) struct device *sc0; struct scsi_cdb *cdb;{ register struct sd_softc *sc = (struct sd_softc *)sc0; register struct buf *bp = sc->sc_tab.b_actf; register int stat; stat = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba, sc->sc_unit.u_targ, &sc->sc_cmd, bp->b_un.b_addr, bp->b_bcount, bp->b_flags & B_READ); sc->sc_sense.status = stat; if (stat & 0xfe) { /* XXX */ (void) sderror(sc, stat); bp->b_flags |= B_ERROR; bp->b_error = EIO; } /* * Done with SCSI bus, before we `ought' to be. Release it. */ (*sc->sc_unit.u_rel)(sc->sc_unit.u_updev); bp->b_resid = 0; sc->sc_tab.b_errcnt = 0; sc->sc_tab.b_actf = bp->b_actf; biodone(bp); if ((bp = sc->sc_tab.b_actf) == NULL) sc->sc_tab.b_active = 0; else sdstart(sc, bp);}/* * sdgo is called from the hba driver or target code when it has * allocated the scsi bus and DMA resources and target datapath for us. */voidsdgo(sc0, cdb) struct device *sc0; register struct scsi_cdb *cdb;{ register struct sd_softc *sc = (struct sd_softc *)sc0; register struct buf *bp = sc->sc_tab.b_actf; register int n; register unsigned int u; SD_TRACE(T_MKCDB, sc, bp); if (sc->sc_format_pid) { *cdb = sc->sc_cmd; n = 0; } else { CDB10(cdb)->cdb_cmd = bp->b_flags & B_READ ? CMD_READ10 : CMD_WRITE10; CDB10(cdb)->cdb_lun_rel = sc->sc_unit.u_unit << 5; u = bp->b_cylin; CDB10(cdb)->cdb_lbah = u >> 24; CDB10(cdb)->cdb_lbahm = u >> 16; CDB10(cdb)->cdb_lbalm = u >> 8; CDB10(cdb)->cdb_lbal = u; CDB10(cdb)->cdb_xxx = 0; n = sc->sc_blksize - 1; u = (bp->b_bcount + n) >> (DEV_BSHIFT + sc->sc_bshift); CDB10(cdb)->cdb_lenh = u >> 8; CDB10(cdb)->cdb_lenl = u; CDB10(cdb)->cdb_ctrl = 0; n = (bp->b_bcount & n) != 0;#ifdef DEBUG if (n) printf("%s: partial block xfer -- %x bytes\n", sc->sc_dk.dk_dev.dv_xname, bp->b_bcount);#endif sc->sc_transfers++; } if ((*sc->sc_unit.u_go)(sc->sc_unit.u_updev, sc->sc_unit.u_targ, sdintr, (void *)sc, bp, n) == 0) {#ifdef notyet sc->sc_dk.dk_busy = 1; sc->sc_dk.dk_seek++; /* XXX */ sc->sc_dk.dk_xfer++; sc->sc_dk.dk_wds += bp->b_bcount >> 6;#endif return; } /* * Some sort of nasty unrecoverable error: clobber the * transfer. Call the bus release function first, though. */ (*sc->sc_unit.u_rel)(sc->sc_unit.u_updev);#ifdef DEBUG if (sddebug & SDB_ERROR) printf("%s: sdgo: %s adr %d blk %d len %d ecnt %d\n", sc->sc_dk.dk_dev.dv_xname, bp->b_flags & B_READ? "read" : "write", bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, sc->sc_tab.b_errcnt);#endif bp->b_flags |= B_ERROR; bp->b_error = EIO; bp->b_resid = 0; sc->sc_tab.b_errcnt = 0; sc->sc_tab.b_actf = bp->b_actf; biodone(bp); if ((bp = sc->sc_tab.b_actf) == NULL) sc->sc_tab.b_active = 0; else sdstart(sc, bp);}/* * A transfer finished (or, someday, disconnected). * We are already off the target/hba queues. * Restart this one for error recovery, or start the next, as appropriate. */voidsdintr(sc0, stat, resid) struct device *sc0; int stat, resid;{ register struct sd_softc *sc = (struct sd_softc *)sc0; register struct buf *bp = sc->sc_tab.b_actf; int retry; if (bp == NULL) panic("sdintr"); SD_TRACE(T_INTR, sc, bp);#ifdef notyet sc->sc_dk.dk_busy = 0;#endif if ((stat & STS_MASK) != STS_GOOD) {#ifdef DEBUG if (sddebug & SDB_ERROR) printf("%s: sdintr scsi status 0x%x resid %d\n", sc->sc_dk.dk_dev.dv_xname, stat, resid);#endif retry = sderror(sc, stat); if (retry && ++sc->sc_tab.b_errcnt <= SDRETRY) { printf("%s: retry %d\n", sc->sc_dk.dk_dev.dv_xname, sc->sc_tab.b_errcnt); goto restart; } bp->b_flags |= B_ERROR; bp->b_error = EIO; } bp->b_resid = resid; sc->sc_tab.b_errcnt = 0; sc->sc_tab.b_actf = bp->b_actf; biodone(bp); if ((bp = sc->sc_tab.b_actf) == NULL) sc->sc_tab.b_active = 0; else {restart: sdstart(sc, bp); }}intsdioctl(dev_t dev, int cmd, register caddr_t data, int flag, struct proc *p){ register struct sd_softc *sc = sdcd.cd_devs[sdunit(dev)];#ifdef COMPAT_SUNOS int error; error = sun_dkioctl(&sc->sc_dk, cmd, data, sdpart(dev)); if (error >= 0) return (error);#endif switch (cmd) { 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) return (EPERM); sc->sc_format_pid = p->p_pid; } else sc->sc_format_pid = 0; break; case SDIOCGFORMAT: /* find out who has the device in format mode */ *(int *)data = sc->sc_format_pid; break; case SDIOCSCSICOMMAND:#define cdb ((struct scsi_cdb *)data) /* * Save what user gave us as SCSI cdb to use with next * read or write to the char device. Be sure to replace * the lun field with the actual unit number. */ if (sc->sc_format_pid != p->p_pid) return (EPERM); if (legal_cmds[cdb->cdb_bytes[0]] == 0) return (EINVAL); sc->sc_cmd = *cdb; sc->sc_cmd.cdb_bytes[1] = (sc->sc_cmd.cdb_bytes[1] & ~(7 << 5)) | (sc->sc_unit.u_unit << 5);#undef cdb break; case SDIOCSENSE: /* * return the SCSI sense data saved after the last * operation that completed with "check condition" status. */ sc->sc_sense = *(struct scsi_fmt_sense *)data; break; case DIOCGDINFO: *(struct disklabel *)data = sc->sc_dk.dk_label; break; case DIOCGPART: ((struct partinfo *)data)->disklab = &sc->sc_dk.dk_label; ((struct partinfo *)data)->part = &sc->sc_dk.dk_label.d_partitions[sdpart(dev)]; break; default: return (ENOTTY); } return (0);}intsdsize(dev_t dev){ register int unit = sdunit(dev); register struct sd_softc *sc; if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL || (sc->sc_flags & SDF_ALIVE) == 0) return (-1); return (sc->sc_dk.dk_label.d_partitions[sdpart(dev)].p_size);}/* * Write `len' bytes from address `addr' to drive and partition in `dev', * at block blkoff from the beginning of the partition. The address is * either kernel virtual or physical (some machines may never use one or * the other, but we need it in the protocol to stay machine-independent). */intsddump(dev_t dev, daddr_t blkoff, caddr_t addr, int len){ register struct sd_softc *sc; register struct partition *p; register daddr_t bn, n, nblks; register struct hba_softc *hba; register int stat, unit; struct scsi_cdb cdb; /* drive ok? */ unit = sdunit(dev); if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL || (sc->sc_flags & SDF_ALIVE) == 0) return (ENXIO); /* blocks in range? */ p = &sc->sc_dk.dk_label.d_partitions[sdpart(dev)]; n = (len + sc->sc_blksize - 1) >> DEV_BSHIFT; if (blkoff < 0 || blkoff >= p->p_size || blkoff + n > p->p_size) return (EINVAL); bn = blkoff + p->p_offset; bn >>= sc->sc_bshift; /* scsi bus idle? */ hba = sc->sc_unit.u_hba; if (hba->hba_head) { (*hba->hba_driver->hd_reset)(hba, 0); printf("[reset %s] ", sc->sc_dk.dk_dev.dv_xname); } CDB10(&cdb)->cdb_cmd = CMD_WRITE10; CDB10(&cdb)->cdb_lun_rel = sc->sc_unit.u_unit << 5; CDB10(&cdb)->cdb_xxx = 0; CDB10(&cdb)->cdb_ctrl = 0;#define DUMP_MAX (32 * 1024) /* no more than 32k per write */ for (;;) { if ((n = len) > DUMP_MAX) n = DUMP_MAX; CDB10(&cdb)->cdb_lbah = bn >> 24; CDB10(&cdb)->cdb_lbahm = bn >> 16; CDB10(&cdb)->cdb_lbalm = bn >> 8; CDB10(&cdb)->cdb_lbal = bn; nblks = n >> (DEV_BSHIFT + sc->sc_bshift); CDB10(&cdb)->cdb_lenh = nblks >> 8; CDB10(&cdb)->cdb_lenl = nblks; stat = hba->hba_driver->hd_dump(hba, sc->sc_unit.u_targ, &cdb, addr, n); if ((stat & STS_MASK) != STS_GOOD) { printf("%s: scsi write error 0x%x\ndump ", sc->sc_dk.dk_dev.dv_xname, stat); return (EIO); } if ((len -= n) == 0) return (0); addr += n; bn += nblks; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -